#!/local/bin/perl5 -w
# 
# This was fun, haven't done much on dohnuts since I took a topology course years ago.
# 
# 
#FROST 
use strict;
 
my ($xval,$yval); # global x,y values
my @f;            # ar. of ar. field
 
sub hod{my ($x,$y) = @_;
        [\$f[$x][$y],\$f[($x+1) % $xval][$y],
         \$f[($x+1) % $xval][($y+1) % $yval],\$f[$x][($y+1) %$yval]]}

# This is basically it, it returns an referense to an 
# array of references to the four cells of @f constituing 
# a hod. This reference (conviniently named $r wherever it apears is 
# then passed back and fort through the program. note that the cella are 
# ordered from bottom left, counter clockwise

sub draw{for (my $y = 0;$y <= $yval;$y++)
         {for (my $x = 0;$x <= $xval;$x++){
             if($f[$x][$y]eq'X'){print '*'}
             elsif($f[$x][$y]eq'A'){print '.'}
             else{print ' '}}print "\n"}}

sub r_left{my $r = shift;
           my @r = @{$r};
           my $tmp = ${$r[0]};
${$r[0]}=${$r[3]};${$r[3]}=${$r[2]};${$r[2]}=${$r[1]};${$r[1]}=$tmp}
sub r_right{my $r = shift;
            my @r = @{$r};
            my $tmp = ${$r[0]};
${$r[0]}=${$r[1]};${$r[1]}=${$r[2]};${$r[2]}=${$r[3]};${$r[3]}=$tmp}
# There's probably a more estetic way of doing this

sub freeze{my $r = shift;
           for (@{$r}) {if ($$_ eq 'A'){$$_ = 'X'}}}
sub evaluate{my $r = shift;
             my $str;
             for (@{$r}) {$str .= $$_}
             if ($str =~ /X.*A|A.*X/){
                 freeze($r)}
             else{if ($str=~/A.* | .*A/){
                 if (rand > 0.5){r_left($r)}else{r_right($r)}}}}

# The elements of @f contain X(frost) A(vapor) ' '(vacum) the above tests  
# should make it obious why I didn't go for . and * in the field :-)


sub evalall{my $step = shift;   # 0 or 1
            for (my $x = $step ; $x <= $xval ; $x=$x+2){
                for (my $y = $step ; $y <= $yval ; $y=$y+2){
                    evaluate(hod($x,$y))}}}
#loops through all hod's starting 0,0 or 1,1

my $TICK = 0;
$SIG{ALRM} = sub { warn "TICKS: $TICK\n"; exit };
alarm $ENV{TIMELIMIT} || 120;

sub mainloop{my $step=shift;
             for (1..$step){$TICK++;evalall($_ % 2);          draw}}
# $_ % 2 alterates 0,1,0,1

sub genfield{my ($x,$y,$d)=@_;
             $xval = $x;$yval=$y;
             for ($x=0;$x<=$xval;$x++){
                 for ($y=0;$y<=$yval;$y++){
                     if (rand(1) < $d){$f[$x][$y]='A'}else{$f[$x][$y]=' '}}}
             $f[($xval+1)/2][($yval+1)/2] = 'X'}
# builds and populates @f, places the X(frost) symbol in the midle.

sub main{my ($x,$y,$d,$t) = @ARGV;
         genfield(--$x,--$y,$d);
         $t ||= 1_000_000_000;
         mainloop($t);
}
main();
