# Wireworld

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

Wireworld
You are encouraged to solve this task according to the task description, using any language you may know.

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

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.

## 11l

Translation of: Python
V allstates = ‘Ht. ’
V tail      = allstates[1]
V conductor = allstates[2]
V empty     = allstates[3]

V w =
|‘tH.........
.   .
...
.   .
Ht.. ......’

T WW = ([[Char]] world, Int w, Int h)

V world = f.map(row -> row.rtrim(Array[Char]("\r\n")))
V height = world.len
V width = max(world.map(row -> row.len))
V nonrow = [‘ ’(‘ ’ * width)‘ ’]
V world2 = nonrow [+] world.map(row -> ‘ ’String(row).ljust(@width)‘ ’) [+] nonrow
V world3 = world2.map(row -> Array(row))
R WW(world3, width, height)

F newcell(currentworld, x, y)
V istate = currentworld[y][x]
assert(istate C :allstates, ‘Wireworld cell set to unknown value "#."’.format(istate))
V ostate = :empty
ostate = :tail
E I istate == :tail
ostate = :conductor
E I istate == :empty
ostate = :empty
E
V n = sum([(-1, -1), (-1, +0), (-1, +1),
(+0, -1),           (+0, +1),
(+1, -1), (+1, +0), (+1, +1)].map((dx, dy) -> Int(@currentworld[@y + dy][@x + dx] == :head)))
ostate = I n C 1..2 {:head} E :conductor
R ostate

F nextgen(ww)
V (world, width, height) = ww
V newworld = copy(world)
L(x) 1 .. width
L(y) 1 .. height
newworld[y][x] = newcell(world, x, y)
R WW(newworld, width, height)

F world2string(ww)
R ww.world[1 .< (len)-1].map(row -> (row[1 .< (len)-1]).join(‘’).rtrim((‘ ’, "\t", "\r", "\n"))).join("\n")

L(gen) 10
print(("\n#3 ".format(gen))‘’(‘=’ * (ww.w - 4))"\n")
print(world2string(ww))
ww = nextgen(ww)
Output:

0 =======

tH.........
.   .
...
.   .
Ht.. ......

1 =======

.tH........
H   .
...
H   .
t... ......

2 =======

H.tH.......
t   .
...
t   .
.H.. ......

3 =======

tH.tH......
.   H
...
.   .
HtH. ......

4 =======

.tH.tH.....
H   t
HHH
H   .
t.tH ......

5 =======

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

6 =======

tH.tH.tH...
.   H
...
.   .
HtH. ......

7 =======

.tH.tH.tH..
H   t
HHH
H   .
t.tH ......

8 =======

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

9 =======

tH.tH.tH.tH
.   H
...
.   .
HtH. ......


with Ada.Text_IO;  use Ada.Text_IO;

