package Unit; use strict; use warnings; use include; use Obj; Obj->newclass("Unit" => # Meta Stages => ["-"], # Instance Data Map => undef, Y => undef, X => undef, Num => undef, Last => undef, Laster => undef, Goals => undef, StuckMem => undef, #Stucker => undef, # Class stuff Actions => ["go", "magnet"], Methods => ["symbol", "trapt"], init => sub { my $self = shift; return unless $self->{Instance}; die "Instance lacks a Map!\n" unless $self->{Map}; $self->{Last} = [-1, -1]; $self->{Laster} = [-1, -1]; $self->{Goals} = []; $self->{StuckMem} = {}; #$self->{Stucker} = {}; my ($y, $x) = ($self->{Y}, $self->{X}); # Choose a random starting point. ($y, $x) = $self->{Map}->getpt(".") unless defined $y and defined $x; $self->go("-warp", $y, $x); } ); sub symbol { my $self = shift; my $symbol = $self->{Num}; $symbol = "@" if $symbol > 9; my $color = "cyan"; $color = "yellow" if $self->trapt; return ($symbol, $color); } sub trapt { # Misleadingly named... my $self = shift; return unless @{ $self->{Goals} }; # not really but visually... return if $self->{Goals}[-1][0]{Y} == $self->{Goals}[0][0]{Y} and $self->{Goals}[-1][0]{X} == $self->{Goals}[0][0]{X}; return 1; } sub go { my ($self, $act) = @_; my ($y, $x) = args $act; # CHECKS die "thats not a map" unless ref $self->{Map} eq "BDSM::Map"; die "go where?" unless defined $y and defined $x; die "bounds!" if $y < 0 or $y > $self->{Map}->height; die "bounds!" if $x < 0 or $x > $self->{Map}->width; die "cant go there!" if $self->{Map}{Map}[$y][$x]{_} ne "."; # DO IT # Leave old tile unless we just appeared $self->{Map}->mod($self->{Y}, $self->{X}, ".") unless $act->{warp}; # Enter the new tile $self->{Y} = $y; $self->{X} = $x; $self->{Map}->mod($y, $x, $self); } sub magnet { my $self = shift; my $noY = shift; my $noX = shift; my $magnet = $self->{Goals}[-1]; my ($toY, $toX) = offset($magnet); my @best; # Determine the best direction in which to move. foreach my $dir (1 .. 9) { # don't wait just cause thats our only option! last if $#best == -1 and $dir == 9; my $y = $self->{Y}; my $x = $self->{X}; $y-- if $dir == 1 or $dir == 5 or $dir == 6; $y++ if $dir == 2 or $dir == 7 or $dir == 8; $x-- if $dir == 3 or $dir == 5 or $dir == 7; $x++ if $dir == 4 or $dir == 6 or $dir == 8; next if $self->{Num} != 1 and defined $noY and $noY == $y and $noX == $x; # Adjacent to a non-buddy? Move, then! if ($dir == 9) { # Anyone next to us? my $move = 0; foreach my $DIR (1 .. 8) { my $Y = $self->{Y}; my $X = $self->{X}; $Y-- if $DIR == 1 or $DIR == 5 or $DIR == 6; $Y++ if $DIR == 2 or $DIR == 7 or $DIR == 8; $X-- if $DIR == 3 or $DIR == 5 or $DIR == 7; $X++ if $DIR == 4 or $DIR == 6 or $DIR == 8; my $block = $self->{Map}{Map}[$Y][$X]{_}; next unless ref $block; # Only move if of a lower rank. That way both dont move and cause that # thing where you both go left and right and never break the loop! # And lower numbers are higher ranks. Heh! $move++, last if $self->{Num} > $block->{Num}; } next if $move; } # Backtracking is ok. Moving into stuff is not (unless we're chillin') next if $dir != 9 and $self->{Map}{Map}[$y][$x]{_} ne "."; # If we can directly follow our buddy and go on the tile they were # literally just on, then by golly, do it! # But not if we're in movement mode. Cause then we wanna probably form a # shappe! unless ($noY) { if ($magnet->[0]{Laster} and @{ $magnet->[0]{Laster} } and $y == $magnet->[0]{Laster}[0] and $x == $magnet->[0]{Laster}[1]) { @best = (0, $y, $x, $dir); last; } } # Evaluate sum of the distances between the magnet. my $dist = euclid($y, $x, offset($magnet)); # Is this the way to go? @best = ($dist, $y, $x, $dir) if $#best == -1 or $dist <= $best[0]; } # If we're literally surrounded, just chill and pray people get moving. debug("$self->{Num} trapped!!!!!!!!"), return if $#best == -1; # So do we go now? return 42 if $best[1] == $self->{Y} and $best[2] == $self->{X}; # Chillin'. $self->go($best[1], $best[2]); $self->{Laster} = $self->{Last}; $self->{Last} = [$best[1], $best[2]]; return $best[3]; } sub euclid { my ($y1, $x1, $y2, $x2) = @_; return sqrt((($y1 - $y2) ** 2) + (($x1 - $x2) ** 2)); } sub offset { my $magnet = shift; return ($magnet->[0]{Y} + $magnet->[1], $magnet->[0]{X} + $magnet->[2]); } 42;