#!/usr/bin/perl # Command line arguments: # --------------------------------------------------------- # -h | the desired height of the grid # -w | the desired width of the grid # -v | the desired number of vapor molecules # -c | the desired initial number of crystals # -d | require an ENTER between iterations # --------------------------------------------------------- # # Defaults: # --------------------------------------------------------- # height | the current height of the buffer # width | the current width of the buffer # vapor | height * width / 5 # crystals | 1 # delay | do not delay between iterations # --------------------------------------------------------- use Win32::Console; $HEIGHT = 0; $SPACE_CHR = " "; $WIDTH = 0; $VAPOR_CHR = "."; $VAPOR = 0; $CRYST_CHR = "+"; $CRYSTALS = 0; $DELAY = 0; $CONSOLE = new Win32::Console; $CONSOLE->Alloc; while ($_ = shift @ARGV) { if (/^-h/i) { $ref = \$HEIGHT } elsif (/^-w/i) { $ref = \$WIDTH } elsif (/^-v/i) { $ref = \$VAPOR } elsif (/^-c/i) { $ref = \$CRYSTALS } elsif (/^-d/i) { $DELAY = 1; next } else { next } $_ = shift @ARGV || last; /\D/ && next; $$ref = $_; } if ($HEIGHT) { if ($HEIGHT > ($CONSOLE->Size)[1]) { print "Cannot create a console of that height in this window.\n"; exit; } } else { $HEIGHT = ($CONSOLE->Size)[1]; } $HEIGHT -= $HEIGHT % 2; unless ($HEIGHT) { print "Cannot create a console of zero height.\n"; exit; } if ($WIDTH) { if ($WIDTH > ($CONSOLE->Size)[0]) { print "Cannot create a console of that width in this window.\n"; exit; } } else { $WIDTH = ($CONSOLE->Size)[0]; } $WIDTH -= $WIDTH % 2; unless ($WIDTH) { print "Cannot create a console of zero width.\n"; exit; } $CRYSTALS ||= 1; if ($CRYSTALS > $HEIGHT * $WIDTH) { print "Too many crystals!\n"; exit; } if ($VAPOR) { if ($VAPOR + $CRYSTALS > $HEIGHT * $WIDTH) { print "Too much vapor!\n"; exit; } } else { $VAPOR = int($HEIGHT * $WIDTH / 5); if ($VAPOR + $CRYSTALS > $HEIGHT * $WIDTH) { $VAPOR = $HEIGHT * $WIDTH - $CRYSTALS; } } $CONSOLE->Window(1, 0, 0, $WIDTH - 1, $HEIGHT - 1); $CONSOLE->Size($WIDTH, $HEIGHT); $CONSOLE->Cursor(-1, -1, 1, 0); $CONSOLE->Display; @grid = &initialize_grid($WIDTH, $HEIGHT, $VAPOR, $CRYSTALS); while (++$i) { $catstr = join "", map { @{$_} } @grid; $CONSOLE->WriteChar($catstr, 0, 0); if ($DELAY) { $CONSOLE->Cursor(0, 0); getc; } last unless $catstr =~ /\./; &transform_grid(\@grid, $i % 2); } getc unless $DELAY; #------------------------------- sub initialize_grid { my ($w, $h, $f, $c) = @_; my @o = (); my $i, $j, $n; for $i (0 .. $h - 1) { for $j (0 .. $w - 1) { $o[$i][$j] = $SPACE_CHR; } } $n = 0; while ($n < ($f + $c)) { $i = int(rand $h); $j = int(rand $w); next unless $o[$i][$j] eq $SPACE_CHR; $o[$i][$j] = $n++ >= $f ? $CRYST_CHR : $VAPOR_CHR; } @o; } sub transform_grid { my @o = @{$_[0]}; my $w = scalar(@{$o[0]}) - 1; my $h = scalar(@o) - 1; my $i, $j; for ($i = -$_[1]; $i < $h; $i += 2) { for ($j = -$_[1]; $j < $w; $j += 2) { &process_square(\($o[$i][$j], $o[$i + 1][$j], $o[$i + 1][$j + 1], $o[$i][$j + 1])); } } } sub process_square { my $tmp; if (&compare_list($VAPOR_CHR, @_)) { if (&compare_list($CRYST_CHR, @_)) { for (@_) { $$_ = $CRYST_CHR if $$_ eq $VAPOR_CHR; } } else { if (&compare_list($SPACE_CHR, @_)) { @_ = reverse @_ if (int(rand 2)); $tmp = ${$_[0]}; ${$_[0]} = ${$_[1]}; ${$_[1]} = ${$_[2]}; ${$_[2]} = ${$_[3]}; ${$_[3]} = $tmp; } } } } sub compare_list { my $match = shift @_; for (@_) { return 1 if $match eq $$_; } }