def otherwise=true:

def dead=0, alive= not dead:

def radius=1,
    diameter= (2*radius)+1,
    neighbours= (diameter*diameter)-1:

proc calculate.next.state(chan link[], value in[], state, var next.state)=
    var count:
    seq
	var state.of.neighbour[neighbours]:
	seq
	    par i=[0 for neighbours]
		link[in[i]] ? state.of.neighbour[i]
	    count:=0
	    seq i=[0 for neighbours]
		if
		    state.of.neighbour[i]=alive
			count:=count+1
		    state.of.neighbour[i]=dead
			skip
	    if
		count<2
		    next.state:=dead
		count=2
		    next.state:=state
		count=3
		    next.state:=alive
		count>3
		    next.state:=dead
:

proc broadcast.present.state(chan link[], value out[], state)=
    par i=[0 for neighbours]
	link[out[i]] ! state
:

def set.state=1, ask.state=2, terminate=3:

proc cell(chan link[], value in[], out[], chan control, sense)=
    var state, instruction:
    seq
	state:=dead
	control ? instruction
	while instruction <> terminate
	    seq
		if
		    instruction=set.state
			control ? state
		    instruction=ask.state
			var next.state:
			seq
			    par
				broadcast.present.state(link, out, state)
				seq
				    calculate.next.state(link, in, state,
					next.state)
				    sense ! (state<>next.state); next.state

			    state:=next.state

		control ? instruction
:

def array.width=5, array.height=5:
def number.of.cells=array.height*array.width,
    number.of.links=neighbours*number.of.cells:

proc initialize(value x, y, var in[], out[])=
    seq delta.x=[-radius for diameter]
	seq delta.y=[-radius for diameter]
	    var direction:
	    seq
		direction:=delta.x+(diameter*delta.y)
		if
		    direction<>0
			var index, process:
			seq
			    process:=x+(array.width*y)
			    index:=(neighbours+direction) \ (neighbours+1)
			    out[index]:=index+(neighbours*process)

			    process:=((x+delta.x+array.width) \ array.width) +
				(array.width*
				((y+delta.y+array.height) \ array.height))
			    index:=(neighbours-direction) \ (neighbours+1)
			    in[index]:=index+(neighbours*process)
		    direction=0
			skip
:

def control= not ((not 0)<<5), escape=control/\'[':

proc move.cursor(chan screen, value x, y)=
    screen ! escape; '='; '*s'+y; '*s'+x
:

proc initialize.display(chan screen)=
    screen ! control /\ 'Z'
:

proc clean.up.display(chan screen)=
    move.cursor(screen, 0, array.height)
:

proc display.state(chan screen, value x, y, state)=
    seq
	move.cursor(screen, x, y)
	if
	    state=alive
		screen ! '**'
	    state=dead
		screen ! '*s'
:

proc generation(chan screen, control[], sense[], var active)=
    seq
	seq  cell=[0 for number.of.cells]
	    control[cell] ! ask.state
	active:=false
	seq cell=[0 for number.of.cells]
	    var changed, next.state:
	    seq
		sense[cell] ? changed; next.state
		if
		    changed
			seq
			    display.state(screen, cell\array.width,
				cell/array.width, next.state)
			    active:=true
		    not changed
			skip
:

proc edit(chan keyboard, screen, control[])=
    def ctrl= not ((not 0)<<5):
    def left.key= 'h',	right.key= 'l', up.key= 'k', down.key= 'j',
	uproot.key= '*s', plant.key= '**', plant.key2= '8':
    var x, y, editing, ch:
    seq
	x:=array.width/2
	y:=array.height/2
	editing:=true
	while editing
	    seq
		move.cursor(screen, x, y)
		keyboard ? ch
		if
		    (ch=left.key) and (x>0)
			x:=x-1
		    (ch=right.key) and (x<(array.width-1))
			x:=x+1
		    (ch=up.key) and (y>0)
			y:=y-1
		    (ch=down.key) and (y<(array.height-1))
			y:=y+1
		    (ch=uproot.key) or (ch=plant.key) or (ch=plant.key2)
			var state:
			seq
			    state:=(dead /\ (ch=uproot.key)) \/
				(alive /\ ((ch=plant.key) or (ch=plant.key2)))
			    control[x+(array.width*y)] ! set.state; state
			    display.state(screen, x, y, state)
		    (ch='q') or (ch='Q')
			editing:=false
		    otherwise
			skip
:

def idle=1, editing=2, single.stepping=3, free.running=4, terminated=5:

proc display.activity(chan screen, value activity)=
    seq
	move.cursor(screen, array.width+1, array.height+2)

	proc write.string(value str[])=
	    seq i=[1 for str[byte 0]]
		screen ! str[byte i]
	:
	if
	    activity=idle
		write.string("Idle")
	    activity=editing
		write.string("Edit")
	    activity=single.stepping
		write.string("Step")
	    activity=free.running
		write.string("Busy")
	    activity=terminated
		write.string("Done")
:

proc controller(chan keyboard, screen, control[], sense[])=
    var activity:
    seq
	activity:=idle
	initialize.display(screen)
	while activity<>terminated
	    seq
		display.activity(screen, activity)
		var ch:
		pri alt
		    (activity <> editing) & keyboard ? ch
			if
			    (ch='q') or (ch='Q')
				activity:=terminated
			    (ch='i') or (ch='I')
				activity:=idle
			    (ch='e') or (ch='E')
				activity:=editing
			    (ch='r') or (ch='R')
				activity:=free.running
			    (ch='s') or (ch='S')
				activity:=single.stepping
		    (activity=editing) & skip
			seq
			    edit(keyboard, screen, control)
			    activity:=idle
		    (activity=free.running) or (activity=single.stepping) & skip
			var changing:
			seq
			    generation(screen, control, sense, changing)
			    if
				(activity=single.stepping) or (not changing)
				    activity:=idle
				(activity=free.running) and changing
				    skip
	display.activity(screen, activity)
	seq cell=[0 for number.of.cells]
	    control[cell] ! terminate
	clean.up.display(screen)
:

chan link[number.of.links], control[number.of.cells], sense[number.of.cells]:
seq
    output ! RAW
    par
	controller(input, output, control, sense)

	par x=[0 for array.width]
	    par y=[0 for array.height]
		var in[neighbours], out[neighbours]:
		seq
		    initialize(x, y, in, out)
		    cell(link, in, out, control[x+(array.width*y)],
			sense[x+(array.width*y)])
    output ! TEXT
