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.




Enumeration 
   #Empty     
   #Electron_head
   #Electron_tail
   #Conductor
EndEnumeration
 
#Delay=100
#XSize=23
#YSize=12
 
Procedure Limit(n, min, max)
  If n<min
    n=min
  ElseIf n>max
    n=max
  EndIf
  ProcedureReturn n
EndProcedure
 
Procedure Moore_neighborhood(Array World(2),x,y)
  Protected cnt=0, i, j
  For i=Limit(x-1, 0, #XSize) To Limit(x+1, 0, #XSize)
    For j=Limit(y-1, 0, #YSize) To Limit(y+1, 0, #YSize) 
      If World(i,j)=#Electron_head
        cnt+1
      EndIf
    Next
  Next
  ProcedureReturn cnt
EndProcedure
 
Procedure PresentWireWorld(Array World(2))
  Protected x,y
  ;ClearConsole()
  For y=0 To #YSize
    For x=0 To #XSize
      ConsoleLocate(x,y)
      Select World(x,y)
        Case #Electron_head
          ConsoleColor(12,0): Print("#")
        Case #Electron_tail
          ConsoleColor(4,0): Print("#")
        Case #Conductor
          ConsoleColor(6,0): Print("#")
        Default
          ConsoleColor(15,0): Print(" ")
      EndSelect
    Next
    PrintN("")
  Next
EndProcedure
 
Procedure UpdateWireWorld(Array World(2))
  Dim NewArray(#XSize,#YSize)
  Protected i, j
  For i=0 To #XSize
    For j=0 To #YSize
      Select World(i,j)
        Case #Electron_head
          NewArray(i,j)=#Electron_tail
        Case #Electron_tail
          NewArray(i,j)=#Conductor
        Case #Conductor
          Define m=Moore_neighborhood(World(),i,j)
          If m=1 Or m=2
            NewArray(i,j)=#Electron_head
          Else
            NewArray(i,j)=#Conductor
          EndIf
        Default ; e.g. should be Empty
          NewArray(i,j)=#Empty
      EndSelect
    Next
  Next
  CopyArray(NewArray(),World())
EndProcedure
 
If OpenConsole()
  EnableGraphicalConsole(#True)
  ConsoleTitle("XOR() WireWorld")
  ;- Set up the WireWorld
  Dim WW.i(#XSize,#YSize)
  Define x, y
  Restore StartWW
  For y=0 To #YSize
    For x=0 To #XSize
      Read.i WW(x,y)
    Next
  Next
 
  ;- Start the WireWorld simulation
  Repeat
    PresentWireWorld(WW())
    UpdateWireWorld(WW())
    Delay(#Delay)
  ForEver
EndIf 
 
DataSection
  StartWW:
  Data.i  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.i  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.i  0,0,0,3,3,3,3,2,1,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.i  0,0,1,0,0,0,0,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0,0,0
  Data.i  0,0,0,2,3,3,3,3,3,3,3,0,0,0,0,0,0,3,0,0,0,0,0,0
  Data.i  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,0,0,0,0
  Data.i  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,3,3,3,3,3
  Data.i  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,0,0,0,0
  Data.i  0,0,0,3,3,3,3,3,3,3,3,0,0,0,0,0,0,3,0,0,0,0,0,0
  Data.i  0,0,1,0,0,0,0,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0,0,0
  Data.i  0,0,0,2,3,3,3,3,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.i  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  Data.i  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
EndDataSection