git @ Cat's Eye Technologies Jaccia / 4b3c4fc
Compile CA definitions to JS, add HTML demos using yoob.js. catseye 7 years ago
6 changed file(s) with 796 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 <!DOCTYPE html>
1 <head>
2 <meta charset="utf-8">
3 <title>Jaccia Demo</title>
4 </head>
5 <body>
6
7 <h1>Jaccia Demo</h1>
8
9 <textarea id="input" rows="10">
10 ########S##
11 #%%%%%%%%%#
12 #%###%###%#
13 #%#%#%%%#%#
14 #%#%#%#%###
15 #%%%#%#%#%#
16 #####%#%#%#
17 #%#%%%#%%%#
18 #%#%###%###
19 #%%%#%%%%%#
20 #########F#
21 </textarea>
22
23 <pre id="output" style="border: 1px solid blue">
24 </pre>
25
26 <button id="start">Start</button>
27 <button id="stop">Stop</button>
28 <button id="step">Step</button>
29 <button id="load">Load</button>
30 Speed: <input id="speed" type="range" min="0" max="200" value="0" />
31
32 </body>
33 <script src="yoob/controller.js"></script>
34 <script src="yoob/playfield.js"></script>
35 <script src="../script/jaccia.js"></script>
36 <script>
37 var output = document.getElementById('output');
38 var c = new yoob.Controller();
39 var pf;
40
41 c.load = function(text) {
42 pf = new yoob.Playfield();
43 pf.setDefault('Space');
44 pf.load(0, 0, text, loadMapper);
45 output.innerHTML = pf.dump(dumpMapper);
46 };
47
48 c.step = function() {
49 var newPf = new yoob.Playfield();
50 newPf.setDefault('Space');
51 evolve_playfield(pf, newPf);
52 pf = newPf;
53 output.innerHTML = pf.dump(dumpMapper);
54 };
55
56 c.connect({
57 'start': 'start',
58 'stop': 'stop',
59 'step': 'step',
60 'load': 'load',
61 'source': 'input',
62 'speed': 'speed'
63 });
64 </script>
0 <!DOCTYPE html>
1 <head>
2 <meta charset="utf-8">
3 <title>Jacciata Demo</title>
4 </head>
5 <body>
6
7 <h1>Jacciata Demo</h1>
8
9 <textarea id="input" rows="10">
10 ####S####
11 #%%%%%%%#
12 #%#####%#
13 #%#%%%#%#
14 #%#%#%#%#
15 #%%%#%%%#
16 ##F######
17 </textarea>
18
19 <pre id="output" style="border: 1px solid blue">
20 </pre>
21
22 <button id="start">Start</button>
23 <button id="stop">Stop</button>
24 <button id="step">Step</button>
25 <button id="load">Load</button>
26 Speed: <input id="speed" type="range" min="0" max="200" value="0" />
27
28 </body>
29 <script src="yoob/controller.js"></script>
30 <script src="yoob/playfield.js"></script>
31 <script src="../script/jacciata.js"></script>
32 <script>
33 var output = document.getElementById('output');
34 var c = new yoob.Controller();
35 var pf;
36
37 c.load = function(text) {
38 pf = new yoob.Playfield();
39 pf.setDefault('Space');
40 pf.load(0, 0, text, loadMapper);
41 output.innerHTML = pf.dump(dumpMapper);
42 };
43
44 c.step = function() {
45 var newPf = new yoob.Playfield();
46 newPf.setDefault('Space');
47 evolve_playfield(pf, newPf);
48 pf = newPf;
49 output.innerHTML = pf.dump(dumpMapper);
50 };
51
52 c.connect({
53 'start': 'start',
54 'stop': 'stop',
55 'step': 'step',
56 'load': 'load',
57 'source': 'input',
58 'speed': 'speed'
59 });
60 </script>
0 /*
1 * This file is part of yoob.js version 0.2-PRE
2 * This file is in the public domain. See http://unlicense.org/ for details.
3 */
4 if (window.yoob === undefined) yoob = {};
5
6 /*
7 * A controller for executing(/animating/evolving) states
8 * (such as esolang program states or cellular automaton
9 * configurations.)
10 *
11 * Can be connected to a UI in the DOM.
12 *
13 * Subclass this and override the following methods:
14 * - make it evolve the state by one tick in the step() method
15 * - make it load the state from a multiline string in the load() method
16 */
17 yoob.Controller = function() {
18 this.intervalId = undefined;
19 this.delay = 100;
20 this.source = undefined;
21 this.speed = undefined;
22
23 var makeOnClick = function(controller, key) {
24 if (controller['click_' + key] !== undefined)
25 key = 'click_' + key;
26 return function(e) { controller[key](); }
27 };
28
29 /*
30 * Single argument is a dictionary (object) where the keys
31 * are the actions a controller can undertake, and the values
32 * are either DOM elements or strings; if strings, DOM elements
33 * with those ids will be obtained from the document and used.
34 */
35 this.connect = function(dict) {
36 var self = this;
37 var keys = ["start", "stop", "step", "load"];
38 for (var i in keys) {
39 var key = keys[i];
40 var value = dict[key];
41 if (typeof value === 'string') {
42 value = document.getElementById(value);
43 }
44 if (value !== undefined) {
45 value.onclick = makeOnClick(this, key);
46 }
47 }
48
49 var source = dict.source;
50 if (typeof source === 'string') {
51 source = document.getElementById(source);
52 }
53 if (source !== undefined) {
54 this.source = source;
55 }
56
57 var speed = dict.speed;
58 if (typeof speed === 'string') {
59 speed = document.getElementById(speed);
60 }
61 if (speed !== undefined) {
62 this.speed = speed;
63 speed.value = self.delay;
64 speed.onchange = function(e) {
65 self.delay = speed.value;
66 if (self.intervalId !== undefined) {
67 self.stop();
68 self.start();
69 }
70 }
71 }
72 };
73
74 this.click_step = function(e) {
75 this.stop();
76 this.step();
77 };
78
79 this.step = function() {
80 alert("step() NotImplementedError");
81 };
82
83 this.click_load = function(e) {
84 this.stop();
85 this.load(this.source.value);
86 };
87
88 this.load = function(text) {
89 alert("load() NotImplementedError");
90 };
91
92 this.start = function() {
93 if (this.intervalId !== undefined)
94 return;
95 this.step();
96 var self = this;
97 this.intervalId = setInterval(function() { self.step(); }, this.delay);
98 };
99
100 this.stop = function() {
101 if (this.intervalId === undefined)
102 return;
103 clearInterval(this.intervalId);
104 this.intervalId = undefined;
105 };
106 };
0 /*
1 * This file is part of yoob.js version 0.2
2 * This file is in the public domain. See http://unlicense.org/ for details.
3 */
4 if (window.yoob === undefined) yoob = {};
5
6 /*
7 * A two-dimensional Cartesian grid of values.
8 */
9 yoob.Playfield = function() {
10 this._store = {};
11 this.minX = undefined;
12 this.minY = undefined;
13 this.maxX = undefined;
14 this.maxY = undefined;
15 this._default = undefined;
16
17 /*
18 * Set the default value for this Playfield. This
19 * value is returned by get() for any cell that was
20 * never written to, or had `undefined` put() into it.
21 */
22 this.setDefault = function(v) {
23 this._default = v;
24 };
25
26 /*
27 * Obtain the value at (x, y). The default value will
28 * be returned if the cell was never written to.
29 */
30 this.get = function(x, y) {
31 var v = this._store[x+','+y];
32 if (v === undefined) return this._default;
33 return v;
34 };
35
36 /*
37 * Write a new value into (x, y). Note that writing
38 * `undefined` into a cell has the semantics of deleting
39 * the value at that cell; a subsequent get() for that
40 * location will return this Playfield's default value.
41 */
42 this.put = function(x, y, value) {
43 var key = x+','+y;
44 if (value === undefined || value === this._default) {
45 delete this._store[key];
46 return;
47 }
48 if (this.minX === undefined || x < this.minX) this.minX = x;
49 if (this.maxX === undefined || x > this.maxX) this.maxX = x;
50 if (this.minY === undefined || y < this.minY) this.minY = y;
51 if (this.maxY === undefined || y > this.maxY) this.maxY = y;
52 this._store[key] = value;
53 };
54
55 /*
56 * Like put(), but does not update the playfield bounds. Do
57 * this if you must do a batch of put()s in a more efficient
58 * manner; after doing so, call recalculateBounds().
59 */
60 this.putDirty = function(x, y, value) {
61 var key = x+','+y;
62 if (value === undefined || value === this._default) {
63 delete this._store[key];
64 return;
65 }
66 this._store[key] = value;
67 };
68
69 /*
70 * Recalculate the bounds (min/max X/Y) which are tracked
71 * internally to support methods like foreach(). This is
72 * not needed *unless* you've used putDirty() at some point.
73 * (In which case, call this immediately after your batch
74 * of putDirty()s.)
75 */
76 this.recalculateBounds = function() {
77 this.minX = undefined;
78 this.minY = undefined;
79 this.maxX = undefined;
80 this.maxX = undefined;
81
82 for (var cell in this._store) {
83 var pos = cell.split(',');
84 var x = parseInt(pos[0], 10);
85 var y = parseInt(pos[1], 10);
86 if (this.minX === undefined || x < this.minX) this.minX = x;
87 if (this.maxX === undefined || x > this.maxX) this.maxX = x;
88 if (this.minY === undefined || y < this.minY) this.minY = y;
89 if (this.maxY === undefined || y > this.maxY) this.maxY = y;
90 }
91 };
92
93 /*
94 * Clear the contents of this Playfield.
95 */
96 this.clear = function() {
97 this._store = {};
98 this.minX = undefined;
99 this.minY = undefined;
100 this.maxX = undefined;
101 this.maxX = undefined;
102 };
103
104 /*
105 * Load a string into this Playfield.
106 * The string may be multiline, with newline (ASCII 10)
107 * characters delimiting lines. ASCII 13 is ignored.
108 *
109 * If transformer is given, it should be a one-argument
110 * function which accepts a character and returns the
111 * object you wish to write into the playfield upon reading
112 * that character.
113 */
114 this.load = function(x, y, string, transformer) {
115 var lx = x;
116 var ly = y;
117 if (transformer === undefined) {
118 transformer = function(c) {
119 if (c === ' ') {
120 return undefined;
121 } else {
122 return c;
123 }
124 }
125 }
126 for (var i = 0; i < string.length; i++) {
127 var c = string.charAt(i);
128 if (c === '\n') {
129 lx = x;
130 ly++;
131 } else if (c === '\r') {
132 } else {
133 this.putDirty(lx, ly, transformer(c));
134 lx++;
135 }
136 }
137 this.recalculateBounds();
138 };
139
140 /*
141 * Convert this Playfield to a multi-line string. Each row
142 * is a line, delimited with a newline (ASCII 10).
143 *
144 * If transformer is given, it should be a one-argument
145 * function which accepts a playfield element and returns a
146 * character (or string) you wish to place in the resulting
147 * string for that element.
148 */
149 this.dump = function(transformer) {
150 var text = "";
151 if (transformer === undefined) {
152 transformer = function(c) { return c; }
153 }
154 for (var y = this.minY; y <= this.maxY; y++) {
155 var row = "";
156 for (var x = this.minX; x <= this.maxX; x++) {
157 row += transformer(this.get(x, y));
158 }
159 text += row + "\n";
160 }
161 return text;
162 };
163
164 /*
165 * Iterate over every defined cell in the Playfield.
166 * fun is a callback which takes three parameters:
167 * x, y, and value. If this callback returns a value,
168 * it is written into the Playfield at that position.
169 * This function ensures a particular order.
170 */
171 this.foreach = function(fun) {
172 for (var y = this.minY; y <= this.maxY; y++) {
173 for (var x = this.minX; x <= this.maxX; x++) {
174 var key = x+','+y;
175 var value = this._store[key];
176 if (value === undefined)
177 continue;
178 var result = fun(x, y, value);
179 if (result !== undefined) {
180 if (result === ' ') {
181 result = undefined;
182 }
183 this.put(x, y, result);
184 }
185 }
186 }
187 };
188
189 /*
190 * Analogous to (monoid) map in functional languages,
191 * iterate over this Playfield, transform each value using
192 * a supplied function, and write the transformed value into
193 * a destination Playfield.
194 *
195 * Supplied function should take a Playfield (this Playfield),
196 * x, and y, and return a value.
197 *
198 * The map source may extend beyond the internal bounds of
199 * the Playfield, by giving the min/max Dx/Dy arguments
200 * (which work like margin offsets.)
201 *
202 * Useful for evolving a cellular automaton playfield. In this
203 * case, min/max Dx/Dy should be computed from the neighbourhood.
204 */
205 this.map = function(destPf, fun, minDx, minDy, maxDx, maxDy) {
206 if (minDx === undefined) minDx = 0;
207 if (minDy === undefined) minDy = 0;
208 if (maxDx === undefined) maxDx = 0;
209 if (maxDy === undefined) maxDy = 0;
210 for (var y = this.minY + minDy; y <= this.maxY + maxDy; y++) {
211 for (var x = this.minX + minDx; x <= this.maxX + maxDx; x++) {
212 destPf.putDirty(x, y, fun(pf, x, y));
213 }
214 }
215 destPf.recalculateBounds();
216 };
217
218 /*
219 * Draws elements of the Playfield in a drawing context.
220 * x and y are canvas coordinates, and width and height
221 * are canvas units of measure.
222 * The default implementation just renders them as text,
223 * in black.
224 * Override if you wish to draw them differently.
225 */
226 this.drawElement = function(ctx, x, y, cellWidth, cellHeight, elem) {
227 ctx.fillStyle = "black";
228 ctx.fillText(elem.toString(), x, y);
229 };
230
231 /*
232 * Draws the Playfield in a drawing context.
233 * cellWidth and cellHeight are canvas units of measure for each cell.
234 */
235 this.drawContext = function(ctx, offsetX, offsetY, cellWidth, cellHeight) {
236 var me = this;
237 this.foreach(function (x, y, elem) {
238 me.drawElement(ctx, offsetX + x * cellWidth, offsetY + y * cellHeight,
239 cellWidth, cellHeight, elem);
240 });
241 };
242
243 this.getExtentX = function() {
244 if (this.maxX === undefined || this.minX === undefined) {
245 return 0;
246 } else {
247 return this.maxX - this.minX + 1;
248 }
249 };
250
251 this.getExtentY = function() {
252 if (this.maxY === undefined || this.minY === undefined) {
253 return 0;
254 } else {
255 return this.maxY - this.minY + 1;
256 }
257 };
258
259 /*
260 * Draws the Playfield, and a set of Cursors, on a canvas element.
261 * Resizes the canvas to the needed dimensions.
262 * cellWidth and cellHeight are canvas units of measure for each cell.
263 */
264 this.drawCanvas = function(canvas, cellWidth, cellHeight, cursors) {
265 var ctx = canvas.getContext('2d');
266
267 var width = this.getExtentX();
268 var height = this.getExtentY();
269
270 if (cellWidth === undefined) {
271 ctx.textBaseline = "top";
272 ctx.font = cellHeight + "px monospace";
273 cellWidth = ctx.measureText("@").width;
274 }
275
276 canvas.width = width * cellWidth;
277 canvas.height = height * cellHeight;
278
279 ctx.clearRect(0, 0, canvas.width, canvas.height);
280
281 ctx.textBaseline = "top";
282 ctx.font = cellHeight + "px monospace";
283
284 var offsetX = this.minX * cellWidth * -1;
285 var offsetY = this.minY * cellHeight * -1;
286
287 for (var i = 0; i < cursors.length; i++) {
288 cursors[i].drawContext(
289 ctx,
290 cursors[i].x * cellWidth, cursors[i].y * cellHeight,
291 cellWidth, cellHeight
292 );
293 }
294
295 this.drawContext(ctx, offsetX, offsetY, cellWidth, cellHeight);
296 };
297
298 };
0 /*
1 * This file was AUTOMATICALLY generated from an ALPACA description.
2 * EDIT AT YOUR OWN RISK!
3 */
4
5
6 function in_nbhd_pred(pf, x, y, pred, nbhd) {
7 var count = 0;
8 for (var i = 0; i < nbhd.length; i++) {
9 if (pred(pf.get(x+nbhd[i][0], y+nbhd[i][1]))) {
10 count++;
11 }
12 }
13 return count;
14 }
15
16 function in_nbhd_eq(pf, x, y, stateId, nbhd) {
17 return in_nbhd_pred(pf, x, y, function(x) { return x === stateId; }, nbhd);
18 }
19
20 function evolve_playfield(pf, new_pf) {
21 pf.map(new_pf, evalState, -1, -1, 1, 1);
22 }
23 function loadMapper(c) {
24 if (c === ' ') return 'Space';
25 if (c === '#') return 'Wall';
26 if (c === '%') return 'Slime';
27 if (c === 'S') return 'Food2';
28 if (c === 'F') return 'Food';
29 };
30 function dumpMapper(s) {
31 if (s === 'Space') return ' ';
32 if (s === 'Wall') return '#';
33 if (s === 'Slime') return '%';
34 if (s === 'Food2') return 'S';
35 if (s === 'Food') return 'F';
36 };
37 function is_Sustainer(st) {
38 return (st === 'Food') || (st === 'Food2') || (st === 'Slime') || 0;
39 }
40
41 function evalClass_Sustainer(pf, x, y) {
42 var id;
43 return undefined;
44 }
45
46 function eval_Space(pf, x, y) {
47 var id;
48 return 'Space';
49 }
50
51 function eval_Wall(pf, x, y) {
52 var id;
53 return 'Wall';
54 }
55
56 function eval_Food(pf, x, y) {
57 var id;
58 id = evalClass_Sustainer(pf, x, y);
59 if (id !== undefined) return id;
60 return 'Food';
61 }
62
63 function eval_Food2(pf, x, y) {
64 var id;
65 id = evalClass_Sustainer(pf, x, y);
66 if (id !== undefined) return id;
67 return 'Food2';
68 }
69
70 function eval_Slime(pf, x, y) {
71 var id;
72 if (!((in_nbhd_pred(pf, x, y, is_Sustainer, [[0,-1],[0,1],[-1,0],[1,0]]) >= 2))) {
73 return 'Space';
74 }
75 id = evalClass_Sustainer(pf, x, y);
76 if (id !== undefined) return id;
77 return 'Slime';
78 }
79
80 function evalState(pf, x, y) {
81 var stateId = pf.get(x, y);
82 if (stateId === 'Space') return eval_Space(pf, x, y);
83 if (stateId === 'Wall') return eval_Wall(pf, x, y);
84 if (stateId === 'Food') return eval_Food(pf, x, y);
85 if (stateId === 'Food2') return eval_Food2(pf, x, y);
86 if (stateId === 'Slime') return eval_Slime(pf, x, y);
87 }
0 /*
1 * This file was AUTOMATICALLY generated from an ALPACA description.
2 * EDIT AT YOUR OWN RISK!
3 */
4
5
6 function in_nbhd_pred(pf, x, y, pred, nbhd) {
7 var count = 0;
8 for (var i = 0; i < nbhd.length; i++) {
9 if (pred(pf.get(x+nbhd[i][0], y+nbhd[i][1]))) {
10 count++;
11 }
12 }
13 return count;
14 }
15
16 function in_nbhd_eq(pf, x, y, stateId, nbhd) {
17 return in_nbhd_pred(pf, x, y, function(x) { return x === stateId; }, nbhd);
18 }
19
20 function evolve_playfield(pf, new_pf) {
21 pf.map(new_pf, evalState, -1, -1, 1, 1);
22 }
23 function loadMapper(c) {
24 if (c === ' ') return 'Space';
25 if (c === '#') return 'Wall';
26 if (c === '%') return 'Slime';
27 if (c === '@') return 'Solved';
28 if (c === 'F') return 'Finish';
29 if (c === '-') return 'Head';
30 if (c === 'S') return 'Start';
31 if (c === '?') return 'Body';
32 };
33 function dumpMapper(s) {
34 if (s === 'Space') return ' ';
35 if (s === 'Wall') return '#';
36 if (s === 'Slime') return '%';
37 if (s === 'Solved') return '@';
38 if (s === 'Finish') return 'F';
39 if (s === 'Head') return '-';
40 if (s === 'Start') return 'S';
41 if (s === 'Body') return '?';
42 };
43 function is_Sassy(st) {
44 return (st === 'Body') || (st === 'Solved') || (st === 'Head') || (st === 'Finish') || (st === 'Start') || 0;
45 }
46
47 function is_Solution(st) {
48 return (st === 'Solved') || (st === 'Finish') || 0;
49 }
50
51 function is_Starter(st) {
52 return (st === 'Body') || (st === 'Start') || (st === 'Head') || 0;
53 }
54
55 function is_Sustainer(st) {
56 return (st === 'Start') || (st === 'Head') || (st === 'Finish') || (st === 'Slime') || 0;
57 }
58
59 function evalClass_Starter(pf, x, y) {
60 var id;
61 return undefined;
62 }
63
64 function evalClass_Sustainer(pf, x, y) {
65 var id;
66 return undefined;
67 }
68
69 function evalClass_Sassy(pf, x, y) {
70 var id;
71 return undefined;
72 }
73
74 function evalClass_Solution(pf, x, y) {
75 var id;
76 return undefined;
77 }
78
79 function eval_Space(pf, x, y) {
80 var id;
81 return 'Space';
82 }
83
84 function eval_Wall(pf, x, y) {
85 var id;
86 return 'Wall';
87 }
88
89 function eval_Slime(pf, x, y) {
90 var id;
91 if ((!((in_nbhd_pred(pf, x, y, is_Sustainer, [[0,-1],[0,1],[-1,0],[1,0]]) >= 2))||(in_nbhd_eq(pf, x, y, 'Head', [[0,-1],[0,1],[-1,0],[1,0]]) >= 2))) {
92 return 'Space';
93 }
94 if ((in_nbhd_pred(pf, x, y, is_Starter, [[0,-1],[0,1],[-1,0],[1,0]]) >= 1)) {
95 return 'Head';
96 }
97 id = evalClass_Sustainer(pf, x, y);
98 if (id !== undefined) return id;
99 return 'Slime';
100 }
101
102 function eval_Head(pf, x, y) {
103 var id;
104 if (true) {
105 return 'Body';
106 }
107 id = evalClass_Starter(pf, x, y);
108 if (id !== undefined) return id;
109 id = evalClass_Sustainer(pf, x, y);
110 if (id !== undefined) return id;
111 id = evalClass_Sassy(pf, x, y);
112 if (id !== undefined) return id;
113 return 'Head';
114 }
115
116 function eval_Body(pf, x, y) {
117 var id;
118 if ((in_nbhd_pred(pf, x, y, is_Solution, [[0,-1],[0,1],[-1,0],[1,0]]) >= 1)) {
119 return 'Solved';
120 }
121 if (!((in_nbhd_pred(pf, x, y, is_Sassy, [[0,-1],[0,1],[-1,0],[1,0]]) >= 2))) {
122 return 'Space';
123 }
124 id = evalClass_Starter(pf, x, y);
125 if (id !== undefined) return id;
126 id = evalClass_Sassy(pf, x, y);
127 if (id !== undefined) return id;
128 return 'Body';
129 }
130
131 function eval_Solved(pf, x, y) {
132 var id;
133 if (!((in_nbhd_pred(pf, x, y, is_Sassy, [[0,-1],[0,1],[-1,0],[1,0]]) >= 2))) {
134 return 'Space';
135 }
136 id = evalClass_Sassy(pf, x, y);
137 if (id !== undefined) return id;
138 id = evalClass_Solution(pf, x, y);
139 if (id !== undefined) return id;
140 return 'Solved';
141 }
142
143 function eval_Start(pf, x, y) {
144 var id;
145 id = evalClass_Starter(pf, x, y);
146 if (id !== undefined) return id;
147 id = evalClass_Sustainer(pf, x, y);
148 if (id !== undefined) return id;
149 id = evalClass_Sassy(pf, x, y);
150 if (id !== undefined) return id;
151 return 'Start';
152 }
153
154 function eval_Finish(pf, x, y) {
155 var id;
156 id = evalClass_Sustainer(pf, x, y);
157 if (id !== undefined) return id;
158 id = evalClass_Sassy(pf, x, y);
159 if (id !== undefined) return id;
160 id = evalClass_Solution(pf, x, y);
161 if (id !== undefined) return id;
162 return 'Finish';
163 }
164
165 function evalState(pf, x, y) {
166 var stateId = pf.get(x, y);
167 if (stateId === 'Space') return eval_Space(pf, x, y);
168 if (stateId === 'Wall') return eval_Wall(pf, x, y);
169 if (stateId === 'Slime') return eval_Slime(pf, x, y);
170 if (stateId === 'Head') return eval_Head(pf, x, y);
171 if (stateId === 'Body') return eval_Body(pf, x, y);
172 if (stateId === 'Solved') return eval_Solved(pf, x, y);
173 if (stateId === 'Start') return eval_Start(pf, x, y);
174 if (stateId === 'Finish') return eval_Finish(pf, x, y);
175 }