Generate JS with alpaca, add demo in HTML using yoob.js.
catseye
12 years ago
0 | <!DOCTYPE html> | |
1 | <head> | |
2 | <meta charset="utf-8"> | |
3 | <title>REDGREEN Demo</title> | |
4 | </head> | |
5 | <body> | |
6 | ||
7 | <h1>REDGREEN Demo</h1> | |
8 | ||
9 | <textarea id="input" rows="20" cols="80"> | |
10 | ##### | |
11 | ||
12 | # # | |
13 | ...... # # | |
14 | # ~ # | |
15 | ####################### # | |
16 | %# # | |
17 | . . . T ##### # | |
18 | ### # : # | |
19 | # # | |
20 | # . # | |
21 | # # | |
22 | # # | |
23 | # . # | |
24 | # # | |
25 | # # | |
26 | >>>>>>>>>>>>>>>##<<<<<<<<<<<<<<<<<############################ | |
27 | % | |
28 | T | |
29 | </textarea> | |
30 | ||
31 | <pre id="output" style="border: 1px solid blue"> | |
32 | </pre> | |
33 | ||
34 | <button id="start">Start</button> | |
35 | <button id="stop">Stop</button> | |
36 | <button id="step">Step</button> | |
37 | <button id="load">Load</button> | |
38 | Speed: <input id="speed" type="range" min="0" max="200" value="0" /> | |
39 | ||
40 | </body> | |
41 | <script src="yoob/controller.js"></script> | |
42 | <script src="yoob/playfield.js"></script> | |
43 | <script src="../script/redgreen.js"></script> | |
44 | <script> | |
45 | var output = document.getElementById('output'); | |
46 | var c = new yoob.Controller(); | |
47 | var pf; | |
48 | ||
49 | c.load = function(text) { | |
50 | pf = new yoob.Playfield(); | |
51 | pf.setDefault('Air'); | |
52 | pf.load(0, 0, text, loadMapper); | |
53 | output.innerHTML = pf.dump(dumpMapper); | |
54 | }; | |
55 | ||
56 | c.step = function() { | |
57 | var newPf = new yoob.Playfield(); | |
58 | newPf.setDefault('Air'); | |
59 | evolve_playfield(pf, newPf); | |
60 | pf = newPf; | |
61 | output.innerHTML = pf.dump(dumpMapper); | |
62 | }; | |
63 | ||
64 | c.connect({ | |
65 | 'start': 'start', | |
66 | 'stop': 'stop', | |
67 | 'step': 'step', | |
68 | 'load': 'load', | |
69 | 'source': 'input', | |
70 | 'speed': 'speed' | |
71 | }); | |
72 | </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 'Air'; | |
25 | if (c === '#') return 'Earth'; | |
26 | if (c === '%') return 'Fire'; | |
27 | if (c === '&') return 'Magma'; | |
28 | if (c === '*') return 'Spark'; | |
29 | if (c === '-') return 'Tail'; | |
30 | if (c === '.') return 'OnePebble'; | |
31 | if (c === ':') return 'TwoPebble'; | |
32 | if (c === '=') return 'Wire'; | |
33 | if (c === '<') return 'ConveyorLeft'; | |
34 | if (c === '?') return 'Randomizer'; | |
35 | if (c === '>') return 'ConveyorRight'; | |
36 | if (c === '@') return 'Smoke'; | |
37 | if (c === 'D') return 'DuctTape'; | |
38 | if (c === 'O') return 'UnravelTape'; | |
39 | if (c === 'T') return 'Torch'; | |
40 | if (c === 'Z') return 'BigZappy'; | |
41 | if (c === 'f') return 'Fish'; | |
42 | if (c === 'l') return 'Twig'; | |
43 | if (c === 'o') return 'Bubble'; | |
44 | if (c === 's') return 'Steam'; | |
45 | if (c === 'z') return 'Zappy'; | |
46 | if (c === '~') return 'Water'; | |
47 | }; | |
48 | function dumpMapper(s) { | |
49 | if (s === 'Air') return ' '; | |
50 | if (s === 'Earth') return '#'; | |
51 | if (s === 'Fire') return '%'; | |
52 | if (s === 'Magma') return '&'; | |
53 | if (s === 'Spark') return '*'; | |
54 | if (s === 'Tail') return '-'; | |
55 | if (s === 'OnePebble') return '.'; | |
56 | if (s === 'TwoPebble') return ':'; | |
57 | if (s === 'Wire') return '='; | |
58 | if (s === 'ConveyorLeft') return '<'; | |
59 | if (s === 'Randomizer') return '?'; | |
60 | if (s === 'ConveyorRight') return '>'; | |
61 | if (s === 'Smoke') return '@'; | |
62 | if (s === 'DuctTape') return 'D'; | |
63 | if (s === 'UnravelTape') return 'O'; | |
64 | if (s === 'Torch') return 'T'; | |
65 | if (s === 'BigZappy') return 'Z'; | |
66 | if (s === 'Fish') return 'f'; | |
67 | if (s === 'Twig') return 'l'; | |
68 | if (s === 'Bubble') return 'o'; | |
69 | if (s === 'Steam') return 's'; | |
70 | if (s === 'Zappy') return 'z'; | |
71 | if (s === 'Water') return '~'; | |
72 | }; | |
73 | function is_Passthru(st) { | |
74 | return (st === 'Fire') || (st === 'Zappy') || (st === 'BigZappy') || (st === 'Air') || (st === 'Water') || (st === 'Smoke') || (st === 'Bubble') || (st === 'Steam') || 0; | |
75 | } | |
76 | ||
77 | function is_Flammable(st) { | |
78 | return (st === 'UnravelTape') || (st === 'Twig') || (st === 'DuctTape') || 0; | |
79 | } | |
80 | ||
81 | function is_Support(st) { | |
82 | return (st === 'Wire') || (st === 'DuctTape') || (st === 'Randomizer') || (st === 'TwoPebble') || (st === 'Magma') || (st === 'Tail') || (st === 'Earth') || (st === 'Spark') || (st === 'Twig') || 0; | |
83 | } | |
84 | ||
85 | function is_Burner(st) { | |
86 | return (st === 'Fire') || (st === 'Zappy') || (st === 'Spark') || (st === 'Magma') || (st === 'BigZappy') || 0; | |
87 | } | |
88 | ||
89 | function is_Steamy(st) { | |
90 | return (st === 'Bubble') || (st === 'Steam') || (st === 'Smoke') || 0; | |
91 | } | |
92 | ||
93 | function is_Fallable(st) { | |
94 | return (st === 'UnravelTape') || (st === 'OnePebble') || (st === 'TwoPebble') || (st === 'Twig') || 0; | |
95 | } | |
96 | ||
97 | function evalClass_Fallable(pf, x, y) { | |
98 | var id; | |
99 | if (((!(is_Support(pf.get(x+0,y+1)))&&(in_nbhd_eq(pf, x, y, 'Air', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 2))&&!((in_nbhd_eq(pf, x, y, 'DuctTape', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)))) { | |
100 | return 'Air'; | |
101 | } | |
102 | if (((!(is_Support(pf.get(x+0,y+1)))&&(in_nbhd_eq(pf, x, y, 'Water', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 4))&&!((in_nbhd_eq(pf, x, y, 'DuctTape', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)))) { | |
103 | return 'Water'; | |
104 | } | |
105 | if ((((pf.get(x+0,y+1)==='ConveyorLeft')&&!(is_Passthru(pf.get(x+-1,y+0))))||((pf.get(x+0,y+1)==='ConveyorRight')&&!(is_Passthru(pf.get(x+1,y+0)))))) { | |
106 | return pf.get(x+0,y+0); | |
107 | } | |
108 | return undefined; | |
109 | } | |
110 | ||
111 | function evalClass_Passthru(pf, x, y) { | |
112 | var id; | |
113 | if (is_Fallable(pf.get(x+0,y+-1))) { | |
114 | return pf.get(x+0,y+-1); | |
115 | } | |
116 | if ((is_Fallable(pf.get(x+1,y+0))&&(pf.get(x+1,y+1)==='ConveyorLeft'))) { | |
117 | return pf.get(x+1,y+0); | |
118 | } | |
119 | if ((is_Fallable(pf.get(x+-1,y+0))&&(pf.get(x+-1,y+1)==='ConveyorRight'))) { | |
120 | return pf.get(x+-1,y+0); | |
121 | } | |
122 | return undefined; | |
123 | } | |
124 | ||
125 | function evalClass_Flammable(pf, x, y) { | |
126 | var id; | |
127 | if ((in_nbhd_pred(pf, x, y, is_Burner, [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)) { | |
128 | return 'Fire'; | |
129 | } | |
130 | return undefined; | |
131 | } | |
132 | ||
133 | function evalClass_Steamy(pf, x, y) { | |
134 | var id; | |
135 | if ((((((pf.get(x+-1,y+0)==='Water')||(pf.get(x+1,y+0)==='Water'))||(pf.get(x+-1,y+-1)==='Water'))||(pf.get(x+1,y+-1)==='Water'))||(pf.get(x+0,y+-1)==='Water'))) { | |
136 | return 'Water'; | |
137 | } | |
138 | if (true) { | |
139 | return 'Air'; | |
140 | } | |
141 | return undefined; | |
142 | } | |
143 | ||
144 | function evalClass_Burner(pf, x, y) { | |
145 | var id; | |
146 | return undefined; | |
147 | } | |
148 | ||
149 | function evalClass_Support(pf, x, y) { | |
150 | var id; | |
151 | return undefined; | |
152 | } | |
153 | ||
154 | function eval_Air(pf, x, y) { | |
155 | var id; | |
156 | if ((((((((pf.get(x+0,y+-1)==='Water')||(pf.get(x+-1,y+-1)==='Water'))||(pf.get(x+1,y+-1)==='Water'))||((pf.get(x+-1,y+0)==='Water')&&is_Support(pf.get(x+-1,y+1))))||(((pf.get(x+-1,y+0)==='Water')&&(pf.get(x+-1,y+1)==='Water'))&&(pf.get(x+0,y+1)==='Water')))||((pf.get(x+1,y+0)==='Water')&&is_Support(pf.get(x+1,y+1))))||(((pf.get(x+1,y+0)==='Water')&&(pf.get(x+1,y+1)==='Water'))&&(pf.get(x+0,y+1)==='Water')))) { | |
157 | return 'Water'; | |
158 | } | |
159 | if ((((pf.get(x+0,y+1)==='Steam')||(pf.get(x+-1,y+1)==='Steam'))||(pf.get(x+1,y+1)==='Steam'))) { | |
160 | return 'Steam'; | |
161 | } | |
162 | if ((((pf.get(x+0,y+1)==='Smoke')||(pf.get(x+-1,y+1)==='Smoke'))||(pf.get(x+1,y+1)==='Smoke'))) { | |
163 | return 'Smoke'; | |
164 | } | |
165 | if ((in_nbhd_eq(pf, x, y, 'Spark', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)) { | |
166 | return 'Zappy'; | |
167 | } | |
168 | id = evalClass_Passthru(pf, x, y); | |
169 | if (id !== undefined) return id; | |
170 | return 'Air'; | |
171 | } | |
172 | ||
173 | function eval_Water(pf, x, y) { | |
174 | var id; | |
175 | if (((in_nbhd_eq(pf, x, y, 'Fire', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)||(in_nbhd_eq(pf, x, y, 'Magma', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1))) { | |
176 | return 'Steam'; | |
177 | } | |
178 | if ((((pf.get(x+0,y+1)==='Bubble')||(pf.get(x+0,y+1)==='Smoke'))||(pf.get(x+0,y+1)==='Steam'))) { | |
179 | return 'Bubble'; | |
180 | } | |
181 | if (((in_nbhd_eq(pf, x, y, 'Fish', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 3)&&(in_nbhd_eq(pf, x, y, 'Water', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 5))) { | |
182 | return 'Fish'; | |
183 | } | |
184 | id = evalClass_Passthru(pf, x, y); | |
185 | if (id !== undefined) return id; | |
186 | return 'Water'; | |
187 | } | |
188 | ||
189 | function eval_Fire(pf, x, y) { | |
190 | var id; | |
191 | if ((((in_nbhd_eq(pf, x, y, 'Water', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)||!((in_nbhd_eq(pf, x, y, 'Air', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)))||((!((in_nbhd_eq(pf, x, y, 'Torch', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1))&&!((in_nbhd_eq(pf, x, y, 'DuctTape', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)))&&!((in_nbhd_eq(pf, x, y, 'Twig', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1))))) { | |
192 | return 'Smoke'; | |
193 | } | |
194 | id = evalClass_Passthru(pf, x, y); | |
195 | if (id !== undefined) return id; | |
196 | id = evalClass_Burner(pf, x, y); | |
197 | if (id !== undefined) return id; | |
198 | return 'Fire'; | |
199 | } | |
200 | ||
201 | function eval_Earth(pf, x, y) { | |
202 | var id; | |
203 | if ((in_nbhd_eq(pf, x, y, 'Fire', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)) { | |
204 | return 'Magma'; | |
205 | } | |
206 | id = evalClass_Support(pf, x, y); | |
207 | if (id !== undefined) return id; | |
208 | return 'Earth'; | |
209 | } | |
210 | ||
211 | function eval_Magma(pf, x, y) { | |
212 | var id; | |
213 | if ((!((in_nbhd_eq(pf, x, y, 'Fire', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1))&&!((in_nbhd_eq(pf, x, y, 'Magma', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 2)))) { | |
214 | return 'Earth'; | |
215 | } | |
216 | id = evalClass_Support(pf, x, y); | |
217 | if (id !== undefined) return id; | |
218 | id = evalClass_Burner(pf, x, y); | |
219 | if (id !== undefined) return id; | |
220 | return 'Magma'; | |
221 | } | |
222 | ||
223 | function eval_Steam(pf, x, y) { | |
224 | var id; | |
225 | id = evalClass_Passthru(pf, x, y); | |
226 | if (id !== undefined) return id; | |
227 | id = evalClass_Steamy(pf, x, y); | |
228 | if (id !== undefined) return id; | |
229 | return 'Steam'; | |
230 | } | |
231 | ||
232 | function eval_Smoke(pf, x, y) { | |
233 | var id; | |
234 | id = evalClass_Passthru(pf, x, y); | |
235 | if (id !== undefined) return id; | |
236 | id = evalClass_Steamy(pf, x, y); | |
237 | if (id !== undefined) return id; | |
238 | return 'Smoke'; | |
239 | } | |
240 | ||
241 | function eval_Bubble(pf, x, y) { | |
242 | var id; | |
243 | id = evalClass_Passthru(pf, x, y); | |
244 | if (id !== undefined) return id; | |
245 | id = evalClass_Steamy(pf, x, y); | |
246 | if (id !== undefined) return id; | |
247 | return 'Bubble'; | |
248 | } | |
249 | ||
250 | function eval_Fish(pf, x, y) { | |
251 | var id; | |
252 | if ((!((in_nbhd_eq(pf, x, y, 'Water', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1))&&!((in_nbhd_eq(pf, x, y, 'Fish', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 8)))) { | |
253 | return 'Air'; | |
254 | } | |
255 | if (((in_nbhd_eq(pf, x, y, 'Fish', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 4)||(in_nbhd_eq(pf, x, y, 'Water', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 7))) { | |
256 | return 'Water'; | |
257 | } | |
258 | return 'Fish'; | |
259 | } | |
260 | ||
261 | function eval_OnePebble(pf, x, y) { | |
262 | var id; | |
263 | if (((pf.get(x+0,y+-1)==='OnePebble')&&is_Support(pf.get(x+0,y+1)))) { | |
264 | return 'TwoPebble'; | |
265 | } | |
266 | id = evalClass_Fallable(pf, x, y); | |
267 | if (id !== undefined) return id; | |
268 | return 'OnePebble'; | |
269 | } | |
270 | ||
271 | function eval_TwoPebble(pf, x, y) { | |
272 | var id; | |
273 | id = evalClass_Fallable(pf, x, y); | |
274 | if (id !== undefined) return id; | |
275 | id = evalClass_Support(pf, x, y); | |
276 | if (id !== undefined) return id; | |
277 | return 'TwoPebble'; | |
278 | } | |
279 | ||
280 | function eval_Spark(pf, x, y) { | |
281 | var id; | |
282 | if (true) { | |
283 | return 'Tail'; | |
284 | } | |
285 | id = evalClass_Support(pf, x, y); | |
286 | if (id !== undefined) return id; | |
287 | id = evalClass_Burner(pf, x, y); | |
288 | if (id !== undefined) return id; | |
289 | return 'Spark'; | |
290 | } | |
291 | ||
292 | function eval_Tail(pf, x, y) { | |
293 | var id; | |
294 | if (true) { | |
295 | return 'Wire'; | |
296 | } | |
297 | id = evalClass_Support(pf, x, y); | |
298 | if (id !== undefined) return id; | |
299 | return 'Tail'; | |
300 | } | |
301 | ||
302 | function eval_Wire(pf, x, y) { | |
303 | var id; | |
304 | if (((in_nbhd_eq(pf, x, y, 'Spark', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)&&!((in_nbhd_eq(pf, x, y, 'Spark', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 3)))) { | |
305 | return 'Spark'; | |
306 | } | |
307 | id = evalClass_Support(pf, x, y); | |
308 | if (id !== undefined) return id; | |
309 | return 'Wire'; | |
310 | } | |
311 | ||
312 | function eval_DuctTape(pf, x, y) { | |
313 | var id; | |
314 | if ((!((in_nbhd_eq(pf, x, y, 'DuctTape', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 2))||!(((in_nbhd_eq(pf, x, y, 'DuctTape', [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1)&&(in_nbhd_pred(pf, x, y, is_Support, [[0,-1],[0,1],[-1,0],[-1,1],[-1,-1],[1,0],[1,1],[1,-1]]) >= 1))))) { | |
315 | return 'UnravelTape'; | |
316 | } | |
317 | id = evalClass_Support(pf, x, y); | |
318 | if (id !== undefined) return id; | |
319 | id = evalClass_Flammable(pf, x, y); | |
320 | if (id !== undefined) return id; | |
321 | return 'DuctTape'; | |
322 | } | |
323 | ||
324 | function eval_UnravelTape(pf, x, y) { | |
325 | var id; | |
326 | id = evalClass_Fallable(pf, x, y); | |
327 | if (id !== undefined) return id; | |
328 | id = evalClass_Flammable(pf, x, y); | |
329 | if (id !== undefined) return id; | |
330 | return 'UnravelTape'; | |
331 | } | |
332 | ||
333 | function eval_Twig(pf, x, y) { | |
334 | var id; | |
335 | id = evalClass_Fallable(pf, x, y); | |
336 | if (id !== undefined) return id; | |
337 | id = evalClass_Support(pf, x, y); | |
338 | if (id !== undefined) return id; | |
339 | id = evalClass_Flammable(pf, x, y); | |
340 | if (id !== undefined) return id; | |
341 | return 'Twig'; | |
342 | } | |
343 | ||
344 | function eval_Zappy(pf, x, y) { | |
345 | var id; | |
346 | if (true) { | |
347 | return 'BigZappy'; | |
348 | } | |
349 | id = evalClass_Passthru(pf, x, y); | |
350 | if (id !== undefined) return id; | |
351 | id = evalClass_Burner(pf, x, y); | |
352 | if (id !== undefined) return id; | |
353 | return 'Zappy'; | |
354 | } | |
355 | ||
356 | function eval_BigZappy(pf, x, y) { | |
357 | var id; | |
358 | if (true) { | |
359 | return 'Air'; | |
360 | } | |
361 | id = evalClass_Passthru(pf, x, y); | |
362 | if (id !== undefined) return id; | |
363 | id = evalClass_Burner(pf, x, y); | |
364 | if (id !== undefined) return id; | |
365 | return 'BigZappy'; | |
366 | } | |
367 | ||
368 | function eval_Randomizer(pf, x, y) { | |
369 | var id; | |
370 | id = evalClass_Support(pf, x, y); | |
371 | if (id !== undefined) return id; | |
372 | return 'Randomizer'; | |
373 | } | |
374 | ||
375 | function eval_ConveyorLeft(pf, x, y) { | |
376 | var id; | |
377 | if (((pf.get(x+0,y+1)==='Randomizer')&&guess)) { | |
378 | return 'ConveyorRight'; | |
379 | } | |
380 | return 'ConveyorLeft'; | |
381 | } | |
382 | ||
383 | function eval_ConveyorRight(pf, x, y) { | |
384 | var id; | |
385 | if (((pf.get(x+0,y+1)==='Randomizer')&&guess)) { | |
386 | return 'ConveyorLeft'; | |
387 | } | |
388 | return 'ConveyorRight'; | |
389 | } | |
390 | ||
391 | function eval_Torch(pf, x, y) { | |
392 | var id; | |
393 | return 'Torch'; | |
394 | } | |
395 | ||
396 | function evalState(pf, x, y) { | |
397 | var stateId = pf.get(x, y); | |
398 | if (stateId === 'Air') return eval_Air(pf, x, y); | |
399 | if (stateId === 'Water') return eval_Water(pf, x, y); | |
400 | if (stateId === 'Fire') return eval_Fire(pf, x, y); | |
401 | if (stateId === 'Earth') return eval_Earth(pf, x, y); | |
402 | if (stateId === 'Magma') return eval_Magma(pf, x, y); | |
403 | if (stateId === 'Steam') return eval_Steam(pf, x, y); | |
404 | if (stateId === 'Smoke') return eval_Smoke(pf, x, y); | |
405 | if (stateId === 'Bubble') return eval_Bubble(pf, x, y); | |
406 | if (stateId === 'Fish') return eval_Fish(pf, x, y); | |
407 | if (stateId === 'OnePebble') return eval_OnePebble(pf, x, y); | |
408 | if (stateId === 'TwoPebble') return eval_TwoPebble(pf, x, y); | |
409 | if (stateId === 'Spark') return eval_Spark(pf, x, y); | |
410 | if (stateId === 'Tail') return eval_Tail(pf, x, y); | |
411 | if (stateId === 'Wire') return eval_Wire(pf, x, y); | |
412 | if (stateId === 'DuctTape') return eval_DuctTape(pf, x, y); | |
413 | if (stateId === 'UnravelTape') return eval_UnravelTape(pf, x, y); | |
414 | if (stateId === 'Twig') return eval_Twig(pf, x, y); | |
415 | if (stateId === 'Zappy') return eval_Zappy(pf, x, y); | |
416 | if (stateId === 'BigZappy') return eval_BigZappy(pf, x, y); | |
417 | if (stateId === 'Randomizer') return eval_Randomizer(pf, x, y); | |
418 | if (stateId === 'ConveyorLeft') return eval_ConveyorLeft(pf, x, y); | |
419 | if (stateId === 'ConveyorRight') return eval_ConveyorRight(pf, x, y); | |
420 | if (stateId === 'Torch') return eval_Torch(pf, x, y); | |
421 | } |