# 
# Tor K. Fuglerud wrote:
#  > This was fun, haven't done much on dohnuts since I took a topology
#  > course years ago.
# [snip program]
# 
# I've taken your program and perlified it a bit, you are doing a lot of C
# programming, aren't you? :)
# 
# Hope you don't mind, it changed quite a bit but the overall structure is
# still the same.
# 
# Here's a small list of the things I changed:
# - 'beautified' (but probably slowed down) r_left and r_right and unified
#    them into one sub (r_left_right)
# - removed sub main and mainloop
# - freeze uses tr/// instead of loop
# - evaluate uses tr/// instead of regexes, this easily allows to use the
#    'original' symbols for vapor and ice/frost
# - genfield uses map and perl for-loop to create field
# - general reformatting of the code to improve the readability
# 
# Cheers,
# Torsten
# 
#!/usr/bin/perl -w
#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 reference to an
# array of references to the four cells of @f constituting
# a hod. This reference (conveniently named $r wherever it apears is
# then passed back and fort through the program. note that the cells are
# ordered from bottom left, counter clockwise

sub draw {
     local $\ = "\n";
     print @$_ for @f;
}

sub r_left_right {
     my ($r) = @_;
     my @vals = map {$$_} @$r;
     if (rand > 0.5) {     # rotate left
         push @vals, shift @vals;
     } else {              #rotate rigth
         unshift @vals, pop @vals;
     }
     $$_ = shift @vals for @$r;
}
# Rotate right or left, 50% chance for each

sub freeze {
     my $r = shift;
     $$_ =~ tr/./*/ for @$r;
}
# Freeze all vapors to frost

sub evaluate {
     my ($r) = @_;
     local $_ = '';
     for my $char_ref (@$r) {
         $_ .= $$char_ref;
     }

     if (tr/.//) { # vapor and
         tr/*// ? freeze($r):       #    frost  -> freeze
         tr/ // ? r_left_right($r): # or vacuum -> rotate left or right
         1;                         # or else   -> do nothing
     }
}

our $TICK = 0;
sub evalall {
     $TICK++;
     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

sub genfield {
     ($xval, $yval, my $density) = @_;

     push @f, [ map { (rand()<$density)? '.' : ' ' } 0 .. $yval ]
         for (0 .. $xval);

     $f[($xval+1)/2][($yval+1)/2] = '*';
}
# builds and populates @f, places the '*' frost symbol in the middle.
# '.' stands for vapor
# ' ' stands for vacuum

my ($x,$y,$density,$t) = @ARGV;
$t ||= 1000000000;
genfield(--$y,--$x,$density); # generate the field
$SIG{ALRM} = sub { warn "TICKS: $TICK\n"; exit };
alarm $ENV{TIMELIMIT} || 120;

for (1 .. $t) {
  evalall($_ % 2); #  for 1 .. $t;  # main loop
  draw;                         # draw field
}

