Pristine Ack-5.5
[Ack-5.5.git] / lang / occam / test / lifegame.ocm
1 def otherwise=true:
2
3 def dead=0, alive= not dead:
4
5 def radius=1,
6     diameter= (2*radius)+1,
7     neighbours= (diameter*diameter)-1:
8
9 proc calculate.next.state(chan link[], value in[], state, var next.state)=
10     var count:
11     seq
12         var state.of.neighbour[neighbours]:
13         seq
14             par i=[0 for neighbours]
15                 link[in[i]] ? state.of.neighbour[i]
16             count:=0
17             seq i=[0 for neighbours]
18                 if
19                     state.of.neighbour[i]=alive
20                         count:=count+1
21                     state.of.neighbour[i]=dead
22                         skip
23             if
24                 count<2
25                     next.state:=dead
26                 count=2
27                     next.state:=state
28                 count=3
29                     next.state:=alive
30                 count>3
31                     next.state:=dead
32 :
33
34 proc broadcast.present.state(chan link[], value out[], state)=
35     par i=[0 for neighbours]
36         link[out[i]] ! state
37 :
38
39 def set.state=1, ask.state=2, terminate=3:
40
41 proc cell(chan link[], value in[], out[], chan control, sense)=
42     var state, instruction:
43     seq
44         state:=dead
45         control ? instruction
46         while instruction <> terminate
47             seq
48                 if
49                     instruction=set.state
50                         control ? state
51                     instruction=ask.state
52                         var next.state:
53                         seq
54                             par
55                                 broadcast.present.state(link, out, state)
56                                 seq
57                                     calculate.next.state(link, in, state,
58                                         next.state)
59                                     sense ! (state<>next.state); next.state
60
61                             state:=next.state
62
63                 control ? instruction
64 :
65
66 def array.width=5, array.height=5:
67 def number.of.cells=array.height*array.width,
68     number.of.links=neighbours*number.of.cells:
69
70 proc initialize(value x, y, var in[], out[])=
71     seq delta.x=[-radius for diameter]
72         seq delta.y=[-radius for diameter]
73             var direction:
74             seq
75                 direction:=delta.x+(diameter*delta.y)
76                 if
77                     direction<>0
78                         var index, process:
79                         seq
80                             process:=x+(array.width*y)
81                             index:=(neighbours+direction) \ (neighbours+1)
82                             out[index]:=index+(neighbours*process)
83
84                             process:=((x+delta.x+array.width) \ array.width) +
85                                 (array.width*
86                                 ((y+delta.y+array.height) \ array.height))
87                             index:=(neighbours-direction) \ (neighbours+1)
88                             in[index]:=index+(neighbours*process)
89                     direction=0
90                         skip
91 :
92
93 def control= not ((not 0)<<5), escape=control/\'[':
94
95 proc move.cursor(chan screen, value x, y)=
96     screen ! escape; '='; '*s'+y; '*s'+x
97 :
98
99 proc initialize.display(chan screen)=
100     screen ! control /\ 'Z'
101 :
102
103 proc clean.up.display(chan screen)=
104     move.cursor(screen, 0, array.height)
105 :
106
107 proc display.state(chan screen, value x, y, state)=
108     seq
109         move.cursor(screen, x, y)
110         if
111             state=alive
112                 screen ! '**'
113             state=dead
114                 screen ! '*s'
115 :
116
117 proc generation(chan screen, control[], sense[], var active)=
118     seq
119         seq  cell=[0 for number.of.cells]
120             control[cell] ! ask.state
121         active:=false
122         seq cell=[0 for number.of.cells]
123             var changed, next.state:
124             seq
125                 sense[cell] ? changed; next.state
126                 if
127                     changed
128                         seq
129                             display.state(screen, cell\array.width,
130                                 cell/array.width, next.state)
131                             active:=true
132                     not changed
133                         skip
134 :
135
136 proc edit(chan keyboard, screen, control[])=
137     def ctrl= not ((not 0)<<5):
138     def left.key= 'h',  right.key= 'l', up.key= 'k', down.key= 'j',
139         uproot.key= '*s', plant.key= '**', plant.key2= '8':
140     var x, y, editing, ch:
141     seq
142         x:=array.width/2
143         y:=array.height/2
144         editing:=true
145         while editing
146             seq
147                 move.cursor(screen, x, y)
148                 keyboard ? ch
149                 if
150                     (ch=left.key) and (x>0)
151                         x:=x-1
152                     (ch=right.key) and (x<(array.width-1))
153                         x:=x+1
154                     (ch=up.key) and (y>0)
155                         y:=y-1
156                     (ch=down.key) and (y<(array.height-1))
157                         y:=y+1
158                     (ch=uproot.key) or (ch=plant.key) or (ch=plant.key2)
159                         var state:
160                         seq
161                             state:=(dead /\ (ch=uproot.key)) \/
162                                 (alive /\ ((ch=plant.key) or (ch=plant.key2)))
163                             control[x+(array.width*y)] ! set.state; state
164                             display.state(screen, x, y, state)
165                     (ch='q') or (ch='Q')
166                         editing:=false
167                     otherwise
168                         skip
169 :
170
171 def idle=1, editing=2, single.stepping=3, free.running=4, terminated=5:
172
173 proc display.activity(chan screen, value activity)=
174     seq
175         move.cursor(screen, array.width+1, array.height+2)
176
177         proc write.string(value str[])=
178             seq i=[1 for str[byte 0]]
179                 screen ! str[byte i]
180         :
181         if
182             activity=idle
183                 write.string("Idle")
184             activity=editing
185                 write.string("Edit")
186             activity=single.stepping
187                 write.string("Step")
188             activity=free.running
189                 write.string("Busy")
190             activity=terminated
191                 write.string("Done")
192 :
193
194 proc controller(chan keyboard, screen, control[], sense[])=
195     var activity:
196     seq
197         activity:=idle
198         initialize.display(screen)
199         while activity<>terminated
200             seq
201                 display.activity(screen, activity)
202                 var ch:
203                 pri alt
204                     (activity <> editing) & keyboard ? ch
205                         if
206                             (ch='q') or (ch='Q')
207                                 activity:=terminated
208                             (ch='i') or (ch='I')
209                                 activity:=idle
210                             (ch='e') or (ch='E')
211                                 activity:=editing
212                             (ch='r') or (ch='R')
213                                 activity:=free.running
214                             (ch='s') or (ch='S')
215                                 activity:=single.stepping
216                     (activity=editing) & skip
217                         seq
218                             edit(keyboard, screen, control)
219                             activity:=idle
220                     (activity=free.running) or (activity=single.stepping) & skip
221                         var changing:
222                         seq
223                             generation(screen, control, sense, changing)
224                             if
225                                 (activity=single.stepping) or (not changing)
226                                     activity:=idle
227                                 (activity=free.running) and changing
228                                     skip
229         display.activity(screen, activity)
230         seq cell=[0 for number.of.cells]
231             control[cell] ! terminate
232         clean.up.display(screen)
233 :
234
235 chan link[number.of.links], control[number.of.cells], sense[number.of.cells]:
236 seq
237     output ! RAW
238     par
239         controller(input, output, control, sense)
240
241         par x=[0 for array.width]
242             par y=[0 for array.height]
243                 var in[neighbours], out[neighbours]:
244                 seq
245                     initialize(x, y, in, out)
246                     cell(link, in, out, control[x+(array.width*y)],
247                         sense[x+(array.width*y)])
248     output ! TEXT