about summary refs log tree commit diff stats
path: root/app
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2023-11-03 00:18:41 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2023-11-03 00:18:41 -0400
commit00641f16c889093b32b8e97a6050817f6fe43780 (patch)
tree33d0279af22ac028472d5eda0b535b58757dbc05 /app
parent13dfac7905faac21ea98b08a0948104df8411d42 (diff)
downloadwittle-00641f16c889093b32b8e97a6050817f6fe43780.tar.gz
wittle-00641f16c889093b32b8e97a6050817f6fe43780.tar.bz2
wittle-00641f16c889093b32b8e97a6050817f6fe43780.zip
added weird symmetries (and some more puzzles)
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/wittle/display2.js19
-rw-r--r--app/assets/javascripts/wittle/puzzle.js74
-rw-r--r--app/assets/javascripts/wittle/serializer.js22
-rw-r--r--app/assets/javascripts/wittle/solve.js12
-rw-r--r--app/assets/javascripts/wittle/trace2.js134
-rw-r--r--app/assets/javascripts/wittle/validate.js4
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 @@
1var SYM_TYPE_NONE = 0
2var SYM_TYPE_HORIZONTAL = 1
3var SYM_TYPE_VERTICAL = 2
4var SYM_TYPE_ROTATIONAL = 3
5var SYM_TYPE_ROTATE_LEFT = 4
6var SYM_TYPE_ROTATE_RIGHT = 5
7var SYM_TYPE_FLIP_XY = 6
8var SYM_TYPE_FLIP_NEG_XY = 7
9var SYM_TYPE_PARALLEL_H = 8
10var SYM_TYPE_PARALLEL_V = 9
11var SYM_TYPE_PARALLEL_H_FLIP = 10
12var SYM_TYPE_PARALLEL_V_FLIP = 11
13var SYM_TYPE_PILLAR_PARALLEL = 12
14var SYM_TYPE_PILLAR_HORIZONTAL = 13
15var SYM_TYPE_PILLAR_VERTICAL = 14
16var SYM_TYPE_PILLAR_ROTATIONAL = 15
17
1namespace(function() { 18namespace(function() {
2 19
3window.draw = function(puzzle, target='puzzle') { 20window.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) {
207function tailRecurse(x, y) { 207function 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
361function getSymmetricalDir(puzzle, dir) { 383function 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')