Wireworld
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.




declare
  Rules =
  [rule(&  & )
   rule(&H &t)
   rule(&t &.)
   rule(&. &H when:fun {$ Neighbours}
                      fun {IsHead X} X == &H end
                      Hs = {Filter Neighbours IsHead}
                      Len = {Length Hs}
                   in
                      Len == 1 orelse Len == 2
                   end)
   rule(&. &.)]
 
  Init = ["tH........."
          ".   .      "
          "   ...     "
          ".   .      "
          "Ht.. ......"]
 
  MaxGen = 100
 
  %% G(i) -> G(i+1)
  fun {Evolve Gi}
     fun {Get X#Y}
        Row = {CondSelect Gi Y unit}
     in
        {CondSelect Row X & } %% cells beyond boundaries are empty
     end
     fun {GetNeighbors X Y}
        {Map [X-1#Y-1  X#Y-1  X+1#Y-1
              X-1#Y           X+1#Y
              X-1#Y+1  X#Y+1  X+1#Y+1]
         Get}
     end
  in
     {Record.mapInd Gi
      fun {$ Y Row}
         {Record.mapInd Row
          fun {$ X C}
             for Rule in Rules return:Return do
                if C == Rule.1 then
		   When = {CondSelect Rule when {Const true}}
		in
		   if {When {GetNeighbors X Y}} then
		      {Return Rule.2}
		   end
		end
	     end
          end}
      end}
  end
 
  %% Create an arena from a list of strings.
  fun {ReadArena LinesList}
     {List.toTuple '#'
      {Map LinesList
       fun {$ Line}
          {List.toTuple row Line}
       end}}
  end
 
  %% Converts an arena to a virtual string
  fun {ShowArena G}
     {Record.map G
      fun {$ L} {Record.toList L}#"\n" end}
  end
 
  %% helpers
  fun lazy {Iterate F V} V|{Iterate F {F V}} end
  fun {Const X} fun {$ _} X end end
 
  %% prepare GUI
  [QTk]={Module.link ["x-oz://system/wp/QTk.ozf"]}
  GenDisplay
  Field
  GUI = td(label(handle:GenDisplay)
           label(handle:Field font:{QTk.newFont font(family:'Courier')})
          )
  {{QTk.build GUI} show}
 
  G0 = {ReadArena Init}
  Gn = {Iterate Evolve G0}
in
  for
     Gi in Gn
     I in 0..MaxGen
  do
     {GenDisplay set(text:"Gen. "#I)}
     {Field set(text:{ShowArena Gi})}
     {Delay 500}
  end