#!/usr/bin/perl use strict; use warnings; use lib "../adv"; use include; # CONFIGURATION die "Usage: sim.pl [unit_size] [map] [single|multi] [rndfile|-]\n" unless @ARGV == 4; my ($unit_size, $area, $mode, $rnds) = @ARGV; # Rnd Starting Positions CONFIG->rndload("../sim/$rnds") unless $rnds eq "-"; #my $unit_size = 10; # [small], [large] #my $area = "halls"; # beard, halls, squiggle #my $mode = "multi"; # single, multi # SET UP UI use HexedUI; my $ui = create HexedUI { Main => { Type => "Map", At => [0, 0], Size => ["100%", "100%"], Border => 1, Render => sub { my $tile = shift; my ($char, $color); if (ref $tile->{_}) { ($char, $color) = $tile->{_}->symbol; } elsif ($tile->{color}) { $char = $tile->{_}; $color = $tile->{color}; } else { $char = $tile->{_}; $color = { "#" => "orange", "." => "grey" }->{$char}; $color ||= "yellow"; } return ord($char) | HexedUI::paint($color); } }, }; GAME->{UI} = $ui; # SET UP MAP use BDSM::Transform; my $map = loadmap("../maps/$area"); $ui->{Main}->setup($map); $map->{OnChange} = sub { my ($map, $y, $x, $new) = @_; $ui->{Main}->_mod($y, $x, $map->{Map}[$y][$x]); }; use Waypoint; preprock($map); sub run { # ################################################################### # Initialize units use Unit; my @units; foreach (1 .. $unit_size) { my $unit = GAME->{Classes}{Unit}->new(Map => $map, Num => $_); if ($_ != 1) { # Whilst assembling, just form a line. push @{ $unit->{Goals} }, [ $units[-1], 0, +1 ]; } push @units, $unit; } # Leader assembles to a random position my ($ass_y, $ass_x); FIND: while (1) { ($ass_y, $ass_x) = $map->getpt("."); # Ensure there's enough room for everyone to line up next if $ass_x + $unit_size - 1 > $map->width; foreach my $x ($ass_x .. $ass_x + $unit_size - 1) { next FIND if $map->{Map}[$ass_y][$x]{_} eq "#"; } last; } push @{ $units[0]->{Goals} }, [ { Y => $ass_y, X => $ass_x }, 0, 0 ]; # Choose a random destination. my ($goy, $gox) = $map->getpt("."); # ################################################################## # PART ONE: Assembly # Single: Find our buddy, then yield control to the next unit. # Multi: Everyone find everybody at once. GAME->{AssCnt} = 0; if ($mode eq "single") { foreach my $unit (@units) { while (1) { GAME->{UI}{Main}->draw; last if assemble($unit) == 16; } } } else { while (1) { GAME->{UI}{Main}->draw; my $cnt = 0; foreach my $unit (@units) { $cnt++ if assemble($unit) == 16; } last if $cnt == @units; } } $units[0]->{Goals} = [[ { Y => $goy, X => $gox }, 0, 0 ]]; # PART TWO: Movement # Single & Multi: Follow our buddy until everybody reaches the destination. GAME->{MvCnt} = 0; while (1) { GAME->{UI}{Main}->draw; debug "to $goy, $gox. at $units[0]->{Y}, $units[0]->{X}" if $map->{Map}[$goy][$gox]{_} ne "."; foreach my $unit (@units) { ($unit->{Num} == 1) ? ctrl($goy, $gox, @units) : $unit->magnet($goy, $gox); } } } sub assemble { my $unit = shift; my ($Y, $X) = offset($unit->{Goals}[-1]); if ($unit->{Y} == $Y and $unit->{X} == $X) { # If we're already where we need to be, just snooze. if ($#{ $unit->{Goals} }) { pop @{ $unit->{Goals} }; } else { # So our buddy doesn't get confused. $unit->{Laster}[0] = $unit->{Y}; $unit->{Laster}[1] = $unit->{X}; return 16; } } GAME->{AssCnt}++ unless shift; # We might be moving the leader. my $code = $unit->magnet; if ($code and $code == 42) { # Er, just kidding. (Not deadlocked if adjacent to buddy.) # Leader is exception. Actually, any with a dead goal. return if $unit->{Goals}[-1][0]{Num} and abs($unit->{Y} - $unit->{Goals}[-1][0]{Y}) <= 1 and abs($unit->{X} - $unit->{Goals}[-1][0]{X}) <= 1; $unit->deadmag; } $code ||= 0; return $code; } sub ctrl { my $goy = shift; my $gox = shift; my $me = shift; debug "to $goy, $gox. at $me->{Y}, $me->{X}"; my @units = @_; GAME->{MvCnt}++; my $code = assemble($me, "mv"); die "SUCCESS. Ass " . GAME->{AssCnt} . ". Mv " . GAME->{MvCnt} . "." if $me->{Y} == $goy and $me->{X} == $gox; return unless $code; return if $code == 9 or $code == 42; # maintain position or something my $in = { 1 => "k", 2 => "j", 3 => "h", 4 => "l", 5 => "y", 6 => "u", 7 => "b", 8 => "n", }->{$code}; # Update the vectors for the troops. my $vecta; $vecta = { l => [0, -1], h => [0, +1], k => [+1, 0], j => [-1, 0], y => [+1, +1], u => [+1, -1], b => [-1, +1], n => [-1, -1], }->{$in}; $_->{Goals}[0] = [ $_->{Goals}[0][0], @$vecta ] foreach @units; } run;