diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2023-11-03 00:18:41 -0400 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2023-11-03 00:18:41 -0400 |
commit | 00641f16c889093b32b8e97a6050817f6fe43780 (patch) | |
tree | 33d0279af22ac028472d5eda0b535b58757dbc05 /app/assets/javascripts | |
parent | 13dfac7905faac21ea98b08a0948104df8411d42 (diff) | |
download | wittle-00641f16c889093b32b8e97a6050817f6fe43780.tar.gz wittle-00641f16c889093b32b8e97a6050817f6fe43780.tar.bz2 wittle-00641f16c889093b32b8e97a6050817f6fe43780.zip |
added weird symmetries (and some more puzzles)
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r-- | app/assets/javascripts/wittle/display2.js | 19 | ||||
-rw-r--r-- | app/assets/javascripts/wittle/puzzle.js | 74 | ||||
-rw-r--r-- | app/assets/javascripts/wittle/serializer.js | 22 | ||||
-rw-r--r-- | app/assets/javascripts/wittle/solve.js | 12 | ||||
-rw-r--r-- | app/assets/javascripts/wittle/trace2.js | 134 | ||||
-rw-r--r-- | app/assets/javascripts/wittle/validate.js | 4 |
6 files changed, 181 insertions, 84 deletions
diff --git a/app/assets/javascripts/wittle/display2.js b/app/assets/javascripts/wittle/display2.js index 52069d6..ddf3968 100644 --- a/app/assets/javascripts/wittle/display2.js +++ b/app/assets/javascripts/wittle/display2.js | |||
@@ -1,3 +1,20 @@ | |||
1 | var SYM_TYPE_NONE = 0 | ||
2 | var SYM_TYPE_HORIZONTAL = 1 | ||
3 | var SYM_TYPE_VERTICAL = 2 | ||
4 | var SYM_TYPE_ROTATIONAL = 3 | ||
5 | var SYM_TYPE_ROTATE_LEFT = 4 | ||
6 | var SYM_TYPE_ROTATE_RIGHT = 5 | ||
7 | var SYM_TYPE_FLIP_XY = 6 | ||
8 | var SYM_TYPE_FLIP_NEG_XY = 7 | ||
9 | var SYM_TYPE_PARALLEL_H = 8 | ||
10 | var SYM_TYPE_PARALLEL_V = 9 | ||
11 | var SYM_TYPE_PARALLEL_H_FLIP = 10 | ||
12 | var SYM_TYPE_PARALLEL_V_FLIP = 11 | ||
13 | var SYM_TYPE_PILLAR_PARALLEL = 12 | ||
14 | var SYM_TYPE_PILLAR_HORIZONTAL = 13 | ||
15 | var SYM_TYPE_PILLAR_VERTICAL = 14 | ||
16 | var SYM_TYPE_PILLAR_ROTATIONAL = 15 | ||
17 | |||
1 | namespace(function() { | 18 | namespace(function() { |
2 | 19 | ||
3 | window.draw = function(puzzle, target='puzzle') { | 20 | window.draw = function(puzzle, target='puzzle') { |
@@ -260,7 +277,7 @@ function drawStartAndEnd(puzzle, svg) { | |||
260 | 277 | ||
261 | if (cell.start === true) { | 278 | if (cell.start === true) { |
262 | var symStart = null | 279 | var symStart = null |
263 | if (puzzle.symmetry != null) { | 280 | if (puzzle.symType != SYM_TYPE_NONE) { |
264 | var sym = puzzle.getSymmetricalPos(x, y) | 281 | var sym = puzzle.getSymmetricalPos(x, y) |
265 | window.drawSymbolWithSvg(svg, { | 282 | window.drawSymbolWithSvg(svg, { |
266 | 'type': 'start', | 283 | 'type': 'start', |
diff --git a/app/assets/javascripts/wittle/puzzle.js b/app/assets/javascripts/wittle/puzzle.js index 4d6b0fb..cb0b20a 100644 --- a/app/assets/javascripts/wittle/puzzle.js +++ b/app/assets/javascripts/wittle/puzzle.js | |||
@@ -123,6 +123,7 @@ window.Puzzle = class { | |||
123 | } | 123 | } |
124 | puzzle.pillar = parsed.pillar | 124 | puzzle.pillar = parsed.pillar |
125 | puzzle.symmetry = parsed.symmetry | 125 | puzzle.symmetry = parsed.symmetry |
126 | puzzle.symType = parsed.symType | ||
126 | puzzle.largezero = puzzle.width * puzzle.height | 127 | puzzle.largezero = puzzle.width * puzzle.height |
127 | return puzzle | 128 | return puzzle |
128 | } | 129 | } |
@@ -185,36 +186,63 @@ window.Puzzle = class { | |||
185 | } | 186 | } |
186 | 187 | ||
187 | getSymmetricalDir(dir) { | 188 | getSymmetricalDir(dir) { |
188 | if (this.symmetry != null) { | 189 | if (this.symType == SYM_TYPE_VERTICAL || this.symType == SYM_TYPE_ROTATIONAL || this.symType == SYM_TYPE_PARALLEL_H_FLIP) { |
189 | if (this.symmetry.x === true) { | 190 | if (dir === 'left') return 'right' |
190 | if (dir === 'left') return 'right' | 191 | if (dir === 'right') return 'left' |
191 | if (dir === 'right') return 'left' | 192 | } |
192 | } | 193 | if (this.symType == SYM_TYPE_HORIZONTAL || this.symType == SYM_TYPE_ROTATIONAL || this.symType == SYM_TYPE_PARALLEL_V_FLIP) { |
193 | if (this.symmetry.y === true) { | 194 | if (dir === 'top') return 'bottom' |
194 | if (dir === 'top') return 'bottom' | 195 | if (dir === 'bottom') return 'top' |
195 | if (dir === 'bottom') return 'top' | 196 | } |
196 | } | 197 | if (this.symType == SYM_TYPE_ROTATE_LEFT || this.symType == SYM_TYPE_FLIP_NEG_XY) { |
198 | if (dir === 'left') return 'bottom' | ||
199 | if (dir === 'right') return 'top' | ||
200 | } | ||
201 | if (this.symType == SYM_TYPE_ROTATE_RIGHT || this.symType == SYM_TYPE_FLIP_NEG_XY) { | ||
202 | if (dir === 'top') return 'right' | ||
203 | if (dir === 'bottom') return 'left' | ||
204 | } | ||
205 | if (this.symType == SYM_TYPE_ROTATE_LEFT || this.symType == SYM_TYPE_FLIP_XY) { | ||
206 | if (dir === 'top') return 'left' | ||
207 | if (dir === 'bottom') return 'right' | ||
208 | } | ||
209 | if (this.symType == SYM_TYPE_ROTATE_RIGHT || this.symType == SYM_TYPE_FLIP_XY) { | ||
210 | if (dir === 'right') return 'bottom' | ||
211 | if (dir === 'left') return 'top' | ||
197 | } | 212 | } |
198 | return dir | 213 | return dir |
199 | } | 214 | } |
200 | 215 | ||
201 | // The resulting position is guaranteed to be gridsafe. | 216 | // The resulting position is guaranteed to be gridsafe. |
202 | getSymmetricalPos(x, y) { | 217 | getSymmetricalPos(x, y) { |
203 | if (this.symmetry != null) { | 218 | var origx = x |
204 | if (this.pillar === true) { | 219 | var origy = y |
205 | x += this.width/2 | 220 | |
206 | if (this.symmetry.x === true) { | 221 | if (this.symType == SYM_TYPE_VERTICAL || this.symType == SYM_TYPE_ROTATIONAL || this.symType == SYM_TYPE_PARALLEL_H_FLIP) { |
207 | x = this.width - x | 222 | x = (this.width - 1) - origx |
208 | } | 223 | } |
209 | } else { | 224 | if (this.symType == SYM_TYPE_HORIZONTAL || this.symType == SYM_TYPE_ROTATIONAL || this.symType == SYM_TYPE_PARALLEL_V_FLIP) { |
210 | if (this.symmetry.x === true) { | 225 | y = (this.height - 1) - origy |
211 | x = (this.width - 1) - x | 226 | } |
212 | } | 227 | if (this.symType == SYM_TYPE_ROTATE_LEFT || this.symType == SYM_TYPE_FLIP_XY) { |
213 | } | 228 | x = origy |
214 | if (this.symmetry.y === true) { | 229 | } |
215 | y = (this.height - 1) - y | 230 | if (this.symType == SYM_TYPE_ROTATE_RIGHT || this.symType == SYM_TYPE_FLIP_XY) { |
216 | } | 231 | y = origx |
217 | } | 232 | } |
233 | if (this.symType == SYM_TYPE_ROTATE_LEFT || this.symType == SYM_TYPE_FLIP_NEG_XY) { | ||
234 | y = (this.width - 1) - origx | ||
235 | } | ||
236 | if (this.symType == SYM_TYPE_ROTATE_RIGHT || this.symType == SYM_TYPE_FLIP_NEG_XY) { | ||
237 | x = (this.height - 1) - origy | ||
238 | } | ||
239 | if (this.symType == SYM_TYPE_PARALLEL_H || this.symType == SYM_TYPE_PARALLEL_H_FLIP) { | ||
240 | y = (origy == this.height / 2) ? (this.height / 2) : ((origy + (this.height + 1) / 2) % (this.height + 1)) | ||
241 | } | ||
242 | if (this.symType == SYM_TYPE_PARALLEL_V || this.symType == SYM_TYPE_PARALLEL_V_FLIP) { | ||
243 | x = (origx == this.width / 2) ? (this.width / 2) : ((origx + (this.width + 1) / 2) % (this.width + 1)) | ||
244 | } | ||
245 | |||
218 | return {'x':this._mod(x), 'y':y} | 246 | return {'x':this._mod(x), 'y':y} |
219 | } | 247 | } |
220 | 248 | ||
diff --git a/app/assets/javascripts/wittle/serializer.js b/app/assets/javascripts/wittle/serializer.js index 1598d9b..70c7f0f 100644 --- a/app/assets/javascripts/wittle/serializer.js +++ b/app/assets/javascripts/wittle/serializer.js | |||
@@ -46,6 +46,8 @@ window.serializePuzzle = function(puzzle) { | |||
46 | if (puzzle.settings.INVISIBLE_SYMMETRY) settingsFlags |= SETTINGS_FLAG_IS | 46 | if (puzzle.settings.INVISIBLE_SYMMETRY) settingsFlags |= SETTINGS_FLAG_IS |
47 | s.writeByte(settingsFlags) | 47 | s.writeByte(settingsFlags) |
48 | 48 | ||
49 | s.writeByte(puzzle.symType) | ||
50 | |||
49 | return s.str() | 51 | return s.str() |
50 | } | 52 | } |
51 | 53 | ||
@@ -64,10 +66,16 @@ window.deserializePuzzle = function(data) { | |||
64 | 66 | ||
65 | var genericFlags = s.readByte() | 67 | var genericFlags = s.readByte() |
66 | puzzle.autoSolved = genericFlags & GENERIC_FLAG_AUTOSOLVED | 68 | puzzle.autoSolved = genericFlags & GENERIC_FLAG_AUTOSOLVED |
69 | puzzle.symType = SYM_TYPE_NONE | ||
67 | if ((genericFlags & GENERIC_FLAG_SYMMETRICAL) != 0) { | 70 | if ((genericFlags & GENERIC_FLAG_SYMMETRICAL) != 0) { |
68 | puzzle.symmetry = { | 71 | if ((genericFlags & GENERIC_FLAG_SYMMETRY_X) != 0) { |
69 | 'x': ((genericFlags & GENERIC_FLAG_SYMMETRY_X) != 0), | 72 | if ((genericFlags & GENERIC_FLAG_SYMMETRY_Y) != 0) { |
70 | 'y': ((genericFlags & GENERIC_FLAG_SYMMETRY_Y) != 0), | 73 | puzzle.symType = SYM_TYPE_ROTATIONAL |
74 | } else { | ||
75 | puzzle.symType = SYM_TYPE_VERTICAL | ||
76 | } | ||
77 | } else if ((genericFlags & GENERIC_FLAG_SYMMETRY_Y) != 0) { | ||
78 | puzzle.symType = SYM_TYPE_HORIZONTAL | ||
71 | } | 79 | } |
72 | } | 80 | } |
73 | puzzle.pillar = (genericFlags & GENERIC_FLAG_PILLAR) != 0 | 81 | puzzle.pillar = (genericFlags & GENERIC_FLAG_PILLAR) != 0 |
@@ -97,6 +105,10 @@ window.deserializePuzzle = function(data) { | |||
97 | INVISIBLE_SYMMETRY: (settingsFlags & SETTINGS_FLAG_IS) != 0, | 105 | INVISIBLE_SYMMETRY: (settingsFlags & SETTINGS_FLAG_IS) != 0, |
98 | } | 106 | } |
99 | 107 | ||
108 | if (s.hasLeft(1)) { | ||
109 | puzzle.symType = s.readByte() | ||
110 | } | ||
111 | |||
100 | s.destroy() | 112 | s.destroy() |
101 | return puzzle | 113 | return puzzle |
102 | } | 114 | } |
@@ -138,6 +150,10 @@ class Serializer { | |||
138 | if (this.data.length < numBytes) throw Error('Cannot read ' + numBytes + ' bytes from a stream with only '+ this.data.length + ' bytes') | 150 | if (this.data.length < numBytes) throw Error('Cannot read ' + numBytes + ' bytes from a stream with only '+ this.data.length + ' bytes') |
139 | } | 151 | } |
140 | 152 | ||
153 | hasLeft(numBytes = 1) { | ||
154 | return ((this.data.length - this.index) >= numBytes) | ||
155 | } | ||
156 | |||
141 | readByte() { | 157 | readByte() { |
142 | this._checkRead() | 158 | this._checkRead() |
143 | return this.data.charCodeAt(this.index++) | 159 | return this.data.charCodeAt(this.index++) |
diff --git a/app/assets/javascripts/wittle/solve.js b/app/assets/javascripts/wittle/solve.js index 13b9650..8695291 100644 --- a/app/assets/javascripts/wittle/solve.js +++ b/app/assets/javascripts/wittle/solve.js | |||
@@ -28,7 +28,7 @@ function countNodes(x, y, depth) { | |||
28 | if (cell.gap > window.GAP_NONE) return | 28 | if (cell.gap > window.GAP_NONE) return |
29 | if (cell.line !== window.LINE_NONE) return | 29 | if (cell.line !== window.LINE_NONE) return |
30 | 30 | ||
31 | if (puzzle.symmetry == null) { | 31 | if (puzzle.symType == SYM_TYPE_NONE) { |
32 | puzzle.updateCell2(x, y, 'line', window.LINE_BLACK) | 32 | puzzle.updateCell2(x, y, 'line', window.LINE_BLACK) |
33 | } else { | 33 | } else { |
34 | var sym = puzzle.getSymmetricalPos(x, y) | 34 | var sym = puzzle.getSymmetricalPos(x, y) |
@@ -84,7 +84,7 @@ window.solve = function(p, partialCallback, finalCallback) { | |||
84 | // Puzzles which are small enough should be solved synchronously, since the cost of asynchronizing | 84 | // Puzzles which are small enough should be solved synchronously, since the cost of asynchronizing |
85 | // is greater than the cost of the puzzle. | 85 | // is greater than the cost of the puzzle. |
86 | SOLVE_SYNC = false | 86 | SOLVE_SYNC = false |
87 | if (puzzle.symmetry != null) { // 5x5 is the max for symmetry puzzles | 87 | if (puzzle.symType != SYM_TYPE_NONE) { // 5x5 is the max for symmetry puzzles |
88 | if (puzzle.width * puzzle.height <= 121) SOLVE_SYNC = true | 88 | if (puzzle.width * puzzle.height <= 121) SOLVE_SYNC = true |
89 | } else if (puzzle.pillar === true) { // 4x5 is the max for non-symmetry, pillar puzzles | 89 | } else if (puzzle.pillar === true) { // 4x5 is the max for non-symmetry, pillar puzzles |
90 | if (puzzle.width * puzzle.height <= 108) SOLVE_SYNC = true | 90 | if (puzzle.width * puzzle.height <= 108) SOLVE_SYNC = true |
@@ -207,7 +207,7 @@ function taskLoop(partialCallback, finalCallback) { | |||
207 | function tailRecurse(x, y) { | 207 | function tailRecurse(x, y) { |
208 | // Tail recursion: Back out of this cell | 208 | // Tail recursion: Back out of this cell |
209 | puzzle.updateCell2(x, y, 'line', window.LINE_NONE) | 209 | puzzle.updateCell2(x, y, 'line', window.LINE_NONE) |
210 | if (puzzle.symmetry != null) { | 210 | if (puzzle.symType != SYM_TYPE_NONE) { |
211 | var sym = puzzle.getSymmetricalPos(x, y) | 211 | var sym = puzzle.getSymmetricalPos(x, y) |
212 | puzzle.updateCell2(sym.x, sym.y, 'line', window.LINE_NONE) | 212 | puzzle.updateCell2(sym.x, sym.y, 'line', window.LINE_NONE) |
213 | } | 213 | } |
@@ -227,7 +227,7 @@ function solveLoop(x, y, numEndpoints, earlyExitData) { | |||
227 | if (cell.gap > window.GAP_NONE) return | 227 | if (cell.gap > window.GAP_NONE) return |
228 | if (cell.line !== window.LINE_NONE) return | 228 | if (cell.line !== window.LINE_NONE) return |
229 | 229 | ||
230 | if (puzzle.symmetry == null) { | 230 | if (puzzle.symType == SYM_TYPE_NONE) { |
231 | puzzle.updateCell2(x, y, 'line', window.LINE_BLACK) | 231 | puzzle.updateCell2(x, y, 'line', window.LINE_BLACK) |
232 | } else { | 232 | } else { |
233 | var sym = puzzle.getSymmetricalPos(x, y) | 233 | var sym = puzzle.getSymmetricalPos(x, y) |
@@ -379,7 +379,7 @@ window.drawPathNoUI = function(puzzle, path) { | |||
379 | x += dx | 379 | x += dx |
380 | y += dy | 380 | y += dy |
381 | // Set the cell color | 381 | // Set the cell color |
382 | if (puzzle.symmetry == null) { | 382 | if (puzzle.symType == SYM_TYPE_NONE) { |
383 | cell.line = window.LINE_BLACK | 383 | cell.line = window.LINE_BLACK |
384 | } else { | 384 | } else { |
385 | cell.line = window.LINE_BLUE | 385 | cell.line = window.LINE_BLUE |
@@ -457,7 +457,7 @@ window.drawPath = function(puzzle, path, target='puzzle') { | |||
457 | // Unflag the cell, move into it, and reflag it | 457 | // Unflag the cell, move into it, and reflag it |
458 | cell.line = window.LINE_NONE | 458 | cell.line = window.LINE_NONE |
459 | window.onMove(41 * dx, 41 * dy) | 459 | window.onMove(41 * dx, 41 * dy) |
460 | if (puzzle.symmetry == null) { | 460 | if (puzzle.symType == SYM_TYPE_NONE) { |
461 | cell.line = window.LINE_BLACK | 461 | cell.line = window.LINE_BLACK |
462 | } else { | 462 | } else { |
463 | cell.line = window.LINE_BLUE | 463 | cell.line = window.LINE_BLUE |
diff --git a/app/assets/javascripts/wittle/trace2.js b/app/assets/javascripts/wittle/trace2.js index 7a77564..9602a41 100644 --- a/app/assets/javascripts/wittle/trace2.js +++ b/app/assets/javascripts/wittle/trace2.js | |||
@@ -15,7 +15,7 @@ class BoundingBox { | |||
15 | data.svg.appendChild(this.debug) | 15 | data.svg.appendChild(this.debug) |
16 | this.debug.setAttribute('opacity', 0.5) | 16 | this.debug.setAttribute('opacity', 0.5) |
17 | this.debug.setAttribute('style', 'pointer-events: none;') | 17 | this.debug.setAttribute('style', 'pointer-events: none;') |
18 | if (data.puzzle.symmetry == null) { | 18 | if (data.puzzle.symType == SYM_TYPE_NONE) { |
19 | this.debug.setAttribute('fill', 'white') | 19 | this.debug.setAttribute('fill', 'white') |
20 | } else { | 20 | } else { |
21 | if (this.sym !== true) { | 21 | if (this.sym !== true) { |
@@ -120,7 +120,7 @@ class PathSegment { | |||
120 | } | 120 | } |
121 | } | 121 | } |
122 | 122 | ||
123 | if (data.puzzle.symmetry == null) { | 123 | if (data.puzzle.symType == SYM_TYPE_NONE) { |
124 | this.poly1.setAttribute('class', 'line-1 ' + data.svg.id) | 124 | this.poly1.setAttribute('class', 'line-1 ' + data.svg.id) |
125 | this.circ.setAttribute('class', 'line-1 ' + data.svg.id) | 125 | this.circ.setAttribute('class', 'line-1 ' + data.svg.id) |
126 | this.poly2.setAttribute('class', 'line-1 ' + data.svg.id) | 126 | this.poly2.setAttribute('class', 'line-1 ' + data.svg.id) |
@@ -174,7 +174,7 @@ class PathSegment { | |||
174 | if (this.dir === MOVE_NONE) { // Start point | 174 | if (this.dir === MOVE_NONE) { // Start point |
175 | this.circ.setAttribute('r', 24) | 175 | this.circ.setAttribute('r', 24) |
176 | this.circ.setAttribute('class', this.circ.getAttribute('class') + ' start') | 176 | this.circ.setAttribute('class', this.circ.getAttribute('class') + ' start') |
177 | if (data.puzzle.symmetry != null) { | 177 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
178 | this.symCirc.setAttribute('r', 24) | 178 | this.symCirc.setAttribute('r', 24) |
179 | this.symCirc.setAttribute('class', this.symCirc.getAttribute('class') + ' start') | 179 | this.symCirc.setAttribute('class', this.symCirc.getAttribute('class') + ' start') |
180 | } | 180 | } |
@@ -182,7 +182,7 @@ class PathSegment { | |||
182 | // Only insert poly1 in non-startpoints | 182 | // Only insert poly1 in non-startpoints |
183 | data.svg.insertBefore(this.poly1, data.cursor) | 183 | data.svg.insertBefore(this.poly1, data.cursor) |
184 | this.circ.setAttribute('r', 12) | 184 | this.circ.setAttribute('r', 12) |
185 | if (data.puzzle.symmetry != null) { | 185 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
186 | data.svg.insertBefore(this.symPoly1, data.cursor) | 186 | data.svg.insertBefore(this.symPoly1, data.cursor) |
187 | this.symCirc.setAttribute('r', 12) | 187 | this.symCirc.setAttribute('r', 12) |
188 | } | 188 | } |
@@ -194,7 +194,7 @@ class PathSegment { | |||
194 | data.svg.removeChild(this.circ) | 194 | data.svg.removeChild(this.circ) |
195 | data.svg.removeChild(this.poly2) | 195 | data.svg.removeChild(this.poly2) |
196 | data.svg.removeChild(this.pillarCirc) | 196 | data.svg.removeChild(this.pillarCirc) |
197 | if (data.puzzle.symmetry != null) { | 197 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
198 | data.svg.removeChild(this.symPoly1) | 198 | data.svg.removeChild(this.symPoly1) |
199 | data.svg.removeChild(this.symCirc) | 199 | data.svg.removeChild(this.symCirc) |
200 | data.svg.removeChild(this.symPoly2) | 200 | data.svg.removeChild(this.symPoly2) |
@@ -208,19 +208,19 @@ class PathSegment { | |||
208 | var y = clamp(data.y, data.bbox.y1, data.bbox.y2) | 208 | var y = clamp(data.y, data.bbox.y1, data.bbox.y2) |
209 | data.cursor.setAttribute('cx', x) | 209 | data.cursor.setAttribute('cx', x) |
210 | data.cursor.setAttribute('cy', y) | 210 | data.cursor.setAttribute('cy', y) |
211 | if (data.puzzle.symmetry != null) { | 211 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
212 | data.symcursor.setAttribute('cx', this._reflX(x)) | 212 | data.symcursor.setAttribute('cx', this._reflX(x,y)) |
213 | data.symcursor.setAttribute('cy', this._reflY(y)) | 213 | data.symcursor.setAttribute('cy', this._reflY(x,y)) |
214 | } | 214 | } |
215 | if (data.puzzle.pillar === true) { | 215 | if (data.puzzle.pillar === true) { |
216 | if (this.pillarCirc.getAttribute('static') == null) { | 216 | if (this.pillarCirc.getAttribute('static') == null) { |
217 | this.pillarCirc.setAttribute('cx', x) | 217 | this.pillarCirc.setAttribute('cx', x) |
218 | this.pillarCirc.setAttribute('cy', y) | 218 | this.pillarCirc.setAttribute('cy', y) |
219 | } | 219 | } |
220 | if (data.puzzle.symmetry != null) { | 220 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
221 | if (this.symPillarCirc.getAttribute('static') == null) { | 221 | if (this.symPillarCirc.getAttribute('static') == null) { |
222 | this.symPillarCirc.setAttribute('cx', this._reflX(x)) | 222 | this.symPillarCirc.setAttribute('cx', this._reflX(x,y)) |
223 | this.symPillarCirc.setAttribute('cy', this._reflY(y)) | 223 | this.symPillarCirc.setAttribute('cy', this._reflY(x,y)) |
224 | } | 224 | } |
225 | } | 225 | } |
226 | } | 226 | } |
@@ -296,19 +296,19 @@ class PathSegment { | |||
296 | } | 296 | } |
297 | 297 | ||
298 | // Draw the symmetrical path based on the original one | 298 | // Draw the symmetrical path based on the original one |
299 | if (data.puzzle.symmetry != null) { | 299 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
300 | this.symPoly1.setAttribute('points', | 300 | this.symPoly1.setAttribute('points', |
301 | this._reflX(points1.x2) + ' ' + this._reflY(points1.y2) + ',' + | 301 | this._reflX(points1.x2, points1.y2) + ' ' + this._reflY(points1.x2, points1.y2) + ',' + |
302 | this._reflX(points1.x2) + ' ' + this._reflY(points1.y1) + ',' + | 302 | this._reflX(points1.x2, points1.y2) + ' ' + this._reflY(points1.x1, points1.y1) + ',' + |
303 | this._reflX(points1.x1) + ' ' + this._reflY(points1.y1) + ',' + | 303 | this._reflX(points1.x1, points1.y1) + ' ' + this._reflY(points1.x1, points1.y1) + ',' + |
304 | this._reflX(points1.x1) + ' ' + this._reflY(points1.y2) | 304 | this._reflX(points1.x1, points1.y1) + ' ' + this._reflY(points1.x2, points1.y2) |
305 | ) | 305 | ) |
306 | 306 | ||
307 | this.symPoly2.setAttribute('points', | 307 | this.symPoly2.setAttribute('points', |
308 | this._reflX(points2.x2) + ' ' + this._reflY(points2.y2) + ',' + | 308 | this._reflX(points2.x2, points2.y2) + ' ' + this._reflY(points2.x2, points2.y2) + ',' + |
309 | this._reflX(points2.x2) + ' ' + this._reflY(points2.y1) + ',' + | 309 | this._reflX(points2.x2, points2.y2) + ' ' + this._reflY(points2.x1, points2.y1) + ',' + |
310 | this._reflX(points2.x1) + ' ' + this._reflY(points2.y1) + ',' + | 310 | this._reflX(points2.x1, points2.y1) + ' ' + this._reflY(points2.x1, points2.y1) + ',' + |
311 | this._reflX(points2.x1) + ' ' + this._reflY(points2.y2) | 311 | this._reflX(points2.x1, points2.y1) + ' ' + this._reflY(points2.x2, points2.y2) |
312 | ) | 312 | ) |
313 | 313 | ||
314 | this.symCirc.setAttribute('opacity', this.circ.getAttribute('opacity')) | 314 | this.symCirc.setAttribute('opacity', this.circ.getAttribute('opacity')) |
@@ -316,24 +316,46 @@ class PathSegment { | |||
316 | } | 316 | } |
317 | } | 317 | } |
318 | 318 | ||
319 | _reflX(x) { | 319 | _reflX(x,y) { |
320 | if (data.puzzle.symmetry == null) return x | 320 | if (data.puzzle.symType == SYM_TYPE_NONE) return x |
321 | if (data.puzzle.symmetry.x === true) { | 321 | |
322 | if (data.puzzle.symType == SYM_TYPE_VERTICAL || data.puzzle.symType == SYM_TYPE_ROTATIONAL || data.puzzle.symType == SYM_TYPE_PARALLEL_H_FLIP) { | ||
322 | // Mirror position inside the bounding box | 323 | // Mirror position inside the bounding box |
323 | return (data.bbox.middle.x - x) + data.symbbox.middle.x | 324 | return (data.bbox.middle.x - x) + data.symbbox.middle.x |
324 | } | 325 | } |
325 | // Copy position inside the bounding box | 326 | if (data.puzzle.symType == SYM_TYPE_HORIZONTAL || data.puzzle.symType == SYM_TYPE_PARALLEL_H || data.puzzle.symType == SYM_TYPE_PARALLEL_V || data.puzzle.symType == SYM_TYPE_PARALLEL_V_FLIP) { |
326 | return (x - data.bbox.middle.x) + data.symbbox.middle.x | 327 | // Copy position inside the bounding box |
328 | return (x - data.bbox.middle.x) + data.symbbox.middle.x | ||
329 | } | ||
330 | if (data.puzzle.symType == SYM_TYPE_ROTATE_LEFT || data.puzzle.symType == SYM_TYPE_FLIP_XY) { | ||
331 | // Rotate position left inside the bounding box | ||
332 | return (y - data.bbox.middle.y) + data.symbbox.middle.x | ||
333 | } | ||
334 | if (data.puzzle.symType == SYM_TYPE_ROTATE_RIGHT || data.puzzle.symType == SYM_TYPE_FLIP_NEG_XY) { | ||
335 | // Rotate position right inside the bounding box | ||
336 | return (data.bbox.middle.y - y) + data.symbbox.middle.x | ||
337 | } | ||
327 | } | 338 | } |
328 | 339 | ||
329 | _reflY(y) { | 340 | _reflY(x,y) { |
330 | if (data.puzzle.symmetry == null) return y | 341 | if (data.puzzle.symType == SYM_TYPE_NONE) return y |
331 | if (data.puzzle.symmetry.y === true) { | 342 | |
343 | if (data.puzzle.symType == SYM_TYPE_HORIZONTAL || data.puzzle.symType == SYM_TYPE_ROTATIONAL || data.puzzle.symType == SYM_TYPE_PARALLEL_V_FLIP) { | ||
332 | // Mirror position inside the bounding box | 344 | // Mirror position inside the bounding box |
333 | return (data.bbox.middle.y - y) + data.symbbox.middle.y | 345 | return (data.bbox.middle.y - y) + data.symbbox.middle.y |
334 | } | 346 | } |
335 | // Copy position inside the bounding box | 347 | if (data.puzzle.symType == SYM_TYPE_VERTICAL || data.puzzle.symType == SYM_TYPE_PARALLEL_V || data.puzzle.symType == SYM_TYPE_PARALLEL_H || data.puzzle.symType == SYM_TYPE_PARALLEL_H_FLIP) { |
336 | return (y - data.bbox.middle.y) + data.symbbox.middle.y | 348 | // Copy position inside the bounding box |
349 | return (y - data.bbox.middle.y) + data.symbbox.middle.y | ||
350 | } | ||
351 | if (data.puzzle.symType == SYM_TYPE_ROTATE_RIGHT || data.puzzle.symType == SYM_TYPE_FLIP_XY) { | ||
352 | // Rotate position left inside the bounding box | ||
353 | return (x - data.bbox.middle.x) + data.symbbox.middle.y | ||
354 | } | ||
355 | if (data.puzzle.symType == SYM_TYPE_ROTATE_LEFT || data.puzzle.symType == SYM_TYPE_FLIP_NEG_XY) { | ||
356 | // Rotate position right inside the bounding box | ||
357 | return (data.bbox.middle.x - x) + data.symbbox.middle.y | ||
358 | } | ||
337 | } | 359 | } |
338 | } | 360 | } |
339 | 361 | ||
@@ -359,15 +381,29 @@ function clearGrid(svg, puzzle) { | |||
359 | 381 | ||
360 | // This copy is an exact copy of puzzle.getSymmetricalDir, except that it uses MOVE_* values instead of strings | 382 | // This copy is an exact copy of puzzle.getSymmetricalDir, except that it uses MOVE_* values instead of strings |
361 | function getSymmetricalDir(puzzle, dir) { | 383 | function getSymmetricalDir(puzzle, dir) { |
362 | if (puzzle.symmetry != null) { | 384 | if (puzzle.symType == SYM_TYPE_VERTICAL || puzzle.symType == SYM_TYPE_ROTATIONAL || puzzle.symType == SYM_TYPE_PARALLEL_H_FLIP) { |
363 | if (puzzle.symmetry.x === true) { | 385 | if (dir === MOVE_LEFT) return MOVE_RIGHT |
364 | if (dir === MOVE_LEFT) return MOVE_RIGHT | 386 | if (dir === MOVE_RIGHT) return MOVE_LEFT |
365 | if (dir === MOVE_RIGHT) return MOVE_LEFT | 387 | } |
366 | } | 388 | if (puzzle.symType == SYM_TYPE_HORIZONTAL || puzzle.symType == SYM_TYPE_ROTATIONAL || puzzle.symType == SYM_TYPE_PARALLEL_V_FLIP) { |
367 | if (puzzle.symmetry.y === true) { | 389 | if (dir === MOVE_TOP) return MOVE_BOTTOM |
368 | if (dir === MOVE_TOP) return MOVE_BOTTOM | 390 | if (dir === MOVE_BOTTOM) return MOVE_TOP |
369 | if (dir === MOVE_BOTTOM) return MOVE_TOP | 391 | } |
370 | } | 392 | if (puzzle.symType == SYM_TYPE_ROTATE_LEFT || puzzle.symType == SYM_TYPE_FLIP_NEG_XY) { |
393 | if (dir === MOVE_LEFT) return MOVE_BOTTOM | ||
394 | if (dir === MOVE_RIGHT) return MOVE_TOP | ||
395 | } | ||
396 | if (puzzle.symType == SYM_TYPE_ROTATE_RIGHT || puzzle.symType == SYM_TYPE_FLIP_NEG_XY) { | ||
397 | if (dir === MOVE_TOP) return MOVE_RIGHT | ||
398 | if (dir === MOVE_BOTTOM) return MOVE_LEFT | ||
399 | } | ||
400 | if (puzzle.symType == SYM_TYPE_ROTATE_LEFT || puzzle.symType == SYM_TYPE_FLIP_XY) { | ||
401 | if (dir === MOVE_TOP) return MOVE_LEFT | ||
402 | if (dir === MOVE_BOTTOM) return MOVE_RIGHT | ||
403 | } | ||
404 | if (puzzle.symType == SYM_TYPE_ROTATE_RIGHT || puzzle.symType == SYM_TYPE_FLIP_XY) { | ||
405 | if (dir === MOVE_RIGHT) return MOVE_BOTTOM | ||
406 | if (dir === MOVE_LEFT) return MOVE_TOP | ||
371 | } | 407 | } |
372 | return dir | 408 | return dir |
373 | } | 409 | } |
@@ -495,7 +531,7 @@ window.onTraceStart = function(puzzle, pos, svg, start, symStart=null) { | |||
495 | clearAnimations() | 531 | clearAnimations() |
496 | 532 | ||
497 | // Add initial line segments + secondary symmetry cursor, if needed | 533 | // Add initial line segments + secondary symmetry cursor, if needed |
498 | if (puzzle.symmetry == null) { | 534 | if (puzzle.symType == SYM_TYPE_NONE) { |
499 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'type', 'line') | 535 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'type', 'line') |
500 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_BLACK) | 536 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_BLACK) |
501 | } else { | 537 | } else { |
@@ -641,7 +677,7 @@ window.onMove = function(dx, dy) { | |||
641 | || (moveDir === MOVE_TOP && lastDir === MOVE_BOTTOM) | 677 | || (moveDir === MOVE_TOP && lastDir === MOVE_BOTTOM) |
642 | || (moveDir === MOVE_BOTTOM && lastDir === MOVE_TOP)) | 678 | || (moveDir === MOVE_BOTTOM && lastDir === MOVE_TOP)) |
643 | 679 | ||
644 | if (data.puzzle.symmetry != null) { | 680 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
645 | var symMoveDir = getSymmetricalDir(data.puzzle, moveDir) | 681 | var symMoveDir = getSymmetricalDir(data.puzzle, moveDir) |
646 | } | 682 | } |
647 | 683 | ||
@@ -649,21 +685,21 @@ window.onMove = function(dx, dy) { | |||
649 | if (backedUp) { | 685 | if (backedUp) { |
650 | data.path.pop().destroy() | 686 | data.path.pop().destroy() |
651 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_NONE) | 687 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_NONE) |
652 | if (data.puzzle.symmetry != null) { | 688 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
653 | data.puzzle.updateCell2(data.sym.x, data.sym.y, 'line', window.LINE_NONE) | 689 | data.puzzle.updateCell2(data.sym.x, data.sym.y, 'line', window.LINE_NONE) |
654 | } | 690 | } |
655 | } | 691 | } |
656 | 692 | ||
657 | // Move to the next cell | 693 | // Move to the next cell |
658 | changePos(data.bbox, data.pos, moveDir) | 694 | changePos(data.bbox, data.pos, moveDir) |
659 | if (data.puzzle.symmetry != null) { | 695 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
660 | changePos(data.symbbox, data.sym, symMoveDir) | 696 | changePos(data.symbbox, data.sym, symMoveDir) |
661 | } | 697 | } |
662 | 698 | ||
663 | // If we didn't back up, add a path segment and mark the new cell as visited | 699 | // If we didn't back up, add a path segment and mark the new cell as visited |
664 | if (!backedUp) { | 700 | if (!backedUp) { |
665 | data.path.push(new PathSegment(moveDir)) | 701 | data.path.push(new PathSegment(moveDir)) |
666 | if (data.puzzle.symmetry == null) { | 702 | if (data.puzzle.symType == SYM_TYPE_NONE) { |
667 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_BLACK) | 703 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_BLACK) |
668 | } else { | 704 | } else { |
669 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_BLUE) | 705 | data.puzzle.updateCell2(data.pos.x, data.pos.y, 'line', window.LINE_BLUE) |
@@ -849,7 +885,7 @@ function hardCollision() { | |||
849 | } | 885 | } |
850 | } | 886 | } |
851 | 887 | ||
852 | if (data.puzzle.symmetry != null) { | 888 | if (data.puzzle.symType != SYM_TYPE_NONE) { |
853 | if (data.sym.x === data.pos.x && data.sym.y === data.pos.y) { | 889 | if (data.sym.x === data.pos.x && data.sym.y === data.pos.y) { |
854 | console.spam('Collided with our symmetrical line') | 890 | console.spam('Collided with our symmetrical line') |
855 | gapSize = 13 | 891 | gapSize = 13 |
@@ -885,7 +921,7 @@ function move() { | |||
885 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_RIGHT) { | 921 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_RIGHT) { |
886 | console.spam('Collided with other line', cell.line) | 922 | console.spam('Collided with other line', cell.line) |
887 | data.x = data.bbox.x1 + 12 | 923 | data.x = data.bbox.x1 + 12 |
888 | } else if (data.puzzle.symmetry != null) { | 924 | } else if (data.puzzle.symType != SYM_TYPE_NONE) { |
889 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x - 1, data.pos.y) | 925 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x - 1, data.pos.y) |
890 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { | 926 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { |
891 | console.spam('Collided with symmetrical outside / gap-2', cell) | 927 | console.spam('Collided with symmetrical outside / gap-2', cell) |
@@ -903,7 +939,7 @@ function move() { | |||
903 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_LEFT) { | 939 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_LEFT) { |
904 | console.spam('Collided with other line', cell.line) | 940 | console.spam('Collided with other line', cell.line) |
905 | data.x = data.bbox.x2 - 12 | 941 | data.x = data.bbox.x2 - 12 |
906 | } else if (data.puzzle.symmetry != null) { | 942 | } else if (data.puzzle.symType != SYM_TYPE_NONE) { |
907 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x + 1, data.pos.y) | 943 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x + 1, data.pos.y) |
908 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { | 944 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { |
909 | console.spam('Collided with symmetrical outside / gap-2', cell) | 945 | console.spam('Collided with symmetrical outside / gap-2', cell) |
@@ -921,7 +957,7 @@ function move() { | |||
921 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_BOTTOM) { | 957 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_BOTTOM) { |
922 | console.spam('Collided with other line', cell.line) | 958 | console.spam('Collided with other line', cell.line) |
923 | data.y = data.bbox.y1 + 12 | 959 | data.y = data.bbox.y1 + 12 |
924 | } else if (data.puzzle.symmetry != null) { | 960 | } else if (data.puzzle.symType != SYM_TYPE_NONE) { |
925 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x, data.pos.y - 1) | 961 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x, data.pos.y - 1) |
926 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { | 962 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { |
927 | console.spam('Collided with symmetrical outside / gap-2', cell) | 963 | console.spam('Collided with symmetrical outside / gap-2', cell) |
@@ -939,7 +975,7 @@ function move() { | |||
939 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_TOP) { | 975 | } else if (cell.line > window.LINE_NONE && lastDir !== MOVE_TOP) { |
940 | console.spam('Collided with other line', cell.line) | 976 | console.spam('Collided with other line', cell.line) |
941 | data.y = data.bbox.y2 - 12 | 977 | data.y = data.bbox.y2 - 12 |
942 | } else if (data.puzzle.symmetry != null) { | 978 | } else if (data.puzzle.symType != SYM_TYPE_NONE) { |
943 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x, data.pos.y + 1) | 979 | var symCell = data.puzzle.getSymmetricalCell(data.pos.x, data.pos.y + 1) |
944 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { | 980 | if (symCell == null || symCell.type !== 'line' || symCell.gap === window.GAP_FULL) { |
945 | console.spam('Collided with symmetrical outside / gap-2', cell) | 981 | console.spam('Collided with symmetrical outside / gap-2', cell) |
diff --git a/app/assets/javascripts/wittle/validate.js b/app/assets/javascripts/wittle/validate.js index 333d2e1..d6e6484 100644 --- a/app/assets/javascripts/wittle/validate.js +++ b/app/assets/javascripts/wittle/validate.js | |||
@@ -41,7 +41,7 @@ window.validateUserData = function(puzzle, path) { | |||
41 | 41 | ||
42 | if (cell.start === true) { | 42 | if (cell.start === true) { |
43 | puzzleHasStart = true | 43 | puzzleHasStart = true |
44 | if (puzzle.symmetry != null) { | 44 | if (puzzle.symType != SYM_TYPE_NONE) { |
45 | var symCell = puzzle.getSymmetricalCell(x, y) | 45 | var symCell = puzzle.getSymmetricalCell(x, y) |
46 | if (symCell == null || symCell.start !== true) { | 46 | if (symCell == null || symCell.start !== true) { |
47 | throw Error('Startpoint at ' + x + ' ' + y + ' does not have a symmetrical startpoint') | 47 | throw Error('Startpoint at ' + x + ' ' + y + ' does not have a symmetrical startpoint') |
@@ -50,7 +50,7 @@ window.validateUserData = function(puzzle, path) { | |||
50 | } | 50 | } |
51 | if (cell.end != null) { | 51 | if (cell.end != null) { |
52 | puzzleHasEnd = true | 52 | puzzleHasEnd = true |
53 | if (puzzle.symmetry != null) { | 53 | if (puzzle.symType != SYM_TYPE_NONE) { |
54 | var symCell = puzzle.getSymmetricalCell(x, y) | 54 | var symCell = puzzle.getSymmetricalCell(x, y) |
55 | if (symCell == null || symCell.end == null || symCell.end != puzzle.getSymmetricalDir(cell.end)) { | 55 | if (symCell == null || symCell.end == null || symCell.end != puzzle.getSymmetricalDir(cell.end)) { |
56 | throw Error('Endpoint at ' + x + ' ' + y + ' does not have a symmetrical endpoint') | 56 | throw Error('Endpoint at ' + x + ' ' + y + ' does not have a symmetrical endpoint') |