|
@@ -0,0 +1,248 @@
|
|
|
+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
|