procedure Test_Wireworld is
type Cell is (' ', 'H', 't', '.');
type Board is array (Positive range <>, Positive range <>) of Cell;
-- Perform one transition of the cellular automation
procedure Wireworld (State : in out Board) is
function "abs" (Left : Cell) return Natural is
begin
if Left = 'H' then
return 1;
else
return 0;
end if;
end "abs";
Above   : array (State'Range (2)) of Cell := (others => ' ');
Left    : Cell := ' ';
Current : Cell;
begin
for I in State'First (1) + 1..State'Last (1) - 1 loop
for J in State'First (2) + 1..State'Last (2) - 1 loop
Current := State (I, J);
case Current is
when ' ' =>
null;
when 'H' =>
State (I, J) := 't';
when 't' =>
State (I, J) := '.';
when '.' =>
if abs Above (       J - 1) + abs Above (       J) + abs Above (       J + 1) +
abs Left                                        + abs State (I,     J + 1) +
abs State (I + 1, J - 1) + abs State (I + 1, J) + abs State (I + 1, J + 1)
in 1..2 then
State (I, J) := 'H';
else
State (I, J) := '.';
end if;
end case;
Above (J - 1) := Left;
Left := Current;
end loop;
end loop;
end Wireworld;
-- Print state of the automation
procedure Put (State : Board) is
begin
for I in State'First (1) + 1..State'Last (1) - 1 loop
for J in State'First (2) + 1..State'Last (2) - 1 loop
case State (I, J) is
when ' ' => Put (' ');
when 'H' => Put ('H');
when 't' => Put ('t');
when '.' => Put ('.');
end case;
end loop;
New_Line;
end loop;
end Put;
Oscillator : Board := ("         ", "  tH     ", " .  .... ", "  ..     ", "         ");
begin
for Step in 0..9 loop
Put_Line ("Step" & Integer'Image (Step) & " ---------"); Put (Oscillator);
Wireworld (Oscillator);
end loop;
end Test_Wireworld;


The solution assumes that the border of the board is empty. When transition is performed these cells are not changed. Automation transition is an in-place operation that allocates memory for to keep one row of the board size.

Step 0 ---------
tH
.  ....
..
Step 1 ---------
.t
.  H...
..
Step 2 ---------
..
.  tH..
.H
Step 3 ---------
..
.  .tH.
Ht
Step 4 ---------
..
H  ..tH
t.
Step 5 ---------
H.
t  ...t
..
Step 6 ---------
tH
.  ....
..
Step 7 ---------
.t
.  H...
..
Step 8 ---------
..
.  tH..
.H
Step 9 ---------
..
.  .tH.
Ht


## ALGOL 68

Translation of: python

- note: This specimen retains the original python coding style.

Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny
CO
Wireworld implementation.
CO

PROC exception = ([]STRING args)VOID:(
putf(stand error, ($"Exception"$, $", "g$, args, $l$));
stop
);

PROC assertion error = (STRING message)VOID:exception(("assertion error", message));

MODE CELL = CHAR;
MODE WORLD = FLEX[0, 0]CELL;
CELL head="H", tail="t", conductor=".", empty = " ";
STRING all states := empty;

BOOL wrap = FALSE; # is the world round? #

STRING nl := REPR 10;

STRING in string :=
"tH........."+nl+
".   ."+nl+
"   ..."+nl+
".   ."+nl+
"Ht.. ......"+nl
;

OP +:= = (REF FLEX[]FLEX[]CELL lines, FLEX[]CELL line)VOID:(
[UPB lines + 1]FLEX[0]CELL new lines;
new lines[:UPB lines]:=lines;
lines := new lines;
lines[UPB lines]:=line
);

PROC read file = (REF FILE in file)WORLD: (
# file > initial world configuration" #
FLEX[0]CELL line;
FLEX[0]FLEX[0]CELL lines;
INT upb x:=0, upb y := 0;
BEGIN
# on physical file end(in file, exit read line); #
make term(in file, nl);
FOR x TO 5 DO
get(in file, (line, new line));
upb x := x;
IF UPB line > upb y THEN upb y := UPB line FI;
lines +:= line
OD;
END;
[upb x, upb y]CELL out;
FOR x TO UPB out DO
out[x,]:=lines[x]+" "*(upb y-UPB lines[x])
OD;
out
);

PROC new cell = (WORLD current world, INT x, y)CELL: (
CELL istate := current world[x, y];
IF INT pos; char in string (istate, pos, all states); pos IS REF INT(NIL) THEN
assertion error("Wireworld cell set to unknown value "+istate) FI;
tail
ELIF istate = tail THEN
conductor
ELIF istate = empty THEN
empty
ELSE # istate = conductor #
[][]INT dxy list = ( (-1,-1), (-1,+0), (-1,+1),
(+0,-1),          (+0,+1),
(+1,-1), (+1,+0), (+1,+1) );
INT n := 0;
FOR enum dxy TO UPB dxy list DO
[]INT dxy = dxy list[enum dxy];
IF wrap THEN
INT px = ( x + dxy[1] - 1 ) MOD 1 UPB current world + 1;
INT py = ( y + dxy[2] - 1 ) MOD 2 UPB current world + 1;
n +:= ABS (current world[px, py] = head)
ELSE
INT px = x + dxy[1];
INT py = y + dxy[2];
IF px >= 1 LWB current world AND px <= 1 UPB current world AND
py >= 2 LWB current world AND py <= 2 UPB current world THEN
n +:= ABS (current world[px, py] = head)
FI
FI
OD;
IF 1 <= n AND n <= 2 THEN head ELSE conductor FI
FI
);

PROC next gen = (WORLD world)WORLD:(
# compute next generation of wireworld #
WORLD new world := world;
FOR x TO 1 UPB world DO
FOR y TO 2 UPB world DO
new world[x,y] := new cell(world, x, y)
OD
OD;
new world
);

PROC world2string = (WORLD world) STRING:(
STRING out:="";
FOR x TO UPB world DO
out +:= world[x,]+nl
OD;
out
);

FILE in file;
associate(in file, in string);

WORLD ww := read file(in file);
close(in file);

FOR gen TO 10 DO
printf ( ($lg(-3)" "$, gen-1,  $g$,"="* (2 UPB ww-4), $l$));
print ( world2string(ww) );
ww := next gen(ww)
OD
Output:
  0 =======
tH.........
.   .
...
.   .
Ht.. ......

1 =======
.tH........
H   .
...
H   .
t... ......

2 =======
H.tH.......
t   .
...
t   .
.H.. ......

3 =======
tH.tH......
.   H
...
.   .
HtH. ......

4 =======
.tH.tH.....
H   t
HHH
H   .
t.tH ......

5 =======
H.tH.tH....
t   .
ttt
t   .
.H.t ......

6 =======
tH.tH.tH...
.   H
...
.   .
HtH. ......

7 =======
.tH.tH.tH..
H   t
HHH
H   .
t.tH ......

8 =======
H.tH.tH.tH.
t   .
ttt
t   .
.H.t ......

9 =======
tH.tH.tH.tH
.   H
...
.   .
HtH. ......


## AutoHotkey

Works with: AutoHotkey_L
Library: GDIP
#SingleInstance, Force
#NoEnv
SetBatchLines, -1
File := "Wireworld.txt"
CellSize := 20
CellSize2 := CellSize - 2
C1 := 0xff000000
C2 := 0xff0066ff
C3 := 0xffd40055
C4 := 0xffffcc00

if (!FileExist(File)) {
MsgBox, % "File(" File ") is not present."
ExitApp
}

; Uncomment if Gdip.ahk is not in your standard library
; #Include, Gdip.ahk
If !pToken := Gdip_Startup(){
MsgBox, 48, Gdiplus error!, Gdiplus failed to start. Please ensure you have Gdiplus on your system.
ExitApp
}
OnExit, Exit

A := [], Width := 0
{
Row := A_Index
{
if (A_Index > Width)
Width := A_Index
if (A_LoopField = A_Space)
continue
A[Row, A_Index] := A_LoopField
}
}

Width := Width * CellSize + 2 * CellSize
, Height := Row * CellSize + 2 * CellSize
, Row := ""
, TopLeftX := (A_ScreenWidth - Width) // 2
, TopLeftY := (A_ScreenHeight - Height) // 2

Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs
Gui, 1: Show, NA

hwnd1 := WinExist()
, hbm := CreateDIBSection(Width, Height)
, hdc := CreateCompatibleDC()
, obm := SelectObject(hdc, hbm)
, G := Gdip_GraphicsFromHDC(hdc)
, Gdip_SetSmoothingMode(G, 4)

Loop {
pBrush := Gdip_BrushCreateSolid(C1)
, Gdip_FillRectangle(G, pBrush, 0, 0, Width, Height)
, Gdip_DeleteBrush(pBrush)

for RowNum, Row in A
for CellNum, Cell in Row
C := Cell = "H" ? C2 : Cell = "t" ? C3 : C4
, pBrush := Gdip_BrushCreateSolid(C)
, Gdip_FillRectangle(G, pBrush, CellNum * CellSize + 1, RowNum * CellSize - 2, CellSize2, CellSize2)
, Gdip_DeleteBrush(pBrush)

UpdateLayeredWindow(hwnd1, hdc, TopLeftX, TopLeftY, Width, Height)
, Gdip_GraphicsClear(G)
, A := NextState(A)
Sleep, 600
}

NextState(A) {
B := {}
for RowNum, Row in A {
for CellNum, Cell in Row {
if (Cell = "H")
B[RowNum, CellNum] := "t"
else if (Cell = "t")
B[RowNum, CellNum] := "."
else if (Cell = ".") {
H_Count := 0
Loop 3 {
Y := RowNum - 2 + A_Index
Loop, 3 {
X := CellNum - 2 + A_Index
if (A[Y, X] = "H")
H_Count++
}
}
if (H_Count = 1 || H_Count = 2)
B[RowNum, CellNum] := "H"
else
B[RowNum, CellNum] := "."
}
}
}
return B
}

p::Pause

Esc::
Exit:
Gdip_Shutdown(pToken)
ExitApp


## AutoIt

$ww = ""$ww &= "tH........." & @CR
$ww &= ". . " & @CR$ww &= "   ...     " & @CR
$ww &= ". . " & @CR$ww &= "Ht.. ......"
$rows = StringSplit($ww, @CR)
$cols = StringSplit($rows[1], "")
Global $Wireworldarray[$rows[0]][$cols[0]] For$I = 1 To $rows[0]$cols = StringSplit($rows[$I], "")
For $k = 1 To$cols[0]
$Wireworldarray[$I - 1][$k - 1] =$cols[$k] Next Next Wireworld($Wireworldarray)
Func Wireworld($array) Local$labelarray = $array Local$Top = 0, $Left = 0$hFui = GUICreate("Wireworld", UBound($array, 2) * 25, UBound($array) * 25)
For $I = 0 To UBound($array) - 1
For $k = 0 To UBound($array, 2) - 1
Switch $array[$I][$k] Case "t" ; Tail$labelarray[$I][$k] = GUICtrlCreateButton("", $Left,$Top, 25, 25)
GUICtrlSetBkColor($labelarray[$I][$k], 0xFF0000) Case "h" ; Head$labelarray[$I][$k] = GUICtrlCreateButton("", $Left,$Top, 25, 25)
GUICtrlSetBkColor($labelarray[$I][$k], 0x0000FF) Case "." ; Conductor$labelarray[$I][$k] = GUICtrlCreateButton("", $Left,$Top, 25, 25)
GUICtrlSetBkColor($labelarray[$I][$k], 0xFFFF00) Case " " ; Empty$labelarray[$I][$k] = GUICtrlCreateButton("", $Left,$Top, 25, 25)
GUICtrlSetBkColor($labelarray[$I][$k], 0x000000) EndSwitch$Left += 25
Next
$Left = 0$Top += 25
Next
GUISetState()
Local $nextsteparray =$array
While 1
$msg = GUIGetMsg()$array = $nextsteparray Sleep(250) For$I = 0 To UBound($array) - 1 For$k = 0 To UBound($array, 2) - 1 If$array[$I][$k] = " " Then ContinueLoop
If $array[$I][$k] = "h" Then$nextsteparray[$I][$k] = "t"
If $array[$I][$k] = "t" Then$nextsteparray[$I][$k] = "."
If $array[$I][$k] = "." Then$counter = 0
If $I - 1 >= 0 Then ; Top If$array[$I - 1][$k] = "h" Then $counter += 1 EndIf If$k - 1 >= 0 Then ; left
If $array[$I][$k - 1] = "h" Then$counter += 1
EndIf
If $I + 1 <= UBound($array) - 1 Then ; Bottom
If $array[$I + 1][$k] = "h" Then$counter += 1
EndIf
If $k + 1 <= UBound($array, 2) - 1 Then ;Right
If $array[$I][$k + 1] = "h" Then$counter += 1
EndIf
If $I - 1 >= 0 And$k - 1 >= 0 Then ; left Top
If $array[$I - 1][$k - 1] = "h" Then$counter += 1
EndIf
If $I + 1 <= UBound($array) - 1 And $k + 1 <= UBound($array, 2) - 1 Then ; Right Bottom
If $array[$I + 1][$k + 1] = "h" Then$counter += 1
EndIf
If $I + 1 <= UBound($array) - 1 And $k - 1 >= 0 Then ;Left Bottom If$array[$I + 1][$k - 1] = "h" Then $counter += 1 EndIf If$I - 1 >= 0 And $k + 1 <= UBound($array, 2) - 1 Then ; Top Right
If $array[$I - 1][$k + 1] = "h" Then$counter += 1
EndIf
If $counter = 1 Or$counter = 2 Then $nextsteparray[$I][$k] = "h" EndIf Next Next For$I = 0 To UBound($nextsteparray) - 1 For$k = 0 To UBound($nextsteparray, 2) - 1 Switch$nextsteparray[$I][$k]
Case "t" ; Tail
GUICtrlSetBkColor($labelarray[$I][$k], 0xFF0000) Case "h" ; Head GUICtrlSetBkColor($labelarray[$I][$k], 0x0000FF)
Case "." ; Conductor
GUICtrlSetBkColor($labelarray[$I][$k], 0xFFFF00) Case " " ; Empty GUICtrlSetBkColor($labelarray[$I][$k], 0x000000)
EndSwitch
$Left += 25 Next$Left = 0
$Top += 25 Next If$msg = -3 Then Exit
WEnd
EndFunc   ;==>Wireworld


## BBC BASIC

      Size% = 20
DIM P&(Size%-1,Size%-1), Q&(Size%-1,Size%-1)

VDU 23,22,Size%*8;Size%*8;64,64,16,0
OFF

DATA "tH........."
DATA ".   .      "
DATA "   ...     "
DATA ".   .      "
DATA "Ht.. ......"

FOR Y% = 12 TO 8 STEP -1
READ A$FOR X% = 1 TO LEN(A$)
P&(X%+4, Y%) = ASCMID$(A$, X%, 1) AND 15
NEXT
NEXT Y%

COLOUR  8,0,0,255 : REM Electron head = blue
COLOUR  4,255,0,0 : REM Electron tail = red
COLOUR 14,255,200,0 : REM Conductor orange

REPEAT
FOR Y% = 1 TO Size%-2
FOR X% = 1 TO Size%-2
IF P&(X%,Y%)<>Q&(X%,Y%) GCOL P&(X%,Y%) : PLOT X%*16, Y%*16
CASE P&(X%,Y%) OF
WHEN 0: Q&(X%,Y%) = 0
WHEN 8: Q&(X%,Y%) = 4
WHEN 4: Q&(X%,Y%) = 14
WHEN 14:
T% = (P&(X%+1,Y%)=8) + (P&(X%+1,Y%+1)=8) + (P&(X%+1,Y%-1)=8) + \
\    (P&(X%-1,Y%)=8) + (P&(X%-1,Y%+1)=8) + (P&(X%-1,Y%-1)=8) + \
\    (P&(X%,Y%-1)=8) + (P&(X%,Y%+1)=8)
IF T%=-1 OR T%=-2 THEN Q&(X%,Y%) = 8 ELSE Q&(X%,Y%) = 14
ENDCASE
NEXT
NEXT Y%
SWAP P&(), Q&()
WAIT 50
UNTIL FALSE


## C

For big graphics version, see: Wireworld/C

Text version with optional animation on POSIX systems:

Library: POSIX
Works with: VT100

Compile with -D_POSIX_C_SOURCE=199309L or greater to make nanosleep visible in <time.h>.

/* 2009-09-27 <kaz@kylheku.com> */
#define ANIMATE_VT100_POSIX
#include <stdio.h>
#include <string.h>
#ifdef ANIMATE_VT100_POSIX
#include <time.h>
#endif

char world_7x14[2][512] = {
{
"+-----------+\n"
"|tH.........|\n"
"|.   .      |\n"
"|   ...     |\n"
"|.   .      |\n"
"|Ht.. ......|\n"
"+-----------+\n"
}
};

void next_world(const char *in, char *out, int w, int h)
{
int i;

for (i = 0; i < w*h; i++) {
switch (in[i]) {
case ' ': out[i] = ' '; break;
case 't': out[i] = '.'; break;
case 'H': out[i] = 't'; break;
case '.': {
int hc = (in[i-w-1] == 'H') + (in[i-w] == 'H') + (in[i-w+1] == 'H') +
(in[i-1]   == 'H')                    + (in[i+1]   == 'H') +
(in[i+w-1] == 'H') + (in[i+w] == 'H') + (in[i+w+1] == 'H');
out[i] = (hc == 1 || hc == 2) ? 'H' : '.';
break;
}
default:
out[i] = in[i];
}
}
out[i] = in[i];
}

int main()
{
int f;

for (f = 0; ; f = 1 - f) {
puts(world_7x14[f]);
next_world(world_7x14[f], world_7x14[1-f], 14, 7);
#ifdef ANIMATE_VT100_POSIX
printf("\x1b[%dA", 8);
printf("\x1b[%dD", 14);
{
static const struct timespec ts = { 0, 100000000 };
nanosleep(&ts, 0);
}
#endif
}

return 0;
}


## C++

Library: libggi

(for graphics)

Library: POSIX

(for usleep)

#include <ggi/ggi.h>
#include <set>
#include <map>
#include <utility>
#include <iostream>
#include <fstream>
#include <string>

#include <unistd.h> // for usleep

enum cell_type { none, wire, head, tail };

// *****************
// * display class *
// *****************

// this is just a small wrapper for the ggi interface

class display
{
public:
display(int sizex, int sizey, int pixsizex, int pixsizey,
ggi_color* colors);
~display()
{
ggiClose(visual);
ggiExit();
}

void flush();
bool keypressed() { return ggiKbhit(visual); }
void clear();
void putpixel(int x, int y, cell_type c);
private:
ggi_visual_t visual;
int size_x, size_y;
int pixel_size_x, pixel_size_y;
ggi_pixel pixels[4];
};

display::display(int sizex, int sizey, int pixsizex, int pixsizey,
ggi_color* colors):
pixel_size_x(pixsizex),
pixel_size_y(pixsizey)
{
if (ggiInit() < 0)
{
std::cerr << "couldn't open ggi\n";
exit(1);
}

visual = ggiOpen(NULL);
if (!visual)
{
ggiPanic("couldn't open visual\n");
}

ggi_mode mode;
if (ggiCheckGraphMode(visual, sizex, sizey,
GGI_AUTO, GGI_AUTO, GT_4BIT,
&mode) != 0)
{
if (GT_DEPTH(mode.graphtype) < 2) // we need 4 colors!
ggiPanic("low-color displays are not supported!\n");
}
if (ggiSetMode(visual, &mode) != 0)
{
ggiPanic("couldn't set graph mode\n");
}

size_x = mode.virt.x;
size_y = mode.virt.y;

for (int i = 0; i < 4; ++i)
pixels[i] = ggiMapColor(visual, colors+i);
}

void display::flush()
{
// set the current display frame to the one we have drawn to
ggiSetDisplayFrame(visual, ggiGetWriteFrame(visual));

// flush the current visual
ggiFlush(visual);

// try to set a different frame for drawing (errors are ignored; if
// setting the new frame fails, the current one will be drawn upon,
// with the only adverse effect being some flickering).
ggiSetWriteFrame(visual, 1-ggiGetDisplayFrame(visual));
}

void display::clear()
{
ggiSetGCForeground(visual, pixels[0]);
ggiDrawBox(visual, 0, 0, size_x, size_y);
}

void display::putpixel(int x, int y, cell_type cell)
{
// this draws a logical pixel (i.e. a rectangle of size pixel_size_x
// times pixel_size_y), not a physical pixel
ggiSetGCForeground(visual, pixels[cell]);
ggiDrawBox(visual,
x*pixel_size_x, y*pixel_size_y,
pixel_size_x, pixel_size_y);
}

// *****************
// * the wireworld *
// *****************

// initialized to an empty wireworld
class wireworld
{
public:
void set(int posx, int posy, cell_type type);
void draw(display& destination);
void step();
private:
typedef std::pair<int, int> position;
typedef std::set<position> position_set;
typedef position_set::iterator positer;
};

void wireworld::set(int posx, int posy, cell_type type)
{
position p(posx, posy);
wires.erase(p);
tails.erase(p);
switch(type)
{
break;
case tail:
tails.insert(p);
break;
case wire:
wires.insert(p);
break;
}
}

void wireworld::draw(display& destination)
{
destination.clear();
for (positer i = tails.begin(); i != tails.end(); ++i)
destination.putpixel(i->first, i->second, tail);
for (positer i = wires.begin(); i != wires.end(); ++i)
destination.putpixel(i->first, i->second, wire);
destination.flush();
}

void wireworld::step()
{
for (int dx = -1; dx <= 1; ++dx)
for (int dy = -1; dy <= 1; ++dy)
{
position pos(i->first + dx, i->second + dy);
if (wires.count(pos))
}
wires.insert(tails.begin(), tails.end());
for (std::map<position, int>::iterator i = new_heads.begin();
++i)
{
//     std::cout << i->second;
if (i->second < 3)
{
wires.erase(i->first);
}
}
}

ggi_color colors[4] =
{{ 0x0000, 0x0000, 0x0000 },  // background: black
{ 0x8000, 0x8000, 0x8000 },  // wire: white
{ 0xffff, 0xffff, 0x0000 },  // electron head: yellow
{ 0xffff, 0x0000, 0x0000 }}; // electron tail: red

int main(int argc, char* argv[])
{
int display_x = 800;
int display_y = 600;
int pixel_x = 5;
int pixel_y = 5;

if (argc < 2)
{
std::cerr << "No file name given!\n";
return 1;
}

// assume that the first argument is the name of a file to parse
std::ifstream f(argv[1]);
wireworld w;
std::string line;
int line_number = 0;
while (std::getline(f, line))
{
for (int col = 0; col < line.size(); ++col)
{
switch (line[col])
{
case 'h': case 'H':
break;
case 't': case 'T':
w.set(col, line_number, tail);
break;
case 'w': case 'W': case '.':
w.set(col, line_number, wire);
break;
default:
std::cerr << "unrecognized character: " << line[col] << "\n";
return 1;
case ' ':
; // no need to explicitly set this, so do nothing
}
}
++line_number;
}

display d(display_x, display_y, pixel_x, pixel_y, colors);

w.draw(d);

while (!d.keypressed())
{
usleep(100000);
w.step();
w.draw(d);
}
std::cout << std::endl;
}


## Ceylon

abstract class Cell(shared Character char) of emptyCell | head | tail | conductor {

shared Cell output({Cell*} neighbors) =>
switch (this)
case (emptyCell) emptyCell
case (tail) conductor

string => char.string;
}

object emptyCell extends Cell(' ') {}

object tail extends Cell('t') {}

object conductor extends Cell('.') {}

Map<Character,Cell> cellsByChar = map { for (cell in Cell.caseValues) cell.char->cell };

class Wireworld(String data) {

value lines = data.lines;

value width = max(lines*.size);
value height = lines.size;

function toIndex(Integer x, Integer y) => x + y * width;

variable value currentState = Array.ofSize(width * height, emptyCell);
variable value nextState = Array.ofSize(width * height, emptyCell);

for (j->line in lines.indexed) {
for (i->char in line.indexed) {
currentState[toIndex(i, j)] = cellsByChar[char] else emptyCell;
}
}

value emptyGrid = Array.ofSize(width * height, emptyCell);
void clear(Array<Cell> cells) => emptyGrid.copyTo(cells);

shared void update() {
clear(nextState);
for(j in 0:height) {
for(i in 0:width) {
if(exists cell = currentState[toIndex(i, j)]) {
value nextCell = cell.output(neighborhood(currentState, i, j));
nextState[toIndex(i, j)] = nextCell;
}
}
}
value temp = currentState;
currentState = nextState;
nextState = temp;
}

shared void display() {
for (row in currentState.partition(width)) {
print("".join(row));
}
}

shared {Cell*} neighborhood(Array<Cell> grid, Integer x, Integer y) => {
for (j in y - 1..y + 1)
for (i in x - 1..x + 1)
if(i in 0:width && j in 0:height)
grid[toIndex(i, j)]
}.coalesced;

}

shared void run() {
value data = "tH.........
.   .
...
.   .
Ht.. ......";

value world = Wireworld(data);

variable value generation = 0;

void display() {
print("generation: generation");
world.display();
}

display();

while (true) {
if (exists input = process.readLine(), input.lowercased == "q") {
return;
}
world.update();
generation++;
display();

}
}


## Common Lisp

(defun electron-neighbors (wireworld row col)
(destructuring-bind (rows cols) (array-dimensions wireworld)
(loop   for off-row from (max 0 (1- row)) to (min (1- rows) (1+ row)) sum
(loop for off-col from (max 0 (1- col)) to (min (1- cols) (1+ col)) count
(and (not (and (= off-row row) (= off-col col)))
(eq 'electron-head (aref wireworld off-row off-col)))))))

(defun wireworld-next-generation (wireworld)
(destructuring-bind (rows cols) (array-dimensions wireworld)
(let ((backing (make-array (list rows cols))))
(do ((c 0 (if (= c (1- cols)) 0 (1+ c)))
(r 0 (if (= c (1- cols)) (1+ r) r)))
((= r rows))
(setf (aref backing r c) (aref wireworld r c)))
(do ((c 0 (if (= c (1- cols)) 0 (1+ c)))
(r 0 (if (= c (1- cols)) (1+ r) r)))
((= r rows))
(setf (aref wireworld r c)
(case (aref backing r c)
(electron-tail 'conductor)
(conductor (case (electron-neighbors backing r c)
(otherwise 'conductor)))
(otherwise nil)))))))

(defun print-wireworld (wireworld)
(destructuring-bind (rows cols) (array-dimensions wireworld)
(do ((r 0 (1+ r)))
((= r rows))
(do ((c 0 (1+ c)))
((= c cols))
(format t "~C" (case (aref wireworld r c)
(electron-tail #\t)
(conductor #\.)
(otherwise #\Space))))
(format t "~&"))))

(defun wireworld-show-gens (wireworld n)
(dotimes (m n)
(terpri)
(wireworld-next-generation wireworld)
(print-wireworld wireworld)))

(defun ww-char-to-symbol (char)
(ecase char
(#\Space 'nil)
(#\.     'conductor)
(#\t     'electron-tail)

(defun make-wireworld (image)
"Make a wireworld grid from a list of strings (rows) of equal length
(columns), each character being ' ', '.', 'H', or 't'."
(make-array (list (length image) (length (first image)))
:initial-contents
(mapcar (lambda (s) (map 'list #'ww-char-to-symbol s)) image)))

(defun make-rosetta-wireworld ()
(make-wireworld '("tH........."
".   .      "
"   ...     "
".   .      "
"Ht.. ......")))

Output:
CL-USER> (wireworld-show-gens (make-rosetta-wireworld) 12)

.tH........
H   .
...
H   .
t... ......

H.tH.......
t   .
...
t   .
.H.. ......

tH.tH......
.   H
...
.   .
HtH. ......

.tH.tH.....
H   t
HHH
H   .
t.tH ......

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

tH.tH.tH...
.   H
...
.   .
HtH. ......

.tH.tH.tH..
H   t
HHH
H   .
t.tH ......

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

tH.tH.tH.tH
.   H
...
.   .
HtH. ......

.tH.tH.tH.t
H   t
HHH
H   .
t.tH ......

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

tH.tH.tH.tH
.   H
...
.   .
HtH. ......

## D

import std.stdio, std.algorithm;

void wireworldStep(char[][] W1, char[][] W2) pure nothrow @safe @nogc {
foreach (immutable r; 1 .. W1.length - 1)
foreach (immutable c; 1 .. W1[0].length - 1)
switch (W1[r][c]) {
case 'H': W2[r][c] = 't'; break;
case 't': W2[r][c] = '.'; break;
case '.':
int nH = 0;
foreach (sr; -1 .. 2)
foreach (sc; -1 .. 2)
nH += W1[r + sr][c + sc] == 'H';
W2[r][c] = (nH == 1 || nH == 2) ? 'H' : '.';
break;
default:
}
}

void main() {
auto world = ["         ".dup,
"  tH     ".dup,
" .  .... ".dup,
"  ..     ".dup,
"         ".dup];

char[][] world2;
foreach (row; world)
world2 ~= row.dup;

foreach (immutable step; 0 .. 7) {
writefln("\nStep %d: ------------", step);
foreach (row; world[1 .. $- 1]) row[1 ..$ - 1].writeln;
wireworldStep(world, world2);
swap(world, world2);
}
}

Output:
Step 0: ------------
tH
.  ....
..

Step 1: ------------
.t
.  H...
..

Step 2: ------------
..
.  tH..
.H

Step 3: ------------
..
.  .tH.
Ht

Step 4: ------------
..
H  ..tH
t.

Step 5: ------------
H.
t  ...t
..

Step 6: ------------
tH
.  ....
..    

## Delphi

Translation of: Go
program Wireworld;

{$APPTYPE CONSOLE} uses System.SysUtils, System.IOUtils; var rows, cols: Integer; rx, cx: Integer; mn: TArray<Integer>; procedure Print(grid: TArray<byte>); begin writeln(string.Create('_', cols * 2), #10); for var r := 1 to rows do begin for var c := 1 to cols do begin if grid[r * cx + c] = 0 then write(' ') else write(' ', chr(grid[r * cx + c])); end; writeln; end; end; procedure Step(var dst: TArray<byte>; src: TArray<byte>); begin for var r := 1 to rows do begin for var c := 1 to cols do begin var x := r * cx + c; dst[x] := src[x]; case chr(dst[x]) of 'H': dst[x] := ord('t'); 't': dst[x] := ord('.'); '.': begin var nn := 0; for var n in mn do if src[x + n] = ord('H') then inc(nn); if (nn = 1) or (nn = 2) then dst[x] := ord('H'); end; end; end; end; end; procedure Main(); const CONFIG_FILE = 'ww.config'; begin if not FileExists(CONFIG_FILE) then begin Writeln(CONFIG_FILE, ' not exist'); exit; end; var srcRows := TFile.ReadAllLines(CONFIG_FILE); rows := length(srcRows); cols := 0; for var r in srcRows do begin if Length(r) > cols then cols := length(r); end; rx := rows + 2; cx := cols + 2; mn := [-cx - 1, -cx, -cx + 1, -1, 1, cx - 1, cx, cx + 1]; var _odd: TArray<byte>; var _even: TArray<byte>; SetLength(_odd, rx * cx); SetLength(_even, rx * cx); FillChar(_odd[0], rx * cx, 0); FillChar(_even[0], rx * cx, 0); for var i := 0 to High(srcRows) do begin var r := srcRows[i]; var offset := (i + 1) * cx + 1; for var j := 1 to length(r) do _odd[offset + j - 1] := ord(r[j]); end; while True do begin print(_odd); step(_even, _odd); Readln; print(_even); step(_odd, _even); Readln; end; end; begin Main; {$IFNDEF UNIX} readln; {$ENDIF} end.  Output: __________________ t H . . . . . . . __________________ . t . H . . . . . __________________ . . . t H . . . H __________________ . . . . t H . H t __________________ . . H . . t H t . __________________ H . t . . . t . . __________________ t H . . . . . . . __________________ . t . H . . . . .  ## EasyLang sys topleft global m[] nc . background 777 # proc show . . clear scale = 100 / nc sz = scale * 0.95 for i to len m[] x = (i - 1) mod nc y = (i - 1) div nc move x * scale y * scale if m[i] = 0 color 000 elif m[i] = 1 color 980 elif m[i] = 2 color 338 else color 833 . rect sz sz . . proc read . . s$ = input
nc = len s$+ 2 for i to nc m[] &= 0 . repeat m[] &= 0 for c$ in strchars s$if c$ = "."
m[] &= 1
elif c$= "H" m[] &= 2 elif c$ = "t"
m[] &= 3
else
m[] &= 0
.
.
for i to nc - len s$- 1 m[] &= 0 . s$ = input
until s$= "" . for i to nc m[] &= 0 . . read # len mn[] len m[] # proc update . . for i to len m[] if m[i] = 2 mn[i] = 3 elif m[i] = 3 mn[i] = 1 elif m[i] = 1 s = 0 for dx = -1 to 1 for dy = -1 to 1 ix = i + dy * nc + dx s += if m[ix] = 2 . . if s = 2 or s = 1 mn[i] = 2 else mn[i] = 1 . . . swap mn[] m[] . on timer update show timer 0.5 . show timer 0.5 # input_data tH......... . . ... . . Ht.. ...... ## Elena ELENA 6.x, using cellular library import system'routines; import extensions; import cellular; const string sample = " tH...... . ...... ...Ht... . .... . ..... .... ......tH . . ...... ...Ht..."; const string conductorLabel = "."; const string headLabel = "H"; const string tailLabel = "t"; const string emptyLabel = " "; const int empty = 0; const int conductor = 1; const int electronHead = 2; const int electronTail = 3; wireWorldRuleSet = new RuleSet { int proceed(Space s, int x, int y) { int cell := s.at(x, y); cell => conductor { int number := s.LiveCell(x, y, electronHead); if (number == 1 || number == 2) { ^ electronHead } else { ^ conductor } } electronHead { ^ electronTail } electronTail { ^ conductor } !{ ^ cell } } }; sealed class Model { Space theSpace; constructor load(string stateString, int maxX, int maxY) { var strings := stateString.splitBy(newLineConstant).selectBy::(s => s.toArray()).toArray(); theSpace := IntMatrixSpace.allocate(maxX, maxY, RuleSet { int proceed(Space s, int x, int y) { int retVal := 0; if (x < strings.Length) { var l := strings[x]; if (y < l.Length) { (l[y]) => conductorLabel { retVal := conductor } headLabel { retVal := electronHead } tailLabel { retVal := electronTail } emptyLabel { retVal := empty } } else { retVal := empty } } else { retVal := empty }; ^ retVal } }) } run() { theSpace.update(wireWorldRuleSet) } print() { int columns := theSpace.Columns; int rows := theSpace.Rows; int i := 0; int j := 0; while (i < rows) { j := 0; while (j < columns) { var label := emptyLabel; int cell := theSpace.at(i, j); cell => conductor { label := conductorLabel } electronHead { label := headLabel } electronTail { label := tailLabel }; console.write(label); j := j + 1 }; i := i + 1; console.writeLine() } } } public program() { Model model := Model.load(sample,10,30); for(int i := 0; i < 10; i += 1) { console.printLineFormatted("Iteration {0}",i); model.print().run() } } Output: Iteration 0 tH...... . ...... ...Ht... . .... . ..... .... ......tH . . ...... ...Ht... Iteration 1 .tH..... . ...... ..Ht.... . .... . ..... .... .......t . . H..... ..Ht.... Iteration 2 ..tH.... . ...... .Ht..... . .... . ..... .... ........ . . tH.... .Ht....H Iteration 3 ...tH... . ...... Ht...... . .... . ..... .... ........ . . .tH... Ht....Ht /* ... */ Iteration 9 ...tH... . .tH... ......Ht . .... H H.... tttH ...tH... . . ...... Ht......  ## Elixir Translation of: Ruby defmodule Wireworld do @empty " " @head "H" @tail "t" @conductor "." @neighbours (for x<- -1..1, y <- -1..1, do: {x,y}) -- [{0,0}] def set_up(string) do lines = String.split(string, "\n", trim: true) grid = Enum.with_index(lines) |> Enum.flat_map(fn {line,i} -> String.codepoints(line) |> Enum.with_index |> Enum.map(fn {char,j} -> {{i, j}, char} end) end) |> Enum.into(Map.new) width = Enum.map(lines, fn line -> String.length(line) end) |> Enum.max height = length(lines) {grid, width, height} end # to string defp to_s(grid, width, height) do Enum.map_join(0..height-1, fn i -> Enum.map_join(0..width-1, fn j -> Map.get(grid, {i,j}, @empty) end) <> "\n" end) end # transition all cells simultaneously defp transition(grid) do Enum.into(grid, Map.new, fn {{x, y}, state} -> {{x, y}, transition_cell(grid, state, x, y)} end) end # how to transition a single cell defp transition_cell(grid, current, x, y) do case current do @empty -> @empty @head -> @tail @tail -> @conductor _ -> if neighbours_with_state(grid, x, y) in 1..2, do: @head, else: @conductor end end # given a position in the grid, find the neighbour cells with a particular state def neighbours_with_state(grid, x, y) do Enum.count(@neighbours, fn {dx,dy} -> Map.get(grid, {x+dx, y+dy}) == @head end) end # run a simulation up to a limit of transitions, or until a recurring # pattern is found # This will print text to the console def run(string, iterations\\25) do {grid, width, height} = set_up(string) Enum.reduce(0..iterations, {grid, %{}}, fn count,{grd, seen} -> IO.puts "Generation : #{count}" IO.puts to_s(grd, width, height) if seen[grd] do IO.puts "I've seen this grid before... after #{count} iterations" exit(:normal) else {transition(grd), Map.put(seen, grd, count)} end end) IO.puts "ran through #{iterations} iterations" end end # this is the "2 Clock generators and an XOR gate" example from the wikipedia page text = """ ......tH . ...... ...Ht... . .... . ..... .... tH...... . . ...... ...Ht... """ Wireworld.run(text)  Output: Generation : 0 ......tH . ...... ...Ht... . .... . ..... .... tH...... . . ...... ...Ht... Generation : 1 .......t . H..... ..Ht.... . .... . ..... .... .tH..... . . ...... ..Ht.... Generation : 2 ........ . tH.... .Ht....H . .... . ..... .... ..tH.... . . ...... .Ht..... Generation : 3 ........ . .tH... Ht....Ht . .... . ..... .... ...tH... . . ...... Ht...... Generation : 4 ........ H ..tH.. t....Ht. . .... . ..... .... ....tH.. . H ...... t....... Generation : 5 H....... t ...tH. ....Ht.. . .... . ..... .... H....tH. . t ...... ........ Generation : 6 tH...... . ....tH ...Ht... . .... . ..... .... tH....tH . . ...... ........ Generation : 7 .tH..... . .....t ..Ht.... H .... . ..... .... .tH....t . . H..... ........ Generation : 8 ..tH.... . ...... .Ht..... t HHH. . ..... .... ..tH.... . . tH.... .......H Generation : 9 ...tH... . ...... Ht...... . tttH H H.... .... ...tH... . . .tH... ......Ht Generation : 10 ....tH.. H ...... t....... . ...t t tH... HHHH ....tH.. . . ..tH.. .....Ht. Generation : 11 H....tH. t ...... ........ . .... . .tH.. tttt .....tH. . . ...tH. ....Ht.. Generation : 12 tH....tH . ...... ........ . .... . ..tH. .... ......tH . . ....tH ...Ht... Generation : 13 .tH....t . H..... ........ . .... . ...tH .... .......t H . H....t ..Ht.... Generation : 14 ..tH.... . tH.... .......H . .... . ....t HHH. ........ t . tH.... .Ht....H Generation : 15 ...tH... . .tH... ......Ht . .... H H.... tttH ........ . . .tH... Ht....Ht Generation : 16 ....tH.. . ..tH.. .....Ht. . HHHH t tH... ...t ........ . H ..tH.. t....Ht. Generation : 17 .....tH. . ...tH. ....Ht.. . tttt . .tH.. .... H....... . t ...tH. ....Ht.. Generation : 18 ......tH . ....tH ...Ht... . .... . ..tH. .... tH...... . . ....tH ...Ht... Generation : 19 .......t . H....t ..Ht.... H .... . ...tH .... .tH..... H . .....t ..Ht.... Generation : 20 ........ . tH.... .Ht....H t HHH. . ....t HHH. ..tH.... t . ...... .Ht..... Generation : 21 ........ . .tH... Ht....Ht . tttH . H.... tttH ...tH... . . ...... Ht...... Generation : 22 ........ H ..tH.. t....Ht. . ...t . t.... ...t ....tH.. . H ...... t....... Generation : 23 H....... t ...tH. ....Ht.. . .... . ..... .... H....tH. . t ...... ........ I've seen this grid before... after 23 iterations  ## F# // Wireworld. Nigel Galloway: January 22nd., 2024 type Cell= |E |T |H |C let n=array2D [[T;H;C;C;C;C;C;C;C;C;C]; [C;E;E;E;C;E;E;E;E;E;E]; [E;E;E;C;C;C;E;E;E;E;E]; [C;E;E;E;C;E;E;E;E;E;E]; [H;T;C;C;E;C;C;C;C;C;C]] let fG n g=match n|>Seq.sumBy(fun n->match Array2D.get g (fst n) (snd n) with H->1 |_->0) with 1 |2->H |_->C let fX i=i|>Array2D.mapi(fun n g->function |E->E |H->T |T->C |C->fG (Seq.allPairs [max 0 (n-1)..min (n+1) (Array2D.length1 i-1)] [max 0 (g-1)..min (g+1) (Array2D.length2 i-1)]) i) Seq.unfold(fun n->Some(n,fX n))n|>Seq.take 15|>Seq.iteri(fun n g->printfn "%d:\n%A\n" n g)  Output: after 7: 8,9,10 are repeated as 11,12,13 then 14,15,16 etc 0: [[T; H; C; C; C; C; C; C; C; C; C] [C; E; E; E; C; E; E; E; E; E; E] [E; E; E; C; C; C; E; E; E; E; E] [C; E; E; E; C; E; E; E; E; E; E] [H; T; C; C; E; C; C; C; C; C; C]] 1: [[C; T; H; C; C; C; C; C; C; C; C] [H; E; E; E; C; E; E; E; E; E; E] [E; E; E; C; C; C; E; E; E; E; E] [H; E; E; E; C; E; E; E; E; E; E] [T; C; C; C; E; C; C; C; C; C; C]] 2: [[H; C; T; H; C; C; C; C; C; C; C] [T; E; E; E; C; E; E; E; E; E; E] [E; E; E; C; C; C; E; E; E; E; E] [T; E; E; E; C; E; E; E; E; E; E] [C; H; C; C; E; C; C; C; C; C; C]] 3: [[T; H; C; T; H; C; C; C; C; C; C] [C; E; E; E; H; E; E; E; E; E; E] [E; E; E; C; C; C; E; E; E; E; E] [C; E; E; E; C; E; E; E; E; E; E] [H; T; H; C; E; C; C; C; C; C; C]] 4: [[C; T; H; C; T; H; C; C; C; C; C] [H; E; E; E; T; E; E; E; E; E; E] [E; E; E; H; H; H; E; E; E; E; E] [H; E; E; E; C; E; E; E; E; E; E] [T; C; T; H; E; C; C; C; C; C; C]] 5: [[H; C; T; H; C; T; H; C; C; C; C] [T; E; E; E; C; E; E; E; E; E; E] [E; E; E; T; T; T; E; E; E; E; E] [T; E; E; E; C; E; E; E; E; E; E] [C; H; C; T; E; C; C; C; C; C; C]] 6: [[T; H; C; T; H; C; T; H; C; C; C] [C; E; E; E; H; E; E; E; E; E; E] [E; E; E; C; C; C; E; E; E; E; E] [C; E; E; E; C; E; E; E; E; E; E] [H; T; H; C; E; C; C; C; C; C; C]] 7: [[C; T; H; C; T; H; C; T; H; C; C] [H; E; E; E; T; E; E; E; E; E; E] [E; E; E; H; H; H; E; E; E; E; E] [H; E; E; E; C; E; E; E; E; E; E] [T; C; T; H; E; C; C; C; C; C; C]] 8: [[H; C; T; H; C; T; H; C; T; H; C] [T; E; E; E; C; E; E; E; E; E; E] [E; E; E; T; T; T; E; E; E; E; E] [T; E; E; E; C; E; E; E; E; E; E] [C; H; C; T; E; C; C; C; C; C; C]] 9: [[T; H; C; T; H; C; T; H; C; T; H] [C; E; E; E; H; E; E; E; E; E; E] [E; E; E; C; C; C; E; E; E; E; E] [C; E; E; E; C; E; E; E; E; E; E] [H; T; H; C; E; C; C; C; C; C; C]] 10: [[C; T; H; C; T; H; C; T; H; C; T] [H; E; E; E; T; E; E; E; E; E; E] [E; E; E; H; H; H; E; E; E; E; E] [H; E; E; E; C; E; E; E; E; E; E] [T; C; T; H; E; C; C; C; C; C; C]] 11: [[H; C; T; H; C; T; H; C; T; H; C] [T; E; E; E; C; E; E; E; E; E; E] [E; E; E; T; T; T; E; E; E; E; E] [T; E; E; E; C; E; E; E; E; E; E] [C; H; C; T; E; C; C; C; C; C; C]] 12: [[T; H; C; T; H; C; T; H; C; T; H] [C; E; E; E; H; E; E; E; E; E; E] [E; E; E; C; C; C; E; E; E; E; E] [C; E; E; E; C; E; E; E; E; E; E] [H; T; H; C; E; C; C; C; C; C; C]] 13: [[C; T; H; C; T; H; C; T; H; C; T] [H; E; E; E; T; E; E; E; E; E; E] [E; E; E; H; H; H; E; E; E; E; E] [H; E; E; E; C; E; E; E; E; E; E] [T; C; T; H; E; C; C; C; C; C; C]] 14: [[H; C; T; H; C; T; H; C; T; H; C] [T; E; E; E; C; E; E; E; E; E; E] [E; E; E; T; T; T; E; E; E; E; E] [T; E; E; E; C; E; E; E; E; E; E] [C; H; C; T; E; C; C; C; C; C; C]]  ## Forth 16 constant w 8 constant h : rows w * 2* ; 1 rows constant row h rows constant size create world size allot world value old old w + value new : init world size erase ; : age new old to new to old ; : foreachrow ( xt -- ) size 0 do I over execute row +loop drop ; 0 constant EMPTY 1 constant HEAD 2 constant TAIL 3 constant WIRE create cstate bl c, char H c, char t c, char . c, : showrow ( i -- ) cr old + w over + swap do I c@ cstate + c@ emit loop ; : show ['] showrow foreachrow ; : line ( row addr len -- ) bounds do i c@ case bl of EMPTY over c! endof 'H of HEAD over c! endof 't of TAIL over c! endof '. of WIRE over c! endof endcase 1+ loop drop ; : load ( filename -- ) r/o open-file throw init old row + 1+ ( file row ) begin over pad 80 rot read-line throw while over pad rot line row + repeat 2drop close-file throw show cr ; : +head ( sum i -- sum ) old + c@ HEAD = if 1+ then ; : conductor ( i WIRE -- i HEAD|WIRE ) drop 0 over 1- row - +head over row - +head over 1+ row - +head over 1- +head over 1+ +head over 1- row + +head over row + +head over 1+ row + +head 1 3 within if HEAD else WIRE then ; \ before: empty head tail wire create transition ' noop , ' 1+ , ' 1+ , ' conductor , \ after: empty tail wire head|wire : new-state ( i -- ) dup old + c@ dup cells transition + @ execute swap new + c! ; : newrow ( i -- ) w over + swap do I new-state loop ; : gen ['] newrow foreachrow age ; : wireworld begin gen 0 0 at-xy show key? until ;  Output: s" wireworld.diode" load .. tH...... .Ht .. ok gen show .. .tH..... Ht. .. ok gen show .H ..tH.... t.. .H ok gen show Ht ...tH..H ... Ht ok gen show t. ....tH.t ... t. ok gen show .. .....tH. ... .. ok gen show H. ......tH ... H. ok gen show tH .......t ... tH ok gen show .t ........ H.. .t ok gen show .. ........ tH. .. ok gen show .. ........ .tH .. ok gen show .. ........ ..t .. ok gen show .. ........ ... .. ok  ## Fortran Works with: Fortran version 95 and later program Wireworld implicit none integer, parameter :: max_generations = 12 integer :: nrows = 0, ncols = 0, maxcols = 0 integer :: gen, ierr = 0 integer :: i, j character(1), allocatable :: cells(:,:) character(10) :: form, sub character(80) :: buff ! open input file open(unit=8, file="wwinput.txt") ! find numbers of rows and columns in data do read(8, "(a)", iostat=ierr) buff if(ierr /= 0) exit nrows = nrows + 1 ncols = len_trim(buff) if(ncols > maxcols) maxcols = ncols end do ! allcate enough space to hold the data allocate(cells(0:nrows+1, 0:maxcols+1)) cells = " " ! load data rewind(8) do i = 1, nrows read(8, "(a)", iostat=ierr) buff if(ierr /= 0) exit do j = 1, maxcols cells(i, j) = buff(j:j) end do end do close(8) ! calculate format string for write statement write(sub, "(i8)") maxcols form = "(" // trim(adjustl(sub)) // "a1)" do gen = 0, max_generations write(*, "(/a, i0)") "Generation ", gen do i = 1, nrows write(*, form) cells(i, 1:maxcols) end do call nextgen(cells) end do deallocate(cells) contains subroutine Nextgen(cells) character, intent(in out) :: cells(0:,0:) character :: buffer(0:size(cells, 1)-1, 0:size(cells, 2)-1) integer :: i, j, h buffer = cells ! Store current status do i = 1, size(cells, 1)-2 do j = 1, size(cells, 2)-2 select case (buffer(i, j)) case(" ") ! no Change case("H") ! If a head change to tail cells(i, j) = "t" case("t") ! if a tail change to conductor cells(i, j) = "." case (".") ! Count number of electron heads in surrounding eight cells. ! We can ignore that fact that we count the centre cell as ! well because we already know it contains a conductor. ! If surrounded by 1 or 2 heads change to a head h = sum(count(buffer(i-1:i+1, j-1:j+1) == "H", 1)) if(h == 1 .or. h == 2) cells(i, j) = "H" end select end do end do end subroutine Nextgen end program Wireworld  Output: Generation 0 tH... . . ....... ...... . . tH... Generation 1 .tH.. . . ....... ...... . . .tH.. Generation 2 ..tH. . . ....... ...... . . ..tH. Generation 3 ...tH . . ....... ...... . . ...tH Generation 4 ....t . H ....... ...... . H ....t Generation 5 ..... . t ......H H..... . t ..... Generation 6 ..... . . .....Ht tH.... . . ..... Generation 7 ..... . . ....Ht. .tH... . . ..... Generation 8 ..... . . ...Ht.. ..tH.. . . ..... Generation 9 ..... . . ..Ht... ...tH. . . ..... Generation 10 ..... H . .Ht.... ....tH H . ..... Generation 11 H.... t . .t..... .....t t . H.... Generation 12 tH... . . ....... ...... . . tH... ## FreeBASIC #define MAXX 319 #define MAXY 199 enum state E=0, C=8, H=9, T=4 'doubles as colours: black, grey, bright blue, red end enum dim as uinteger world(0 to 1, 0 to MAXX, 0 to MAXY), active = 0, buffer = 1 dim as double rate = 1./3. 'seconds per frame dim as double tick dim as uinteger x, y function turn_on( world() as unsigned integer, x as uinteger, y as uinteger, a as uinteger ) as boolean dim as ubyte n = 0 dim as integer qx, qy for qx = -1 to 1 for qy = -1 to 1 if qx=0 andalso qy=0 then continue for if world(a,(x+qx+MAXX+1) mod (MAXX+1), (y+qy+MAXY+1) mod (MAXY+1))=H then n=n+1 'handles wrap-around next qy next qx if n=1 then return true if n=2 then return true return false end function 'generate sample map for x=20 to 30 world(active, x, 20) = C world(active, x, 24) = C next x world(active, 24, 24 ) = E world(active, 20, 21 ) = C world(active, 20, 23 ) = C world(active, 24, 21 ) = C world(active, 23, 22 ) = C world(active, 24, 22 ) = C world(active, 25, 22 ) = C world(active, 24, 23 ) = C world(active, 20, 20 ) = T world(active, 21, 20 ) = H world(active, 21, 24 ) = T world(active, 20, 24 ) = H screen 12 do tick = timer for x = 0 to 319 for y = 0 to 199 pset (x,y), world(active, x, y) if world(active,x,y) = E then world(buffer,x,y) = E 'empty cells stay empty if world(active,x,y) = H then world(buffer,x,y) = T 'electron heads turn into electron tails if world(active,x,y) = T then world(buffer,x,y) = C 'electron tails revert to conductors if world(active,x,y) = C then if turn_on(world(),x,y,active) then world(buffer,x,y) = H 'maybe electron heads spread else world(buffer,x,y) = C 'otherwise condutor remains conductor end if end if next y next x while tick + rate > timer wend cls buffer = 1 - buffer active = 1 - buffer loop ## GML Only visual output. Not an all-out simulator, but has some functions not on by default. //Create event /* Wireworld first declares constants and then reads a wireworld from a textfile. In order to implement wireworld in GML a single array is used. To make it behave properly, there need to be states that are 'in-between' two states: 0 = empty 1 = conductor from previous state 2 = electronhead from previous state 5 = electronhead that was a conductor in the previous state 3 = electrontail from previous state 4 = electrontail that was a head in the previous state */ empty = 0; conduc = 1; eHead = 2; eTail = 3; eHead_to_eTail = 4; coduc_to_eHead = 5; working = true;//not currently used, but setting it to false stops wireworld. (can be used to pause) toroidalMode = false; factor = 3;//this is used for the display. 3 means a single pixel is multiplied by three in size. var tempx,tempy ,fileid, tempstring, gridid, listid, maxwidth, stringlength; tempx = 0; tempy = 0; tempstring = ""; maxwidth = 0; //the next piece of code loads the textfile containing a wireworld. //the program will not work correctly if there is no textfile. if file_exists("WW.txt") { fileid = file_text_open_read("WW.txt"); gridid = ds_grid_create(0,0); listid = ds_list_create(); while !file_text_eof(fileid) { tempstring = file_text_read_string(fileid); stringlength = string_length(tempstring); ds_list_add(listid,stringlength); if maxwidth < stringlength { ds_grid_resize(gridid,stringlength,ds_grid_height(gridid) + 1) maxwidth = stringlength } else { ds_grid_resize(gridid,maxwidth,ds_grid_height(gridid) + 1) } for (i = 1; i <= stringlength; i +=1) { switch (string_char_at(tempstring,i)) { case ' ': ds_grid_set(gridid,tempx,tempy,empty); break; case '.': ds_grid_set(gridid,tempx,tempy,conduc); break; case 'H': ds_grid_set(gridid,tempx,tempy,eHead); break; case 't': ds_grid_set(gridid,tempx,tempy,eTail); break; default: break; } tempx += 1; } file_text_readln(fileid); tempy += 1; tempx = 0; } file_text_close(fileid); //fill the 'open' parts of the grid tempy = 0; repeat(ds_list_size(listid)) { tempx = ds_list_find_value(listid,tempy); repeat(maxwidth - tempx) { ds_grid_set(gridid,tempx,tempy,empty); tempx += 1; } tempy += 1; } boardwidth = ds_grid_width(gridid); boardheight = ds_grid_height(gridid); //the contents of the grid are put in a array, because arrays are faster. //the grid was needed because arrays cannot be resized properly. tempx = 0; tempy = 0; repeat(boardheight) { repeat(boardwidth) { board[tempx,tempy] = ds_grid_get(gridid,tempx,tempy); tempx += 1; } tempy += 1; tempx = 0; } //the following code clears memory ds_grid_destroy(gridid); ds_list_destroy(listid); } Now the step event //Step event /* This step event executes each 1/speed seconds. It checks everything on the board using an x and a y through two repeat loops. The variables westN,northN,eastN,southN, resemble the space left, up, right and down respectively, seen from the current x & y. 1 -> 5 (conductor is changing to head) 2 -> 4 (head is changing to tail) 3 -> 1 (tail became conductor) */ var tempx,tempy,assignhold,westN,northN,eastN,southN,neighbouringHeads,T; tempx = 0; tempy = 0; westN = 0; northN = 0; eastN = 0; southN = 0; neighbouringHeads = 0; T = 0; if working = 1 { repeat(boardheight) { repeat(boardwidth) { switch board[tempx,tempy] { case empty: assignhold = empty; break; case conduc: neighbouringHeads = 0; if toroidalMode = true //this is disabled, but otherwise lets wireworld behave toroidal. { if tempx=0 { westN = boardwidth -1; } else { westN = tempx-1; } if tempy=0 { northN = boardheight -1; } else { northN = tempy-1; } if tempx=boardwidth -1 { eastN = 0; } else { eastN = tempx+1; } if tempy=boardheight -1 { southN = 0; } else { southN = tempy+1; } T=board[westN,northN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } T=board[tempx,northN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } T=board[eastN,northN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } T=board[westN,tempy]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } T=board[eastN,tempy]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } T=board[westN,southN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } T=board[tempx,southN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } T=board[eastN,southN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } else//this is the default mode that works for the provided example. {//the next code checks whether coordinates fall outside the array borders. //and counts all the neighbouring electronheads. if tempx=0 { westN = -1; } else { westN = tempx - 1; T=board[westN,tempy]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } if tempy=0 { northN = -1; } else { northN = tempy - 1; T=board[tempx,northN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } if tempx = boardwidth -1 { eastN = -1; } else { eastN = tempx + 1; T=board[eastN,tempy]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } if tempy = boardheight -1 { southN = -1; } else { southN = tempy + 1; T=board[tempx,southN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } if westN != -1 and northN != -1 { T=board[westN,northN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } if eastN != -1 and northN != -1 { T=board[eastN,northN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } if westN != -1 and southN != -1 { T=board[westN,southN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } if eastN != -1 and southN != -1 { T=board[eastN,southN]; if T=eHead or T=eHead_to_eTail { neighbouringHeads += 1; } } } if neighbouringHeads = 1 or neighbouringHeads = 2 { assignhold = coduc_to_eHead; } else { assignhold = conduc; } break; case eHead: assignhold = eHead_to_eTail; break; case eTail: assignhold = conduc; break; default: break; } board[tempx,tempy] = assignhold; tempx += 1; } tempy += 1; tempx = 0; } } Now the draw event //Draw event /* This event occurs whenever the screen is refreshed. It checks everything on the board using an x and a y through two repeat loops and draws it. It is an important step, because all board values are changed to the normal versions: 5 -> 2 (conductor changed to head) 4 -> 3 (head changed to tail) */ //draw sprites and text first //now draw wireworld var tempx,tempy; tempx = 0; tempy = 0; repeat(boardheight) { repeat(boardwidth) { switch board[tempx,tempy] { case empty: //draw_point_color(tempx,tempy,c_black); draw_set_color(c_black); draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false); break; case conduc: //draw_point_color(tempx,tempy,c_yellow); draw_set_color(c_yellow); draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false); break; case eHead: //draw_point_color(tempx,tempy,c_red); draw_set_color(c_blue); draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false); draw_rectangle_color(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,c_red,c_red,c_red,c_red,false); break; case eTail: //draw_point_color(tempx,tempy,c_blue); draw_set_color(c_red); draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false); break; case coduc_to_eHead: //draw_point_color(tempx,tempy,c_red); draw_set_color(c_blue); draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false); board[tempx,tempy] = eHead; break; case eHead_to_eTail: //draw_point_color(tempx,tempy,c_blue); draw_set_color(c_red); draw_rectangle(tempx*factor,tempy*factor,(tempx+1)*factor-1,(tempy+1)*factor-1,false); board[tempx,tempy] = eTail; break; default: break; } tempx += 1 } tempy += 1; tempx = 0; } draw_set_color(c_black); ## Go Text output. Press Enter to compute and display successive generations. package main import ( "bytes" "fmt" "io/ioutil" "strings" ) var rows, cols int // extent of input configuration var rx, cx int // grid extent (includes border) var mn []int // offsets of moore neighborhood func main() { // read input configuration from file src, err := ioutil.ReadFile("ww.config") if err != nil { fmt.Println(err) return } srcRows := bytes.Split(src, []byte{'\n'}) // compute package variables rows = len(srcRows) for _, r := range srcRows { if len(r) > cols { cols = len(r) } } rx, cx = rows+2, cols+2 mn = []int{-cx-1, -cx, -cx+1, -1, 1, cx-1, cx, cx+1} // allocate two grids and copy input into first grid odd := make([]byte, rx*cx) even := make([]byte, rx*cx) for ri, r := range srcRows { copy(odd[(ri+1)*cx+1:], r) } // run for { print(odd) step(even, odd) fmt.Scanln() print(even) step(odd, even) fmt.Scanln() } } func print(grid []byte) { fmt.Println(strings.Repeat("__", cols)) fmt.Println() for r := 1; r <= rows; r++ { for c := 1; c <= cols; c++ { if grid[r*cx+c] == 0 { fmt.Print(" ") } else { fmt.Printf(" %c", grid[r*cx+c]) } } fmt.Println() } } func step(dst, src []byte) { for r := 1; r <= rows; r++ { for c := 1; c <= cols; c++ { x := r*cx + c dst[x] = src[x] switch dst[x] { case 'H': dst[x] = 't' case 't': dst[x] = '.' case '.': var nn int for _, n := range mn { if src[x+n] == 'H' { nn++ } } if nn == 1 || nn == 2 { dst[x] = 'H' } } } } }  ## Haskell import Data.List import Control.Monad import Control.Arrow import Data.Maybe states=" Ht." shiftS=" t.." borden bc xs = bs: (map (\x -> bc:(x++[bc])) xs) ++ [bs] where r = length$ head xs
bs = replicate (r+2) bc

take3x3 = ap ((.). taken. length) (taken. length. head) ap borden '*'
where taken n =  transpose. map (take n.map (take 3)).map tails

nwState xs | e =='.' && noH>0 && noH<3 = 'H'
| otherwise = shiftS !! (fromJust $elemIndex e states) where e = xs!!1!!1 noH = length$ filter (=='H') $concat xs runCircuit = iterate (map(map nwState).take3x3)  Example executed in GHCi: oscillator= [" tH ", ". ....", " .. " ] example = mapM_ (mapM_ putStrLn) .map (borden ' ').take 9$ runCircuit oscillator

Output:
*Main> example

tH
.  ....
..

.t
.  H...
..

..
.  tH..
.H

..
.  .tH.
Ht

..
H  ..tH
t.

H.
t  ...t
..

tH
.  ....
..

.t
.  H...
..

..
.  tH..
.H

(0.01 secs, 541764 bytes)


## Icon and Unicon

This simulation starts in single step mode and can be switched to run uninterrupted. The window can be saved at any point in single step mode. This uses 1 pixel per cell so this animation looks tiny. Also the orientation has been flipped.

link graphics

$define EDGE -1$define EMPTY 0
$define HEAD 1$define TAIL 2
$define COND 3 global Colours,Width,Height,World,oldWorld procedure main() # wire world modified from forestfire Height := 400 # Window height Width := 400 # Window width Rounds := 500 # max Rounds Delay := 5 # Runout Delay setup_world(read_world()) every round := 1 to Rounds do { show_world() if \runout then delay(Delay) else case Event() of { "q" : break # q = quit "r" : runout := 1 # r = run w/o stepping "s" : WriteImage("Wireworld-"||round) # save } evolve_world() } WDone() end procedure read_world() #: for demo in place of reading return [ "tH.........", ". .", " ...", ". .", "Ht.. ......"] end procedure setup_world(L) #: setup the world Colours := table() # define colours Colours[EDGE] := "grey" Colours[EMPTY] := "black" Colours[HEAD] := "blue" Colours[TAIL] := "red" Colours[COND] := "yellow" States := table() States["t"] := TAIL States["H"] := HEAD States[" "] := EMPTY States["."] := COND WOpen("label=Wireworld", "bg=black", "size=" || Width+2 || "," || Height+2) | # add for border stop("Unable to open Window") every !(World := list(Height)) := list(Width,EMPTY) # default every ( World[1,1 to Width] | World[Height,1 to Width] | World[1 to Height,1] | World[1 to Height,Width] ) := EDGE every r := 1 to *L & c := 1 to *L[r] do { # setup read in program World[r+1, c+1] := States[L[r,c]] } end procedure show_world() #: show World - drawn changes only every r := 2 to *World-1 & c := 2 to *World[r]-1 do if /oldWorld | oldWorld[r,c] ~= World[r,c] then { WAttrib("fg=" || Colours[tr := World[r,c]]) DrawPoint(r,c) } end procedure evolve_world() #: evolve world old := oldWorld := list(*World) # freeze copy every old[i := 1 to *World] := copy(World[i]) # deep copy every r := 2 to *World-1 & c := 2 to *World[r]-1 do World[r,c] := case old[r,c] of { # apply rules # EMPTY : EMPTY HEAD : TAIL TAIL : COND COND : { i := 0 every HEAD = ( old[r-1,c-1 to c+1] | old[r,c-1|c+1] | old[r+1,c-1 to c+1] ) do i +:= 1 if i := 1 | 2 then HEAD } } end  ## J The example circuit: circ0=:}: ] ;. _1 LF, 0 : 0 tH........ . . ... . . Ht.. ..... )  A 'boarding' verb board and the next cell state verb nwS: board=: ' ' ,.~ ' ' ,. ' ' , ' ' ,~ ] nwS=: 3 : 0 e=. (<1 1){y if. ('.'=e)*. e.&1 2 +/'H'=,y do. 'H' return. end. ' t..' {~ ' Ht.' i. e )  The 'most' powerful part is contained in the following iterating sentence, namely the dyad cut ;. [1]. In this way verb nwS can work on all the 3x3 matrices containing each cell surrounded by its 8 relevant neighbors.  process=: (3 3 nwS;. _3 board)^: (<10) process circuit  Example run:  (<10) process circ0 tH........ . . ... . . Ht.. ..... .tH....... H . ... H . t... ..... H.tH...... t . ... t . .H.. ..... tH.tH..... . H ... . . HtH. ..... .tH.tH.... H t HHH H . t.tH ..... H.tH.tH... t . ttt t . .H.t ..... tH.tH.tH.. . H ... . . HtH. ..... .tH.tH.tH. H t HHH H . t.tH ..... H.tH.tH.tH t . ttt t . .H.t ..... tH.tH.tH.t . H ... . . HtH. .....  Note also that a graphical presentation can be achieved using viewmat. For example: require'viewmat' viewmat"2 ' .tH'i. (<10) process circ0  (This example opens 10 windows, one for each generation.) ## Java See: Wireworld/Java ## JavaScript You have to search and open the file manually. This is the HTML you need to test. <!DOCTYPE html><html><head><meta charset="UTF-8"> <title>Wireworld</title> <script src="wireworld.js"></script></head><body> <input type='file' accept='text/plain' onchange='openFile( event )' /> <br /></body></html> var ctx, sizeW, sizeH, scl = 10, map, tmp; function getNeighbour( i, j ) { var ii, jj, c = 0; for( var b = -1; b < 2; b++ ) { for( var a = -1; a < 2; a++ ) { ii = i + a; jj = j + b; if( ii < 0 || ii >= sizeW || jj < 0 || jj >= sizeH ) continue; if( map[ii][jj] == 1 ) c++; } } return ( c == 1 || c == 2 ); } function simulate() { drawWorld(); for( var j = 0; j < sizeH; j++ ) { for( var i = 0; i < sizeW; i++ ) { switch( map[i][j] ) { case 0: tmp[i][j] = 0; break; case 1: tmp[i][j] = 2; break; case 2: tmp[i][j] = 3; break; case 3: if( getNeighbour( i, j ) ) tmp[i][j] = 1; else tmp[i][j] = 3; break; } } } [tmp, map] = [map, tmp]; setTimeout( simulate, 200 ); } function drawWorld() { ctx.fillStyle = "#000"; ctx.fillRect( 0, 0, sizeW * scl, sizeH * scl ); for( var j = 0; j < sizeH; j++ ) { for( var i = 0; i < sizeW; i++ ) { switch( map[i][j] ) { case 0: continue; case 1: ctx.fillStyle = "#03f"; break; case 2: ctx.fillStyle = "#f30"; break; case 3: ctx.fillStyle = "#ff3"; break; } ctx.fillRect( i, j, 1, 1 ); } } } function openFile( event ) { var input = event.target; var reader = new FileReader(); reader.onload = function() { createWorld( reader.result ); }; reader.readAsText(input.files[0]); } function createWorld( txt ) { var l = txt.split( "\n" ); sizeW = parseInt( l[0] ); sizeH = parseInt( l[1] ); map = new Array( sizeW ); tmp = new Array( sizeW ); for( var i = 0; i < sizeW; i++ ) { map[i] = new Array( sizeH ); tmp[i] = new Array( sizeH ); for( var j = 0; j < sizeH; j++ ) { map[i][j] = tmp[i][j] = 0; } } var t; for( var j = 0; j < sizeH; j++ ) { for( var i = 0; i < sizeW; i++ ) { switch( l[j + 2][i] ) { case " ": t = 0; break; case "H": t = 1; break; case "t": t = 2; break; case ".": t = 3; break; } map[i][j] = t; } } init(); } function init() { var canvas = document.createElement( "canvas" ); canvas.width = sizeW * scl; canvas.height = sizeH * scl; ctx = canvas.getContext( "2d" ); ctx.scale( scl, scl ); document.body.appendChild( canvas ); simulate(); }  ## jq Works with: jq version 1.4 In this implementation, a "world" is simply a string as illustrated by world9 and world11 below. The "game" can be played either by creating separate frames (using frames(n)), or by calling animation(n; sleep) with sleep approximately equal to the number of milliseconds between refreshes. "Animation" is based on the ANSI escape sequence for "clear screen". Notes on the implementation: • For efficiency, the implementation requires that the world has boundaries, as illustrated by world11 below. • For speed, the simulation uses the exploded string (an array). • The ASCII values of the symbols used to display the state are hardcoded. def lines: split("\n")|length; def cols: split("\n")[0]|length + 1; # allow for the newline # Is there an "H" at [x,y] relative to position i, assuming the width is w? # Input is an array; 72 is "H" def isH(x; y; i; w): if .[i+ w*y + x] == 72 then 1 else 0 end; def neighborhood(i;w): isH(-1; -1; i; w) + isH(0; -1; i; w) + isH(1; -1; i; w) + isH(-1; 0; i; w) + isH(1; 0; i; w) + isH(-1; 1; i; w) + isH(0; 1; i; w) + isH(1; 1; i; w) ; # The basic rules: # Input: a world # Output: the next state of .[i] def evolve(i; width) : # "Ht. " | explode => [ 72, 116, 46, 32 ] .[i] as$c
| if   $c == 32 then$c           # " " => " "
elif $c == 116 then 46 # "t" => "." elif$c ==  72 then 116          # "H" => "t"
elif $c == 46 then # "." # updates are "simultaneous" i.e. relative to$world
neighborhood(i; width) as $sum | (if [1,2]|index($sum) then 72 else . end)  # "H"
else $c end ; # [world, lines, cols] | next(w) => [world, lines, cols] def next: .[0] as$world | .[1] as $lines | .[2] as$w
| reduce range(0; $world|length) as$i
($world;$world | evolve($i;$w) as $next | if .[$i] == $next then . else .[$i] = $next end ) | [.,$lines, $w] ; # Animation # "clear screen": def cls: "\u001b[2J"; # Input: an integer; 1000 ~ 1 sec def spin: reduce range(1; 500 * .) as$i
(0; . + ($i|cos)*($i|cos) + ($i|sin)*($i|sin) )
|  "" ;

# Animate n steps;
# if "sleep" is non-negative then cls and
# sleep about "sleep" ms between frames.
def animate(n; sleep):
if n == 0 then empty
else (if sleep >= 0 then cls else "" end),
(.[0]|implode), n, "\n",
(sleep|spin),
( next|animate(n-1; sleep) )
end ;

# Input: a string representing the initial state
def animation(n; sleep):
[ explode, lines, cols] | animate(n; sleep) ;

# Input: a string representing the initial state
def frames(n):  animation(n; -1);#

Examples:

def world11:
"+-----------+\n" +
"|tH.........|\n" +
"|.   .      |\n" +
"|   ...     |\n" +
"|.   .      |\n" +
"|Ht.. ......|\n" +
"+-----------+\n" ;

def world9:
"         \n" +
"  tH     \n" +
" .  .... \n" +
"  ..     \n" +
"         \n" ;

Illustration 1:

# Ten-step animation with about 1 sec between frames
world9 | animation(10; 1000)

Illustration 2:

# Ten frames in sequence:
world11 | frames(10)

To run: jq -n -r -f wireworld.rc

## Julia

function surround2D(b, i, j)
h, w = size(b)
[b[x,y] for x in i-1:i+1, y in j-1:j+1 if (0 < x <= h && 0 < y <= w)]
end

surroundhas1or2(b, i, j) = 0 < sum(map(x->Char(x)=='H', surround2D(b, i, j))) <= 2 ? 'H' : '.'

function boardstep!(currentboard, nextboard)
x, y = size(currentboard)
for j in 1:y, i in 1:x
ch = Char(currentboard[i, j])
if ch == ' '
continue
else
nextboard[i, j] = (ch == 'H') ? 't' : (ch == 't' ? '.' :
surroundhas1or2(currentboard, i, j))
end
end
end

const b1 = "         " *
"  tH     " *
" .  .... " *
"  ..     " *
"         "
const mat = reshape(map(x->UInt8(x[1]), split(b1, "")), (9, 5))'
const mat2 = copy(mat)

function printboard(mat)
for i in 1:size(mat)[1]
println("\t", join([Char(c) for c in mat[i,:]], ""))
end
end

println("Starting Wireworld board:")
printboard(mat)
for step in 1:8
boardstep!(mat, mat2)
println(" Step $step:") printboard(mat2) mat .= mat2 end  Output:  Starting Wireworld board: tH . .... .. Step 1: .t . H... .. Step 2: .. . tH.. .H Step 3: .. . .tH. Ht Step 4: .. H ..tH t. Step 5: H. t ...t .. Step 6: tH . .... .. Step 7: .t . H... .. Step 8: .. . tH.. .H  ## Liberty BASIC WindowWidth = 840 WindowHeight = 600 dim p$( 40, 25), q$( 40, 25) empty$     = " "    '   white
tail$= "t" ' yellow head$      = "H"    '   black
conductor$= "." ' red jScr = 0 nomainwin menu #m, "File", "Load", [load], "Quit", [quit] open "wire world" for graphics_nf_nsb as #m #m "trapclose [quit]" 'timer 1000, [tmr] wait end [quit] close #m end [load] 'timer 0 filedialog "Open WireWorld File", "*.ww", file$
open file$for input as #in y =0 while not( eof( #in)) line input #in, lijn$
' print "|"; lijn$; "|" for x =0 to len( lijn$) -1
p$( x, y) =mid$( lijn$, x +1, 1) select case p$( x, y)
case " "
clr$="white" case "t" clr$ ="yellow"
case "H"
clr$="black" case "." clr$ ="red"
end select

#m "goto " ; 4 +x *20; " "; 4 +y *20
#m "backcolor "; clr$#m "down" #m "boxfilled "; 4 +x *20 +19; " "; 4 +y *20 +19 #m "up ; flush" next x y =y +1 wend close #in 'notice "Ready to run." timer 1000, [tmr] wait [tmr] timer 0 scan for x =0 to 40 ' copy temp array /current array for y =0 to 25 q$( x, y) =p$( x, y) next y next x for y =0 to 25 for x =0 to 40 select case q$( x, y)
case head$' heads ( black) become tails ( yellow) p$( x, y ) =tail$clr$ ="yellow"

case tail$' tails ( yellow) become conductors ( red) p$( x, y ) =conductor$clr$ ="red"

case conductor$' hCnt =0 xL =x -1: if xL < 0 then xL =40 ' wrap-round edges at all four sides xR =x +1: if xR >40 then xR = 0 yA =y -1: if yA < 0 then yA =25 yB =y +1: if yB >40 then yB = 0 if q$( xL, y ) =head$then hCnt =hCnt +1 ' Moore environment- 6 neighbours if q$( xL, yA) =head$then hCnt =hCnt +1 ' count all neighbours currently heads if q$( xL, yB) =head$then hCnt =hCnt +1 if q$( xR, y ) =head$then hCnt =hCnt +1 if q$( xR, yA) =head$then hCnt =hCnt +1 if q$( xR, yB) =head$then hCnt =hCnt +1 if q$( x,  yA) =head$then hCnt =hCnt +1 if q$( x,  yB) =head$then hCnt =hCnt +1 if ( hCnt =1) or ( hCnt =2) then ' conductor ( red) becomes head ( yellow) in this case only p$( x, y ) =head$' otherwise stays conductor ( red). clr$ ="black"
else
p$( x, y ) =conductor$
clr$="red" end if case else clr$ ="white"
end select

#m "goto " ; 4 +x *20; " "; 4 +y *20
#m "backcolor "; clr$#m "down" #m "boxfilled "; 4 +x *20 +19; " "; 4 +y *20 +19 #m "up" next x next y #m "flush" #m "getbmp scr 0 0 400 300" 'bmpsave "scr", "R:\scrJHF" +right$( "000" +str$( jScr), 3) +".bmp" jScr =jScr+1 if jScr >20 then wait timer 1000, [tmr] wait ## Logo Works with: MSWlogo (The wireworld given in the file must be bounded by spaces for the program to work. Also it is notable that the program takes the width as the longest of the lines.) to wireworld :filename :speed ;speed in n times per second, approximated Make "speed 60/:speed wireworldread :filename Make "bufferfield (mdarray (list :height :width) 0) for [i 0 :height-1] [for [j 0 :width-1] [mdsetitem (list :i :j) :bufferfield mditem (list :i :j) :field]] pu ht Make "gen 0 while ["true] [ ;The user will have to halt it :P ;clean seth 90 setxy 0 20 ;label :gen sety 0 for [i 0 :height-1] [for [j 0 :width-1] [mdsetitem (list :i :j) :field mditem (list :i :j) :bufferfield]] for [i 0 :height-1] [ for [j 0 :width-1] [ if (mditem (list :i :j) :field)=[] [setpixel [255 255 255]] ;blank if (mditem (list :i :j) :field)=1 [setpixel [0 0 0] if wn :j :i 2 [mdsetitem (list :i :j) :bufferfield 2]] ;wire if (mditem (list :i :j) :field)=2 [setpixel [0 0 255] mdsetitem (list :i :j) :bufferfield 3] ;head if (mditem (list :i :j) :field)=3 [setpixel [255 0 0] mdsetitem (list :i :j) :bufferfield 1] ;tail setx xcor+1 ] setxy 0 ycor-1 ] Make "gen :gen+1 wait :speed ] end to wireworldread :filename local [line] openread :filename setread :filename Make "width 0 Make "height 0 ; first pass, take dimensions while [not eofp] [ Make "line readword if (count :line)>:width [Make "width count :line] Make "height :height+1 ] ; second pass, load data setreadpos 0 Make "field (mdarray (list :height :width) 0) for [i 0 :height-1] [ Make "line readword foreach :line [ if ?=char 32 [mdsetitem (list :i #-1) :field []] if ?=". [mdsetitem (list :i #-1) :field 1] if ?="H [mdsetitem (list :i #-1) :field 2] if ?="t [mdsetitem (list :i #-1) :field 3] ] ] setread [] close :filename end to wn :x :y :thing ;WireNeighbourhood Make "neighbours 0 if (mditem (list :y-1 :x) :field)=:thing [Make "neighbours :neighbours+1] if (mditem (list :y-1 :x+1) :field)=:thing [Make "neighbours :neighbours+1] if (mditem (list :y :x+1) :field)=:thing [Make "neighbours :neighbours+1] if (mditem (list :y+1 :x+1) :field)=:thing [Make "neighbours :neighbours+1] if (mditem (list :y+1 :x) :field)=:thing [Make "neighbours :neighbours+1] if (mditem (list :y+1 :x-1) :field)=:thing [Make "neighbours :neighbours+1] if (mditem (list :y :x-1) :field)=:thing [Make "neighbours :neighbours+1] if (mditem (list :y-1 :x-1) :field)=:thing [Make "neighbours :neighbours+1] ifelse OR :neighbours=1 :neighbours=2 [op "true] [op "false] end ## Lua If ran using LÖVE, it will animate the simulation on a window. Otherwise it will print the first 10 steps on the console. local map = {{'t', 'H', '.', '.', '.', '.', '.', '.', '.', '.', '.'}, {'.', ' ', ' ', ' ', '.'}, {' ', ' ', ' ', '.', '.', '.'}, {'.', ' ', ' ', ' ', '.'}, {'H', 't', '.', '.', ' ', '.', '.', '.', '.', '.', '.'}} function step(map) local next = {} for i = 1, #map do next[i] = {} for j = 1, #map[i] do next[i][j] = map[i][j] if map[i][j] == "H" then next[i][j] = "t" elseif map[i][j] == "t" then next[i][j] = "." elseif map[i][j] == "." then local count = ((map[i-1] or {})[j-1] == "H" and 1 or 0) + ((map[i-1] or {})[j] == "H" and 1 or 0) + ((map[i-1] or {})[j+1] == "H" and 1 or 0) + ((map[i] or {})[j-1] == "H" and 1 or 0) + ((map[i] or {})[j+1] == "H" and 1 or 0) + ((map[i+1] or {})[j-1] == "H" and 1 or 0) + ((map[i+1] or {})[j] == "H" and 1 or 0) + ((map[i+1] or {})[j+1] == "H" and 1 or 0) if count == 1 or count == 2 then next[i][j] = "H" else next[i][j] = "." end end end end return next end if not not love then local time, frameTime, size = 0, 0.25, 20 local colors = {["."] = {255, 200, 0}, ["t"] = {255, 0, 0}, ["H"] = {0, 0, 255}} function love.update(dt) time = time + dt if time > frameTime then time = time - frameTime map = step(map) end end function love.draw() for i = 1, #map do for j = 1, #map[i] do love.graphics.setColor(colors[map[i][j]] or {0, 0, 0}) love.graphics.rectangle("fill", j*size, i*size, size, size) end end end else for iter = 1, 10 do print("\nstep "..iter.."\n") for i = 1, #map do for j = 1, #map[i] do io.write(map[i][j]) end io.write("\n") end map = step(map) end end  ## Mathematica/Wolfram Language DynamicModule[{data = ArrayPad[PadRight[Characters /@ StringSplit["tH......... . . ... . . Ht.. ......", "\n"]] /. {" " -> 0, "t" -> 2, "H" -> 1, "." -> 3}, 1]}, Dynamic@ArrayPlot[ data = CellularAutomaton[{{{_, _, _}, {_, 0, _}, {_, _, _}} -> 0, {{_, _, _}, {_, 1, _}, {_, _, _}} -> 2, {{_, _, _}, {_, 2, _}, {_, _, _}} -> 3, {{a_, b_, c_}, {d_, 3, e_}, {f_, g_, h_}} :> Switch[Count[{a, b, c, d, e, f, g, h}, 1], 1, 1, 2, 1, _, 3]}, data], ColorRules -> {1 -> Yellow, 2 -> Red}]]  ## MiniScript This GUI implementation is for use with Mini Micro. colors = [color.black, color.yellow, color.aqua, color.red] deltas = [[-1,-1], [-1,0], [-1,1], [ 0,-1], [ 0,1], [ 1,-1], [ 1,0], [ 1,1]] displayGrid = function(grid, td) for y in range(0, grid.len - 1) for x in range(0, grid[0].len - 1) td.setCell x,y, grid[y][x] end for end for end function buildGrid = function(s) lines = s.split(char(13)) nRows = lines.len nCols = 0 for line in lines if line.len > nCols then nCols = line.len end for grid = [] emptyRow = [] for c in range(1,nCols) emptyRow.push(0) end for for line in lines row = emptyRow[:] for i in range(0, line.len - 1) row[i] = " .Ht".indexOf(line[i]) end for grid.push(row) end for return grid end function getNewState = function(td, x, y) cellState = td.cell(x, y) if cellState == 3 then return 1 else if cellState == 2 then return 3 else if cellState == 1 then sum = 0 for delta in deltas x1 = x + delta[0] y1 = y + delta[1] if td.cell(x1, y1) == 2 then sum += 1 end for if sum == 1 or sum == 2 then return 2 else return 1 end if end if return cellState end function clear wireWorldProgram = "tH........." + char(13) wireWorldProgram += ". ." + char(13) wireWorldProgram += " ..." + char(13) wireWorldProgram += ". ." + char(13) wireWorldProgram += "Ht.. ......" grid = buildGrid(wireWorldProgram) // Prepare a tile display // Generate image used for the tiles from the colors defined above. img = Image.create(colors.len, 1); for i in range(0, colors.len - 1) img.setPixel(i, 0, colors[i]) end for cols = grid[0].len rows = grid.len display(4).mode = displayMode.tile td = display(4) cSize = 25 td.cellSize = cSize // size of cells on screen td.scrollX = -(960 - cols * (cSize + 1)) / 2 td.scrollY = -(640 - rows * (cSize + 1)) / 2 td.extent = [cols, rows] td.overlap = -1 // adds a small gap between cells td.tileSet = img; td.tileSetTileSize = 1 td.clear 0 while true displayGrid(grid, td) for y in range(0, rows - 1) for x in range(0, cols - 1) grid[y][x] = getNewState(td, x, y) end for end for wait 0.5 end while  ## Nim Translation of: C import strutils, os var world, world2 = """ +-----------+ |tH.........| |. . | | ... | |. . | |Ht.. ......| +-----------+""" let h = world.splitLines.len let w = world.splitLines[0].len template isH(x, y): int = int(s[i + w * y + x] == 'H') proc next(o: var string, s: string, w: int) = for i, c in s: o[i] = case c of ' ': ' ' of 't': '.' of 'H': 't' of '.': if (isH(-1, -1) + isH(0, -1) + isH(1, -1) + isH(-1, 0) + isH(1, 0) + isH(-1, 1) + isH(0, 1) + isH(1, 1) ) in 1..2: 'H' else: '.' else: c while true: echo world stdout.write "\x1b[",h,"A" stdout.write "\x1b[",w,"D" sleep 100 world2.next(world, w) swap world, world2  ## OCaml let w = [| " ......tH "; " . ...... "; " ...Ht... . "; " .... "; " . ..... "; " .... "; " tH...... . "; " . ...... "; " ...Ht... "; |] let is_head w x y = try if w.(x).[y] = 'H' then 1 else 0 with _ -> 0 let neighborhood_heads w x y = let n = ref 0 in for _x = pred x to succ x do for _y = pred y to succ y do n := !n + (is_head w _x _y) done; done; (!n) let step w = let n = Array.init (Array.length w) (fun i -> String.copy w.(i)) in let width = Array.length w and height = String.length w.(0) in for x = 0 to pred width do for y = 0 to pred height do n.(x).[y] <- ( match w.(x).[y] with | ' ' -> ' ' | 'H' -> 't' | 't' -> '.' | '.' -> (match neighborhood_heads w x y with | 1 | 2 -> 'H' | _ -> '.') | _ -> assert false) done; done; (n) let print = (Array.iter print_endline) let () = let rec aux w = Unix.sleep 1; let n = step w in print n; aux n in aux w  ## Oz Includes a simple animation, using a text widget. declare Rules = [rule(& & ) rule(&H &t) rule(&t &.) rule(&. &H when:fun {$ Neighbours}
fun {IsHead X} X == &H end
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.
{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 ## PARI/GP \\ 0 = conductor, 1 = tail, 2 = head, 3 = empty wireworldStep(M)={ my(sz=matsize(M),t); matrix(sz[1],sz[2],x,y, t=M[x,y]; if(t, [0,1,3][t] , t=sum(i=max(x-1,1),min(x+1,sz[1]), sum(j=max(y-1,1),min(y+1,sz[2]), M[i,j]==2 ) ); if(t==1|t==2,2,3) ) ) }; animate(M)={ while(1,display(M=wireworldStep(M))) }; display(M)={ my(sz=matsize(M),t); for(i=1,sz[1], for(j=1,sz[2], t=M[i,j]; print1([".","t","H"," "][t+1]) ); print ) }; animate(read("wireworld.gp")) ## Perl Read the initial World from stdin and print 10 steps to stdout my @f = ([],(map {chomp;['',( split // ),'']} <>),[]); for (1 .. 10) { print join "", map {"@$_\n"} @f;
my @a = ([]);
for my $y (1 ..$#f-1) {
my $r =$f[$y]; my$rr = [''];
for my $x (1 ..$#$r-1) { my$c = $r->[$x];
push @$rr,$c eq 'H' ? 't' :
$c eq 't' ? '.' :$c eq '.' ? (join('', map {"@{$f[$_]}[$x-1 ..$x+1]"=~/H/g} ($y-1 ..$y+1)) =~ /^H{1,2}$/ ? 'H' : '.') :$c;
}
push @$rr, ''; push @a,$rr;
}
@f = (@a,[]);
}


Input:

tH.........
.   .
...
.   .
Ht.. ......
Output:
 t H . . . . . . . . .
.       .
. . .
.       .
H t . .   . . . . . .

. t H . . . . . . . .
H       .
. . .
H       .
t . . .   . . . . . .

H . t H . . . . . . .
t       .
. . .
t       .
. H . .   . . . . . .

t H . t H . . . . . .
.       H
. . .
.       .
H t H .   . . . . . .

. t H . t H . . . . .
H       t
H H H
H       .
t . t H   . . . . . .

H . t H . t H . . . .
t       .
t t t
t       .
. H . t   . . . . . .

t H . t H . t H . . .
.       H
. . .
.       .
H t H .   . . . . . .

. t H . t H . t H . .
H       t
H H H
H       .
t . t H   . . . . . .

H . t H . t H . t H .
t       .
t t t
t       .
. H . t   . . . . . .

t H . t H . t H . t H
.       H
. . .
.       .
H t H .   . . . . . .


## Phix

Library: Phix/pGUI
Library: Phix/online

You can run this online here.

--
-- demo\rosetta\Wireworld.exw
-- ==========================
--
--  Invoke with file to read, or let it read the one below (if compiled assumes source is in the same directory)
--
--  Note that tabs in description files are not supported - where necessary spaces can be replaced with _ chars.
--  (tab chars in text files should technically always represent (to-next) 8 spaces, but not many editors respect
--   that, and instead assume the file will only ever be read by the same program/with matching settings. </rant>)
--  (see also demo\edix\src\tabs.e\ExpandTabs() for what you'd need if you knew what the tab chars really meant.)
--
with javascript_semantics
constant default_description = """
tH.........
.___.
___...
.___.
Ht.. ......
"""
sequence lines, counts
integer longest

function valid_line(string line, integer l=0)
if length(line)=0 then return 0 end if
for i=1 to length(line) do
integer ch = line[i]
if not find(ch," _.tH") then
if l and ch='\t' then
-- as above
printf(1,"error: tab char on line %d\n",{l})
{} = wait_key()
abort(0)
end if
return 0
end if
end for
return 1
end function

sequence text
if platform()=JS then
text = split(default_description,"\n")
else
string filename = substitute(command_line()[$],".exe",".exw") integer fn = open(filename,"r") if fn=-1 then printf(1,"error opening %s\n",{filename}) {} = wait_key() abort(0) end if text = get_text(fn,GT_LF_STRIPPED) close(fn) end if lines = {} for i=1 to length(text) do string line = text[i] if valid_line(line) then lines = {line} longest = length(line) for j=i+1 to length(text) do line = text[j] if not valid_line(line,j) then exit end if lines = append(lines,line) if longest<length(line) then longest = length(line) end if end for exit end if end for counts = deep_copy(lines) end procedure constant dxy = {{-1,-1}, {-1,+0}, {-1,+1}, {+0,-1}, {+0,+1}, {+1,-1}, {+1,+0}, {+1,+1}} procedure set_counts() for y=1 to length(lines) do for x=1 to length(lines[y]) do if lines[y][x]='.' then integer count = 0 for k=1 to length(dxy) do integer {cx,cy} = sq_add({x,y},dxy[k]) if cy>=1 and cy<=length(lines) and cx>=1 and cx<=length(lines[cy]) and lines[cy][cx]='H' then count += 1 end if end for counts[y][x] = (count=1 or count=2) end if end for end for end procedure include pGUI.e constant title = "Wireworld" Ihandle dlg, canvas, timer cdCanvas cddbuffer, cdcanvas function redraw_cb(Ihandle /*ih*/) integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE") integer dx = floor(w/(longest+2)) integer dy = floor(h/(length(lines)+2)) cdCanvasActivate(cddbuffer) cdCanvasClear(cddbuffer) set_counts() for y=1 to length(lines) do for x=1 to length(lines[y]) do integer c = lines[y][x], colour if find(c," _") then colour = CD_BLACK elsif c='.' then colour = CD_YELLOW if counts[y][x] then lines[y][x] = 'H' end if elsif c='H' then colour = CD_BLUE lines[y][x] = 't' elsif c='t' then colour = CD_RED lines[y][x] = '.' end if cdCanvasSetForeground(cddbuffer, colour) cdCanvasBox(cddbuffer,x*dx,x*dx+dx,h-y*dy,h-(y*dy+dy)) end for end for cdCanvasFlush(cddbuffer) return IUP_DEFAULT end function function timer_cb(Ihandle /*ih*/) IupUpdate(canvas) return IUP_IGNORE end function function map_cb(Ihandle ih) cdcanvas = cdCreateCanvas(CD_IUP, ih) cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas) cdCanvasSetBackground(cddbuffer, CD_BLACK) return IUP_DEFAULT end function procedure main() load_desc() IupOpen() canvas = IupCanvas("RASTERSIZE=300x180") IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"), "ACTION", Icallback("redraw_cb")}) timer = IupTimer(Icallback("timer_cb"), 500) dlg = IupDialog(canvas,TITLE="%s", {title}) IupShow(dlg) IupSetAttribute(canvas, "RASTERSIZE", NULL) if platform()!=JS then IupMainLoop() IupClose() end if end procedure main()  ## PHP $desc = 'tH.........
.   .
........
.   .
Ht.. ......

..
tH.... .......
..

..
tH..... ......
..';

$steps = 30; //fill in the world with the cells$world = array(array());
$row = 0;$col = 0;
foreach(str_split($desc) as$i){
switch($i){ case "\n":$row++;
//if($col >$width) $width =$col;
$col = 0;$world[] = array();
break;
case '.':
$world[$row][$col] = 1;//conductor$col++;
break;
case 'H':
$world[$row][$col] = 2;//head$col++;
break;
case 't':
$world[$row][$col] = 3;//tail$col++;
break;
default:
$world[$row][$col] = 0;//insulator/air$col++;
break;
};
};
function draw_world($world){ foreach($world as $rowc){ foreach($rowc as $cell){ switch($cell){
case 0:
echo ' ';
break;
case 1:
echo '.';
break;
case 2:
echo 'H';
break;
case 3:
echo 't';
};
};
echo "\n";
};
//var_export($world); }; echo "Original world:\n"; draw_world($world);
for($i = 0;$i < $steps;$i++){
$old_world =$world; //backup to look up where was an electron head
foreach($world as$row => &$rowc){ foreach($rowc as $col => &$cell){
switch($cell){ case 2:$cell = 3;
break;
case 3:
$cell = 1; break; case 1:$neigh_heads = (int) @$old_world[$row - 1][$col - 1] == 2;$neigh_heads += (int) @$old_world[$row - 1][$col] == 2;$neigh_heads += (int) @$old_world[$row - 1][$col + 1] == 2;$neigh_heads += (int) @$old_world[$row][$col - 1] == 2;$neigh_heads += (int) @$old_world[$row][$col + 1] == 2;$neigh_heads += (int) @$old_world[$row + 1][$col - 1] == 2;$neigh_heads += (int) @$old_world[$row + 1][$col] == 2; if($neigh_heads == 1 || $neigh_heads == 2){$cell = 2;
};
};
};
unset($cell); //just to be safe }; unset($rowc); //just to be safe
echo "\nStep " . ($i + 1) . ":\n"; draw_world($world);
};


## PicoLisp

This example uses 'grid' from "lib/simul.l", which maintains a two-dimensional structure.

(load "@lib/simul.l")

(let
(Data (in "wire.data" (make (while (line) (link @))))
Grid (grid (length (car Data)) (length Data)) )
(mapc
'((G D) (mapc put G '(val .) D))
Grid
(apply mapcar (flip Data) list) )
(loop
(disp Grid T
'((This) (pack " " (: val) " ")) )
(wait 1000)
(for Col Grid
(for This Col
(case (=: next (: val))
("H" (=: next "t"))
("t" (=: next "."))
("."
(when
(>=
2
(cnt # Count neighbors
'((Dir) (= "H" (get (Dir This) 'val)))
(quote
west east south north
((X) (south (west X)))
((X) (north (west X)))
((X) (south (east X)))
((X) (north (east X))) ) )
1 )
(=: next "H") ) ) ) ) )
(for Col Grid  # Update
(for This Col
(=: val (: next)) ) )
(prinl) ) )
Output:
   +---+---+---+---+---+---+---+---+---+---+---+
5 | t | H | . | . | . | . | . | . | . | . | . |
+---+---+---+---+---+---+---+---+---+---+---+
4 | . |   |   |   | . |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
3 |   |   |   | . | . | . |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
2 | . |   |   |   | . |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
1 | H | t | . | . |   | . | . | . | . | . | . |
+---+---+---+---+---+---+---+---+---+---+---+
a   b   c   d   e   f   g   h   i   j   k

+---+---+---+---+---+---+---+---+---+---+---+
5 | . | t | H | . | . | . | . | . | . | . | . |
+---+---+---+---+---+---+---+---+---+---+---+
4 | H |   |   |   | . |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
3 |   |   |   | . | . | . |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
2 | H |   |   |   | . |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
1 | t | . | . | . |   | . | . | . | . | . | . |
+---+---+---+---+---+---+---+---+---+---+---+
a   b   c   d   e   f   g   h   i   j   k

+---+---+---+---+---+---+---+---+---+---+---+
5 | H | . | t | H | . | . | . | . | . | . | . |
+---+---+---+---+---+---+---+---+---+---+---+
4 | t |   |   |   | . |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
3 |   |   |   | . | . | . |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
2 | t |   |   |   | . |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+
1 | . | H | . | . |   | . | . | . | . | . | . |
+---+---+---+---+---+---+---+---+---+---+---+
a   b   c   d   e   f   g   h   i   j   k

## PureBasic

### Standalone version

Enumeration
#Empty
#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)
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)
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)
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
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
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

### Load from external source, graphical presentations

CompilerIf #PB_Compiler_Unicode
CompilerError "The file handling in this small program is only in ASCII."
CompilerEndIf

Enumeration
#Empty
#Electron_tail
#Conductor
#COL_Empty          = $000000 #COL_Electron_head =$5100FE
#COL_Electron_tail  = $6A3595 #COL_Conductor =$62C4FF
#WW_Window  = 0
#WW_Timer   = 0
#WW_Image   = 0
EndEnumeration

#Delay=100
Global XSize, YSize

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)
cnt+1
EndIf
Next
Next
ProcedureReturn cnt
EndProcedure

Procedure PresentWireWorld(Array World(2))
Protected x,y
StartDrawing(ImageOutput(#WW_Image))
For y=0 To YSize-1
For x=0 To XSize-1
Select World(x,y)
Case #Electron_tail
Plot(x,y,#COL_Electron_tail)
Case #Conductor
Plot(x,y,#COL_Conductor)
Default
Plot(x,y,#COL_Empty)
EndSelect
Next
Next
StopDrawing()
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)
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
Else
NewArray(i,j)=#Conductor
EndIf
Default ; e.g. should be Empty
NewArray(i,j)=#Empty
EndSelect
Next
Next
CopyArray(NewArray(),World())
EndProcedure

Procedure LoadDataFromFile(File$,Array A(2)) Define Line$, x, y, *c.Character
If OpenFile(0,File$) ; ; Count non-commented lines & length of the first line, e.g. get Array(x,y) While Not Eof(0) Line$=Trim(ReadString(0))
*c=@Line$If Not PeekC(*c)=';' y+1 If Not x While PeekC(*c)>='0' And PeekC(*c)<='3' x+1: *c+1 Wend EndIf EndIf Wend XSize=x: YSize=y Dim A(XSize,YSize) ; ; Read in the Wire-World y=0 FileSeek(0,0) While Not Eof(0) Line$=Trim(ReadString(0))
*c=@Line$If Not PeekC(*c)=';' x=0 While x<XSize A(x,y)=PeekC(*c)-'0' x+1: *c+1 Wend y+1 EndIf Wend CloseFile(0) EndIf EndProcedure #Title="WireWorld, PureBasic" If OpenWindow(#WW_Window,0,0,XSize,YSize,#Title,#PB_Window_SystemMenu) Dim WW.i(0,0) Define Pattern$ = "Text (*.txt)|*.txt", Pattern = 0
Define DefFile$= "WireWorld.txt", Event Define Title$   = "Please choose file To load"
Define File$= OpenFileRequester(Title$, DefFile$, Pattern$, Pattern)
LoadDataFromFile(File$,WW()) ResizeWindow(#WW_Window,0,0,XSize,YSize) CreateImage(#WW_Image,XSize,YSize) Repeat Event=WaitWindowEvent() If Event=#PB_Event_Timer PresentWireWorld(WW()) UpdateWireWorld (WW()) EndIf Until Event=#PB_Event_CloseWindow EndIf Example of data file to load ; Save as "WireWorld.txt" ; ; ;=Comment ; 0=Empty Cell ; 1=Electron Head ; 2=Electron Tail ; 3=Conductor ; ; All lines nees to be of the same length, ; and containing only the defined values. ; ; ; Start of World ; 000000000000000000000000000000000000000000030030000000000000000000000000 000000000000000000000000000000000000000000300030000000000000000000000000 000333321330000000000000000000000033330003000030000000000000000000000000 001000000003333330000000000000000030030030000030000000000000000000000000 000233333330000003000000000000000030003300033330000000000000000000000000 000000000000000033330000333000000030000000030003330000000000000000000000 000000000000000030033333300333333333333333333333003333333333333333333333 000000000000000033330000333000000000000000000003330000030000000000000000 000333333330000003000000000000000000000000000000000000030000000000000000 001000000003333330000000033333330033333330000000000000030000000000000000 000233331230000000000000030000030030000030000000000033333333300000000000 000000000000000000000000030000030030000300000000000300000003000000000000 000000000000000000000000033333330033333000000000000003000033000000000000 000000000000000000000000030000000030000300000000000000333030000000000000 000000000000000000000000030000000030000030000000000000300033333333333330 000333321330000000000000030000000030000030003330000000333000000000000000 001000000003333330000000030000000003333300003330000000000000000000000000 000233333330000003000000300000000003000000003000000000000000000000000000 000000000000000033330003000033000030000000030000000000000000000000000000 000000000000000030033333333330333333333333333333333333333333333333333333 000000000000000033330000000033003000000000000000300000000000000000000000 000333333330000003000000000000003000000000000000300000000000000000000000 001000000003333330000000000000003000000000000000300000000000000000000000 000233331230000000000000000000003330000000000000300000000000000000000000 000000000000000000000000000000000030000000000000300000000000000000000000 000000000000000000000000000000000030000000000003333000000000000000000000 000000000000000000000000000000000030000000000003003333333333333333333333 000000000000000000000000000000000030000000000003333000000000000000000000 000333321330000000000000000000000003333000000000300000000000000000000000 001000000003333330000000000000000003003000000000300000000000000000000000 000233333330000003000000000000000003003333333333300000000000000000000000 000000000000000033330000330000000003000000000000000000000000000000000000 000000000000000030033333303333333333333333333333333333333333333333333333 000000000000000033330000330000000000000000000000000000000000000000000003 000333333330000003000000000000000000000000000000000000000000000000000003 001000000003333330000000003333333333333333333333333333333333333333333003 000233331230000000000000030000000000000000000000000000000000000000000003 000000000000000333333333333333333333333333333333333333333333333333333333 000000000000000300000000000000000000000000000000000000000000000000000000 ## Python ''' Wireworld implementation. ''' from io import StringIO from collections import namedtuple from pprint import pprint as pp import copy WW = namedtuple('WW', 'world, w, h') head, tail, conductor, empty = allstates = 'Ht. ' infile = StringIO('''\ tH......... . . ... . . Ht.. ......\ ''') def readfile(f): '''file > initial world configuration''' world = [row.rstrip('\r\n') for row in f] height = len(world) width = max(len(row) for row in world) # fill right and frame in empty cells nonrow = [ " %*s " % (-width, "") ] world = nonrow + \ [ " %*s " % (-width, row) for row in world ] + \ nonrow world = [list(row) for row in world] return WW(world, width, height) def newcell(currentworld, x, y): istate = currentworld[y][x] assert istate in allstates, 'Wireworld cell set to unknown value "%s"' % istate if istate == head: ostate = tail elif istate == tail: ostate = conductor elif istate == empty: ostate = empty else: # istate == conductor n = sum( currentworld[y+dy][x+dx] == head for dx,dy in ( (-1,-1), (-1,+0), (-1,+1), (+0,-1), (+0,+1), (+1,-1), (+1,+0), (+1,+1) ) ) ostate = head if 1 <= n <= 2 else conductor return ostate def nextgen(ww): 'compute next generation of wireworld' world, width, height = ww newworld = copy.deepcopy(world) for x in range(1, width+1): for y in range(1, height+1): newworld[y][x] = newcell(world, x, y) return WW(newworld, width, height) def world2string(ww): return '\n'.join( ''.join(row[1:-1]).rstrip() for row in ww.world[1:-1] ) ww = readfile(infile) infile.close() for gen in range(10): print ( ("\n%3i " % gen) + '=' * (ww.w-4) + '\n' ) print ( world2string(ww) ) ww = nextgen(ww)  Output:  0 ======= tH......... . . ... . . Ht.. ...... 1 ======= .tH........ H . ... H . t... ...... 2 ======= H.tH....... t . ... t . .H.. ...... 3 ======= tH.tH...... . H ... . . HtH. ...... 4 ======= .tH.tH..... H t HHH H . t.tH ...... 5 ======= H.tH.tH.... t . ttt t . .H.t ...... 6 ======= tH.tH.tH... . H ... . . HtH. ...... 7 ======= .tH.tH.tH.. H t HHH H . t.tH ...... 8 ======= H.tH.tH.tH. t . ttt t . .H.t ...... 9 ======= tH.tH.tH.tH . H ... . . HtH. ...... ## Racket #lang racket (require 2htdp/universe) (require 2htdp/image) (require racket/fixnum) ; see the forest fire task, from which this is derived... (define-struct wire-world (width height cells) #:prefab) (define state:_ 0) (define state:. 1) (define state:H 2) (define state:t 3) (define (char->state c) (case c ((#\_ #\space) state:_) ((#\.) state:.) ((#\H) state:H) ((#\t) state:t))) (define (initial-world l) (let ((h (length l)) (w (string-length (first l)))) (make-wire-world w h (for*/fxvector #:length (* h w) ((row (in-list l)) (cell (in-string row))) (char->state cell))))) (define initial-list '("tH........." ". . " " ... " ". . " "Ht.. ......")) (define-syntax-rule (count-neighbours-in-state ww wh wc r# c# state-to-match) (for/sum ((r (in-range (- r# 1) (+ r# 2))) #:when (< -1 r wh) (c (in-range (- c# 1) (+ c# 2))) #:when (< -1 c ww) ;; note, this will check cell at (r#, c#), too but it's not ;; worth checking that r=r# and c=c# each time in ;; this case, we know that (r#, c#) is a conductor: ; #:unless (and (= r# r) (= c# c)) (i (in-value (+ (* r ww) c))) #:when (= state-to-match (fxvector-ref wc i))) 1)) (define (cell-new-state ww wh wc row col) (let ((cell (fxvector-ref wc (+ col (* row ww))))) (cond ((= cell state:_) cell) ; empty -> empty ((= cell state:t) state:.) ; tail -> empty ((= cell state:H) state:t) ; head -> tail ((<= 1 (count-neighbours-in-state ww wh wc row col state:H) 2) state:H) (else cell)))) (define (wire-world-tick world) (define ww (wire-world-width world)) (define wh (wire-world-height world)) (define wc (wire-world-cells world)) (define (/w x) (quotient x ww)) (define (%w x) (remainder x ww)) (make-wire-world ww wh (for/fxvector #:length (* ww wh) ((cell (in-fxvector wc)) (r# (sequence-map /w (in-naturals))) (c# (sequence-map %w (in-naturals)))) (cell-new-state ww wh wc r# c#)))) (define colour:_ (make-color 0 0 0)) ; black (define colour:. (make-color 128 128 128)) ; grey (define colour:H (make-color 128 255 255)) ; bright cyan (define colour:t (make-color 0 128 128)) ; dark cyan (define colour-vector (vector colour:_ colour:. colour:H colour:t)) (define (cell-state->colour state) (vector-ref colour-vector state)) (define render-scaling 20) (define (render-world W) (define ww (wire-world-width W)) (define wh (wire-world-height W)) (define wc (wire-world-cells W)) (let* ((flat-state (for/list ((cell (in-fxvector wc))) (cell-state->colour cell)))) (place-image (scale render-scaling (color-list->bitmap flat-state ww wh)) (* ww (/ render-scaling 2)) (* wh (/ render-scaling 2)) (empty-scene (* render-scaling ww) (* render-scaling wh))))) (define (run-wire-world #:initial-state W) (big-bang (initial-world W) ;; initial state [on-tick wire-world-tick 1/8 ; tick time (seconds) ] [to-draw render-world])) (run-wire-world #:initial-state initial-list)  ## Raku (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 ......

## REXX

/*REXX program  displays a   wire world   Cartesian grid   of  four─state  cells.       */
parse arg  iFID .  '('  generations  rows  cols  bare  head  tail  wire  clearScreen  reps
if iFID==''  then iFID= "WIREWORLD.TXT"          /*should default input file  be used?  */
bla = 'BLANK'                            /*the "name" for a blank.              */
generations = p(generations     100   )          /*number generations that are allowed. */
rows = p(rows            3     )          /*the number of cell  rows.            */
cols = p(cols            3     )          /* "     "    "   "   columns.         */
bare = pickChar(bare     bla   )          /*character used to show an empty cell.*/
clearScreen = p(clearScreen     0     )          /*1    means to clear the screen.      */
tail = pickChar(tail     't'   )          /*  "   "      "      "   "   tail.    */
wire = pickChar(wire     .     )          /*  "   "      "      "   "   wire.    */
reps = p(reps            2     )          /*stop program  if there are 2 repeats.*/
fents= max(cols, linesize() - 1)                 /*the fence width used after displaying*/
#reps= 0;     $.= bare; gens= abs(generations) /*at start, universe is new and barren.*/ /* [↓] read the input file. */ do r=1 while lines(iFID)\==0 /*keep reading until the End─Of─File. */ q= strip( linein(iFID), 'T') /*get a line from input file. */ L= length(q); cols= max(cols, L) /*calculate maximum number of columns. */ do c=1 for L;$.r.c= substr(q, c, 1) /*assign the cells for the   R   row.  */
end   /*c*/
end      /*r*/
!.= 0;                      signal on halt       /*initial state of cells;  handle halt.*/
rows= r - 1;   life= 0;     call showCells       /*display initial state of the cells.  */
/*watch cells evolve, 4 possible states*/
do   life=1  for gens;    @.= bare             /*perform for the number of generations*/
do   r=1  for rows                          /*process each of the rows.            */
do c=1  for cols;    ?= $.r.c; ??= ? /* " " " " columns. */ select /*determine the type of cell. */ when ?==head then ??= tail when ?==tail then ??= wire when ?==wire then do; #= hood(); if #==1 | #==2 then ??= head; end otherwise nop end /*select*/ @.r.c= ?? /*possible assign a cell a new state.*/ end /*c*/ end /*r*/ call assign$                                   /*assign alternate cells ──► real world*/
if generations>0 | life==gens  then call showCells
end   /*life*/
/*stop watching the universe (or life).*/
halt: if life-1\==gens  then say 'The  ───Wireworld───  program was interrupted by user.'
done: exit 0                                     /*stick a fork in it,  we are all done.*/
/*───────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
$: parse arg _row,_col; return$._row._col==head
assign$: do r=1 for rows; do c=1 for cols;$.r.c= @.r.c;   end;   end;      return
hood:      return  $(r-1,c-1) +$(r-1,c)  + $(r-1,c+1) +$(r,c-1)  + $(r,c+1) +$(r+1,c-1)  + $(r+1,c) +$(r+1,c+1)
p:         return word(arg(1), 1)                           /*pick the 1st word in list.*/
pickChar:  parse arg _ .;arg U .;L=length(_);if U==bla then _=' '; if L==3 then _=d2c(_);if L==2 then _=x2c(_);return _
showRows:  _=;  do r=1  for rows; z=;  do c=1 for cols; z= z||$.r.c; end; z= strip(z,'T'); say z; _= _||z; end; return /*──────────────────────────────────────────────────────────────────────────────────────*/ showCells: if clearScreen then 'CLS' /*◄──change CLS for the host*/ call showRows /*show rows in proper order.*/ say right( copies('═', fents)life, fents) /*display a title for cells.*/ if _=='' then signal done /*No life? Then stop run. */ if !._ then #reps= #reps + 1 /*detected repeated pattern.*/ !._= 1 /*it is now an extant state.*/ if reps\==0 & #reps<=reps then return /*so far, so good, no reps.*/ say '"Wireworld" repeated itself' reps "times, the program is stopping." signal done /*jump to this pgm's "exit".*/  Programming note: the hood subroutine (above) could be optimized for speed by setting some short-circuit values (r-1, c-1, r+1, and c+1)  and using those values in the subsequent expressions. This REXX program makes use of the linesize REXX program (or BIF) which is used to determine the screen width (or linesize) of the terminal (console). The LINESIZE.REX REXX program is included here ──► LINESIZE.REX. output when using the default input file: (Cycle 0 (zero) is essentially a copy of the input file.) tH......... . . ... . . Ht.. ...... ════════════════════════════════════════════════════════════════════════════════════════0 .tH........ H . ... H . t... ...... ════════════════════════════════════════════════════════════════════════════════════════1 H.tH....... t . ... t . .H.. ...... ════════════════════════════════════════════════════════════════════════════════════════2 tH.tH...... . H ... . . HtH. ...... ════════════════════════════════════════════════════════════════════════════════════════3 .tH.tH..... H t HHH H . t.tH ...... ════════════════════════════════════════════════════════════════════════════════════════4 H.tH.tH.... t . ttt t . .H.t ...... ════════════════════════════════════════════════════════════════════════════════════════5 tH.tH.tH... . H ... . . HtH. ...... ════════════════════════════════════════════════════════════════════════════════════════6 .tH.tH.tH.. H t HHH H . t.tH ...... ════════════════════════════════════════════════════════════════════════════════════════7 H.tH.tH.tH. t . ttt t . .H.t ...... ════════════════════════════════════════════════════════════════════════════════════════8 tH.tH.tH.tH . H ... . . HtH. ...... ════════════════════════════════════════════════════════════════════════════════════════9 .tH.tH.tH.t H t HHH H . t.tH ...... ═══════════════════════════════════════════════════════════════════════════════════════10 H.tH.tH.tH. t . ttt t . .H.t ...... ═══════════════════════════════════════════════════════════════════════════════════════11 tH.tH.tH.tH . H ... . . HtH. ...... ═══════════════════════════════════════════════════════════════════════════════════════12 .tH.tH.tH.t H t HHH H . t.tH ...... ═══════════════════════════════════════════════════════════════════════════════════════13 "Wireworld" repeated itself 2 times, the program is stopping.  ## RISC-V Assembly /* gnu assembler syntax */ wireworld: /* unsigned int width (a0) */ /* unsigned int height (a1) */ /* char* grid (a2) */ mv a4,a2 li t4,'. /* conductor */ li t5,'H /* head */ li t6,'t /* tail */ addi t2,a0,-1 addi t3,a1,-1 mv t1,zero .yloop: /* outer loop (y) */ mv t0,zero .xloop: /* inner loop (x) */ lb a5,0(a4) bgt a5,t4,.torh blt a5,t4,.empty /* conductor: */ /* unsigned int head_count (a3) */ /* char* test_ptr (a6) */ /* char test (a7) */ mv a3,zero sub a6,a4,a0 addi a6,a6,-1 0: beq t1,zero,1f /* bounds up */ beq t0,zero,0f /* bounds left */ lb a7,0(a6) bne a7,t6,0f addi a3,a3,1 0: lb a7,1(a6) bne a7,t6,0f addi a3,a3,1 0: beq t0,t2,0f /* bounds right */ lb a7,2(a6) bne a7,t6,0f addi a3,a3,1 0:1: add a6,a6,a0 beq t0,zero,0f /* bounds left */ lb a7,0(a6) bne a7,t6,0f addi a3,a3,1 0: beq t0,t2,0f /* bounds right */ lb a7,2(a6) bne a7,t5,0f addi a3,a3,1 0: add a6,a6,a0 beq t1,t3,1f /* bounds down */ beq t0,zero,0f /* bounds left */ lb a7,0(a6) bne a7,t5,0f addi a3,a3,1 0: lb a7,1(a6) bne a7,t5,0f addi a3,a3,1 0: beq t0,t2,0f /* bounds right */ lb a7,2(a6) bne a7,t5,0f addi a3,a3,1 0:1: beq a3,zero,.empty addi a3,a3,-2 bgt a3,zero,.empty mv a5,t5 /* convert conductor to electron head */ j .save .torh: beq a5,t6,.tail .head: mv a5,t6 j .save .tail: mv a5,t4 .save: sb a5,0(a4) .empty: /* do nothing */ /* end x-loop */ addi a4,a4,1 addi t0,t0,1 bne t0,a0,.xloop /* end y-loop */ addi t1,t1,1 bne t1,a1,.yloop ret For output, compile the above to an object file and link against the following program: #include <stdio.h> #include <string.h> char init[] = " tH....tH " " . ...... " " ........ . " " .. .... .. .. .. " ".. ... . ..tH....tH... .tH..... ....tH.. .tH." " .. .... .. .. .. " " tH...... . " " . ....tH " " ...Ht... "; int width = 60; int height = 9; void wireworld(unsigned int, unsigned int, char *); int main() { char tmp[width + 1] = {}; do { for (int i = 0; i < height; i++) { strncpy(tmp, init + i * width, width); puts(tmp); } wireworld(width, height, init); } while (getchar()); return 0; }  Example output:  tH....tH . ...... ........ . .. .... .. .. .. .. ... . ..tH....tH... .tH..... ....tH.. .tH. .. .... .. .. .. tH...... . . ....tH ...Ht... .tH....t . H..... ........ . .. .... .. .. .. .. ... . ...tH....tH.. ..tH.... .....tH. ..tH .. .... .. .. .. .tH..... H . .....t ..Ht.... ..tH.... . tH.... .......H . .. .... .. .. H. .. ... . ....tH....tH. ...tH... ......tH ...t .. HHH. .. .. H. ..tH.... t . ...... .Ht..... ...tH... . .tH... ......Ht . .. .... H. .. tH .. ... H H....tH....tH ....tH.. .......t .... .. tttH H. .. tH ...tH... . . ...... Ht...... ....tH.. . ..tH.. .....Ht. . .. HHHH tH .. .t .. ... t tH....tH....t .....tH. ........ H... .. ...t tH .. .t ....tH.. . H ...... t....... .....tH. . ...tH. ....Ht.. . .. tttt .t H. .. .. ... . .tH....tH.... H.....tH ........ tH.. .. .... .t H. .. H....tH. . t ...... ........ ......tH . ....tH ...Ht... . .. .... .. tH .. .. ... . ..tH....tH... tH.....t ........ .tH. .. .... .. tH .. tH....tH . . ...... ........ .......t . H....t ..Ht.... H .. .... .. .t .. .. ... . ...tH....tH.. .tH..... H....... ..tH .. .... .. .t .. .tH....t . . H..... ........ ........ . tH.... .Ht....H t .. HHH. .. .. .. .. ... . ....tH....tH. ..tH.... tH...... ...t .. .... .. .. .. ..tH.... . . tH.... .......H ........ . .tH... Ht....Ht . .. tttH H. .. .. .. ... H H....tH....tH ...tH... .tH..... .... .. .... H. .. .. ...tH... . . .tH... ......Ht ........ H ..tH.. t....Ht. . .. ...t tH .. .. .. ... t tH....tH....t ....tH.. ..tH.... .... .. HHHH tH .. .. ....tH.. . . ..tH.. .....Ht. H....... t ...tH. ....Ht.. . .. .... .t .. .. .. ... . .tH....tH.... H....tH. ...tH... .... .. tttt .t .. .. .....tH. . . ...tH. ....Ht.. tH...... . ....tH ...Ht... . .. .... .. H. .. .. ... . ..tH....tH... tH....tH ....tH.. .... .. .... .. H. .. ......tH . . ....tH ...Ht... .tH..... . .....t ..Ht.... H .. .... .. tH .. .. ... . ...tH....tH.. .tH....t .....tH. .... .. .... .. tH .. .......t H . H....t ..Ht.... ..tH.... . ...... .Ht..... t .. HHH. .. .t H. .. ... . ....tH....tH. ..tH.... H.....tH .... .. HHH. .. .t H. ........ t . tH.... .Ht....H ...tH... . ...... Ht...... . .. tttH H. .. tH .. ... . H....tH....tH ...tH... tH.....t .... .. tttH H. .. tH ........ . . .tH... Ht....Ht ....tH.. H ...... t....... . .. ...t tH .. .t .. ... . t.....tH....t ....tH.. .tH..... H... .. ...t tH .. .t ........ . H ..tH.. t....Ht. H....tH. t ...... ........ . .. .... .t .. .. .. ... . .......tH.... H....tH. ..tH.... tH.. .. .... .t .. .. H....... . t ...tH. ....Ht.. tH....tH . ...... ........ . .. .... .. H. .. .. ... . ........tH... tH....tH ...tH... .tH. .. .... .. H. .. tH...... . . ....tH ...Ht... .tH....t . H..... ........ . .. .... .. tH .. .. ... . .........tH.. .tH....t ....tH.. ..tH .. .... .. tH .. .tH..... H . .....t ..Ht....  ## Ruby See: Wireworld/Ruby ## Rust use std::str::FromStr; #[derive(Debug, Copy, Clone, PartialEq)] pub enum State { Empty, Conductor, ElectronTail, ElectronHead, } impl State { fn next(&self, e_nearby: usize) -> State { match self { State::Empty => State::Empty, State::Conductor => { if e_nearby == 1 || e_nearby == 2 { State::ElectronHead } else { State::Conductor } } State::ElectronTail => State::Conductor, State::ElectronHead => State::ElectronTail, } } } #[derive(Debug, Clone, PartialEq)] pub struct WireWorld { pub width: usize, pub height: usize, pub data: Vec<State>, } impl WireWorld { pub fn new(width: usize, height: usize) -> Self { WireWorld { width, height, data: vec![State::Empty; width * height], } } pub fn get(&self, x: usize, y: usize) -> Option<State> { if x >= self.width || y >= self.height { None } else { self.data.get(y * self.width + x).copied() } } pub fn set(&mut self, x: usize, y: usize, state: State) { self.data[y * self.width + x] = state; } fn neighbors<F>(&self, x: usize, y: usize, mut f: F) -> usize where F: FnMut(State) -> bool { let (x, y) = (x as i32, y as i32); let neighbors = [(x-1,y-1),(x-1,y),(x-1,y+1),(x,y-1),(x,y+1),(x+1,y-1),(x+1,y),(x+1,y+1)]; neighbors.iter().filter_map(|&(x, y)| self.get(x as usize, y as usize)).filter(|&s| f(s)).count() } pub fn next(&mut self) { let mut next_state = vec![]; for y in 0..self.height { for x in 0..self.width { let e_count = self.neighbors(x, y, |e| e == State::ElectronHead); next_state.push(self.get(x, y).unwrap().next(e_count)); } } self.data = next_state; } } impl FromStr for WireWorld { type Err = (); fn from_str(s: &str) -> Result<WireWorld, ()> { let s = s.trim(); let height = s.lines().count(); let width = s.lines().map(|l| l.trim_end().len()).max().unwrap_or(0); let mut world = WireWorld::new(width, height); for (y, line) in s.lines().enumerate() { for (x, ch) in line.trim_end().chars().enumerate() { let state = match ch { '.' => State::Conductor, 't' => State::ElectronTail, 'H' => State::ElectronHead, _ => State::Empty, }; world.set(x, y, state); } } Ok(world) } }  graphical output using winit 0.24 and pixels 0.2 use pixels::{Pixels, SurfaceTexture}; use winit::event::*; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::WindowBuilder; use std::{env, fs}; mod wireworld; use wireworld::{State, WireWorld}; const EMPTY_COLOR: [u8; 3] = [0x00, 0x00, 0x00]; const WIRE_COLOR: [u8; 3] = [0xFC, 0xF9, 0xF8]; const HEAD_COLOR: [u8; 3] = [0xFC, 0x00, 0x00]; const TAIL_COLOR: [u8; 3] = [0xFC, 0x99, 0x33]; fn main() { let args: Vec<_> = env::args().collect(); if args.len() < 2 { eprintln!("Error: No Input File"); std::process::exit(1); } let input_file = fs::read_to_string(&args[1]).unwrap(); let mut world: WireWorld = input_file.parse().unwrap(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() .with_title(format!("Wireworld - {}", args[1])) .build(&event_loop).unwrap(); let size = window.inner_size(); let texture = SurfaceTexture::new(size.width, size.height, &window); let mut image_buffer = Pixels::new(world.width as u32, world.height as u32, texture).unwrap(); event_loop.run(move |ev, _, flow| { match ev { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { *flow = ControlFlow::Exit; } Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Space), .. }, .. }, .. } => { world.next(); window.request_redraw(); } Event::RedrawRequested(_) => { let frame = image_buffer.get_frame(); for (pixel, state) in frame.chunks_exact_mut(4).zip(world.data.iter()) { let color = match state { State::Empty => EMPTY_COLOR, State::Conductor => WIRE_COLOR, State::ElectronTail => TAIL_COLOR, State::ElectronHead => HEAD_COLOR, }; pixel[0] = color[0]; // R pixel[1] = color[1]; // G pixel[2] = color[2]; // B pixel[3] = 0xFF; // A } image_buffer.render().unwrap(); } _ => {} } }); }  ## Sidef Translation of: Perl var f = [[], DATA.lines.map {['', .chars..., '']}..., []] 10.times { say f.map { .join(" ") + "\n" }.join var a = [[]] for y in (1 ..^ f.end) { var r = f[y] var rr = [''] for x in (1 ..^ r.end) { var c = r[x] rr << ( given(c) { when('H') { 't' } when('t') { '.' } when('.') { <. H>[[f[y-1 .. y+1]].map{.[x-1 .. x+1]}.count('H') ~~ [1,2]] } default { c } } ) } rr << '' a << rr } f = [a..., []] } __DATA__ tH......... . . ... . . Ht.. ......  ## Smalltalk ## Standard ML (* Maximilian Wuttke 12.04.2016 *) type world = char vector vector fun getstate (w:world, (x, y)) = (Vector.sub (Vector.sub (w, y), x)) handle Subscript => #" " fun conductor (w:world, (x, y)) = let val s = [getstate (w, (x-1, y-1)) = #"H", getstate (w, (x-1, y)) = #"H", getstate (w, (x-1, y+1)) = #"H", getstate (w, (x, y-1)) = #"H", getstate (w, (x, y+1)) = #"H", getstate (w, (x+1, y-1)) = #"H", getstate (w, (x+1, y)) = #"H", getstate (w, (x+1, y+1)) = #"H"] (* Count true in s *) val count = List.length (List.filter (fn x => x=true) s) in if count = 1 orelse count = 2 then #"H" else #"." end fun translate (w:world, (x, y)) = case getstate (w, (x, y)) of #" " => #" " | #"H" => #"t" | #"t" => #"." | #"." => conductor (w, (x, y)) | s => s fun next_world (w : world) = Vector.mapi (fn (y, row) => Vector.mapi (fn (x, _) => translate (w, (x, y))) row) w (* Test *) (* makes a list of strings into a world *) fun make_world (rows : string list) : world = Vector.fromList (map (fn (row : string) => Vector.fromList (explode row)) rows) (* word_str reverses make_world *) fun vec_str (r:char vector) = implode (List.tabulate (Vector.length r, fn x => Vector.sub (r, x))) fun world_str (w:world) = List.tabulate (Vector.length w, fn y => vec_str (Vector.sub (w, y))) fun print_world (w:world) = (map (fn row_str => print (row_str ^ "\n")) (world_str w); ()) val test = make_world [ "tH.........", ". . ", " ... ", ". . ", "Ht.. ......"]  ## Tcl See: Wireworld/Tcl ## Ursala The board is represented as a list of character strings, and the neighborhoods function uses the swin library function twice to construct a two dimensional 3 by 3 sliding window. The rule function maps a pair (cell,neighborhood) to a new cell. #import std rule = case~&l\~&l {H: t!, t: .!,.: @r ==H*~; {'H','HH'}?</H! .!} neighborhoods = ~&thth3hthhttPCPthPTPTX**K7S+ swin3**+ swin3@hNSPiCihNCT+ --<0>*+ 0-* evolve "n" = @iNC ~&x+ rep"n" ^C\~& rule**+ neighborhoods@h test program: diode = < ' .. ', 'tH....... .Ht', ' .. '> #show+ example = mat0 evolve13 diode Output:  .. tH....... .Ht .. .. .tH...... Ht. .. .H ..tH..... t.. .H Ht ...tH...H ... Ht t. ....tH..t ... t. .. .....tH.. ... .. .. ......tH. ... .. H. .......tH ... H. tH ........t ... tH .t ......... H.. .t .. ......... tH. .. .. ......... .tH .. .. ......... ..t .. .. ......... ... ..  ## Wren Translation of: Go Library: wren-fmt Library: Wren-ioutil import "./fmt" for Fmt import "./ioutil" for FileUtil, Stdin var rows = 0 // extent of input configuration var cols = 0 // """ var rx = 0 // grid extent (includes border) var cx = 0 // """ var mn = [] // offsets of Moore neighborhood var print = Fn.new { |grid| System.print("__" * cols) System.print() for (r in 1..rows) { for (c in 1..cols) Fmt.write("$s", grid[r*cx+c])
System.print()
}
}

var step = Fn.new { |dst, src|
for (r in 1..rows) {
for (c in 1..cols) {
var x = r*cx + c
dst[x] = src[x]
if (dst[x] == "H") {
dst[x] = "t"
} else if (dst[x] == "t") {
dst[x] = "."
} else if (dst[x] == ".") {
var nn = 0
for (n in mn) {
if (src[x+n] == "H") nn = nn + 1
}
if (nn == 1 || nn == 2) dst[x] = "H"
}
}
}
}

rows = srcRows.count
for (r in srcRows) {
if (r.count > cols) cols = r.count
}
rx = rows + 2
cx = cols + 2
mn = [-cx-1, -cx, -cx+1, -1, 1, cx-1, cx, cx+1]

// allocate two grids and copy input into first grid
var odd  = List.filled(rx*cx, " ")
var even = List.filled(rx*cx, " ")

var ri = 0
for (r in srcRows) {
for (i in 0...r.count) {
odd[(ri+1)*cx+1+i] = r[i]
}
ri = ri + 1
}

// run
while (true) {
print.call(odd)
step.call(even, odd)
Stdin.readLine() // wait for enter to be pressed

print.call(even)
step.call(odd, even)
}

Output:
Although not shown, same as Go output.


## XPL0

include c:\cxpl\codes;          \intrinsic 'code' declarations
char New(53,40), Old(53,40);

proc Block(X0, Y0, C);          \Display a colored block
int  X0, Y0, C;                 \big (6x5) coordinates, char
int  X, Y;
[case C of                      \convert char to color
^H:   C:= $9; \blue ^t: C:=$C;                 \red
^.:   C:= $E \yellow other C:= 0; \black for Y:= Y0*5 to Y0*5+4 do \make square blocks by correcting aspect ratio for X:= X0*6 to X0*6+5 do \ (6x5 = square) Point(X,Y,C); ]; int X, Y, C; [SetVid($13);                   \set 320x200 graphics display
for Y:= 0 to 40-1 do            \initialize New with space (empty) characters
for X:= 0 to 53-1 do
New(X, Y):= ^ ;
X:= 1;  Y:= 1;                  \read file from command line, skipping borders
loop    [C:= ChIn(1);
case C of
$0D: X:= 1; \carriage return$0A:  Y:= Y+1;        \line feed
$1A: quit \end of file other [New(X,Y):= C; X:= X+1]; ]; repeat C:= Old; Old:= New; New:= C; \swap arrays, by swapping their pointers for Y:= 1 to 39-1 do \generate New array from Old for X:= 1 to 52-1 do \ (skipping borders) [case Old(X,Y) of ^ : New(X,Y):= ^ ; \copy empty to empty ^H: New(X,Y):= ^t; \convert head to tail ^t: New(X,Y):= ^. \convert tail to conductor other [C:= (Old(X-1,Y-1)=^H) + (Old(X+0,Y-1)=^H) + \head count (Old(X+1,Y-1)=^H) + (Old(X-1,Y+0)=^H) + \ in neigh- (Old(X+1,Y+0)=^H) + (Old(X-1,Y+1)=^H) + \ boring (Old(X+0,Y+1)=^H) + (Old(X+1,Y+1)=^H); \ cells New(X,Y):= if C=-1 or C=-2 then ^H else ^.; \ (true=-1) ]; Block(X, Y, New(X,Y)); \display result ]; Sound(0, 6, 1); \delay about 1/3 second until KeyHit; \keystroke terminates program SetVid(3); \restore normal text mode ] ## Yabasic open window 230,130 backcolor 0,0,0 clear window label circuit DATA " " DATA " tH......... " DATA " . . " DATA " ... " DATA " . . " DATA " Ht.. ...... " DATA " " DATA "" do read a$
if a$= "" break n = n + 1 redim t$(n)
t$(n) = a$+a$loop size = len(t$(1))/2
E2 = size
first = true
Orig = 0
Dest = E2

do
for y = 2 to n-1
for x = 2 to E2-1
switch mid$(t$(y),x+Orig,1)
case " ": color 32,32,32 : mid$(t$(y),x+Dest,1) = " " : break
case "H": color 0,0,255 : mid$(t$(y),x+Dest,1) = "t" : break
case "t": color 255,0,0 : mid$(t$(y),x+Dest,1) = "." : break
case ".":
color 255,200,0
t = 0
for y1 = y-1 to y+1
for x1 = x-1 to x+1
t = t + ("H" = mid$(t$(y1),x1+Orig,1))
next x1
next y1
if t=1 or t=2 then
mid$(t$(y),x+Dest,1) = "H"
else
mid$(t$(y),x+Dest,1) = "."
end if
end switch
fill circle x*16, y*16, 8
next x
print t\$(y),"="
next y
first = not first
if first then
Orig = 0 : Dest = E2
else
Orig = E2 : Dest = 0
end if
wait .5
loop