Wireworld
class Wireworld {
has @.line;
method height returns Int { @!line.elems }
method width returns Int { max @!line».chars }
multi method new(@line) { samewith :@line }
multi method new($str ) { samewith $str.lines }
method gist { join "\n", @.line }
method !neighbors($i where ^$.height, $j where ^$.width)
{
my @i = grep ^$.height, $i «+« (-1, 0, 1);
my @j = grep ^$.width, $j «+« (-1, 0, 1);
gather for @i X @j -> (\i, \j) {
next if [ i, j ] ~~ [ $i, $j ];
take @!line[i].comb[j];
}
}
method succ {
my @succ;
for ^$.height X ^$.width -> ($i, $j) {
@succ[$i] ~=
do given @.line[$i].comb[$j] {
when 'H' { 't' }
when 't' { '.' }
when '.' {
grep('H', self!neighbors($i, $j)) == 1|2 ?? 'H' !! '.'
}
default { ' ' }
}
}
return self.new: @succ;
}
}
my %*SUB-MAIN-OPTS;
%*SUB-MAIN-OPTS<named-anywhere> = True;
multi sub MAIN (
IO() $filename,
Numeric:D :$interval = 1/4,
Bool :$stop-on-repeat,
) {
run-loop :$interval, :$stop-on-repeat, Wireworld.new: $filename.slurp;
}
#| run a built-in example
multi sub MAIN (
Numeric:D :$interval = 1/4,
Bool :$stop-on-repeat,
) {
run-loop
:$interval,
:$stop-on-repeat,
Wireworld.new:
Q:to/§/
tH.........
. .
...
. .
Ht.. ......
§
}
sub run-loop (
Wireworld:D $initial,
Real:D(Numeric) :$interval = 1/4,
Bool :$stop-on-repeat
){
my %seen is SetHash;
print "\e7"; # save cursor position
for $initial ...^ * eqv * { # generate a sequence (uses .succ)
print "\e8"; # restore cursor position
.say;
last if $stop-on-repeat and %seen{ .gist }++;
sleep $interval;
}
}
When run with --stop-on-repeat
H.tH.tH.tH.
t .
ttt
t .
.H.t ......
Last updated