user
Wireworld is a cellular automaton with some similarities to Conway's Game of Life.

It is capable of doing sophisticated computations with appropriate programs
(it is actually Turing complete),
and is much simpler to program for.

A Wireworld arena consists of a Cartesian grid of cells,
each of which can be in one of four states.
All cell transitions happen simultaneously.

The cell transition rules are this:

:   :   | Input State | Output State | Condition |
        | --- | --- | --- |
        | empty | empty |  |
        | electron head | electron tail |  |
        | electron tail | conductor |  |
        | conductor | electron head | if 1 or 2 cells in the neighborhood of the cell are in the state “electron head” |
        | conductor | conductor | otherwise |

Task

Create a program that reads a Wireworld program from a file and displays an animation of the processing. Here is a sample description file (using "H" for an electron head, "t" for a tail, "." for a conductor and a space for empty) you may wish to test with, which demonstrates two cycle-3 generators and an inhibit gate:

```
tH.........
.   .
   ...
.   .
Ht.. ......

```

While text-only implementations of this task are possible, mapping cells to pixels is advisable if you wish to be able to display large designs. The logic is not significantly more complex.
assistant
(formerly Perl 6)

**Works with**: Rakudo version 2018.03

```
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`

Output:

```
H.tH.tH.tH.
t   .      
   ttt     
t   .      
.H.t ......
```