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 | |
| parent | 13dfac7905faac21ea98b08a0948104df8411d42 (diff) | |
| download | wittle-00641f16c889093b32b8e97a6050817f6fe43780.tar.gz wittle-00641f16c889093b32b8e97a6050817f6fe43780.tar.bz2 wittle-00641f16c889093b32b8e97a6050817f6fe43780.zip | |
added weird symmetries (and some more puzzles)
| -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 | ||||
| -rw-r--r-- | ext/wittle_generator/Panel.cpp | 8 | ||||
| -rw-r--r-- | ext/wittle_generator/Panel.h | 32 | ||||
| -rw-r--r-- | ext/wittle_generator/wittle_generator.cpp | 116 |
9 files changed, 313 insertions, 108 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') |
| diff --git a/ext/wittle_generator/Panel.cpp b/ext/wittle_generator/Panel.cpp index 879d205..3279943 100644 --- a/ext/wittle_generator/Panel.cpp +++ b/ext/wittle_generator/Panel.cpp | |||
| @@ -127,12 +127,6 @@ std::string Panel::Write() { | |||
| 127 | int genericFlags = 0; | 127 | int genericFlags = 0; |
| 128 | if (symmetry != Symmetry::None) { | 128 | if (symmetry != Symmetry::None) { |
| 129 | genericFlags |= Serializer::Symmetrical; | 129 | genericFlags |= Serializer::Symmetrical; |
| 130 | if (symmetry == Symmetry::Vertical || symmetry == Symmetry::Rotational) { | ||
| 131 | genericFlags |= Serializer::SymmetryX; | ||
| 132 | } | ||
| 133 | if (symmetry == Symmetry::Horizontal || symmetry == Symmetry::Rotational) { | ||
| 134 | genericFlags |= Serializer::SymmetryY; | ||
| 135 | } | ||
| 136 | } | 130 | } |
| 137 | serializer.writeByte(genericFlags); | 131 | serializer.writeByte(genericFlags); |
| 138 | 132 | ||
| @@ -233,5 +227,7 @@ std::string Panel::Write() { | |||
| 233 | } | 227 | } |
| 234 | serializer.writeByte(settings); | 228 | serializer.writeByte(settings); |
| 235 | 229 | ||
| 230 | serializer.writeByte(symmetry); | ||
| 231 | |||
| 236 | return serializer.str(); | 232 | return serializer.str(); |
| 237 | } | 233 | } |
| diff --git a/ext/wittle_generator/Panel.h b/ext/wittle_generator/Panel.h index d152370..3bc23c9 100644 --- a/ext/wittle_generator/Panel.h +++ b/ext/wittle_generator/Panel.h | |||
| @@ -188,22 +188,22 @@ class Panel { | |||
| 188 | 188 | ||
| 189 | enum Symmetry { // NOTE - Not all of these are valid symmetries for certain | 189 | enum Symmetry { // NOTE - Not all of these are valid symmetries for certain |
| 190 | // puzzles | 190 | // puzzles |
| 191 | None, | 191 | None = 0, |
| 192 | Horizontal, | 192 | Horizontal = 1, |
| 193 | Vertical, | 193 | Vertical = 2, |
| 194 | Rotational, | 194 | Rotational = 3, |
| 195 | RotateLeft, | 195 | RotateLeft = 4, |
| 196 | RotateRight, | 196 | RotateRight = 5, |
| 197 | FlipXY, | 197 | FlipXY = 6, |
| 198 | FlipNegXY, | 198 | FlipNegXY = 7, |
| 199 | ParallelH, | 199 | ParallelH = 8, |
| 200 | ParallelV, | 200 | ParallelV = 9, |
| 201 | ParallelHFlip, | 201 | ParallelHFlip = 10, |
| 202 | ParallelVFlip, | 202 | ParallelVFlip = 11, |
| 203 | PillarParallel, | 203 | PillarParallel = 12, |
| 204 | PillarHorizontal, | 204 | PillarHorizontal = 13, |
| 205 | PillarVertical, | 205 | PillarVertical = 14, |
| 206 | PillarRotational | 206 | PillarRotational = 15, |
| 207 | }; | 207 | }; |
| 208 | Symmetry symmetry; | 208 | Symmetry symmetry; |
| 209 | 209 | ||
| diff --git a/ext/wittle_generator/wittle_generator.cpp b/ext/wittle_generator/wittle_generator.cpp index c2407cf..0efac07 100644 --- a/ext/wittle_generator/wittle_generator.cpp +++ b/ext/wittle_generator/wittle_generator.cpp | |||
| @@ -420,7 +420,7 @@ Rice::Object wittle_generator_generate_easy(Rice::Object /* self */) { | |||
| 420 | Rice::Object wittle_generator_generate_medium(Rice::Object /* self */) { | 420 | Rice::Object wittle_generator_generate_medium(Rice::Object /* self */) { |
| 421 | Generate generator; | 421 | Generate generator; |
| 422 | 422 | ||
| 423 | int choice = Random::rand() % 66; | 423 | int choice = Random::rand() % 69; |
| 424 | std::cout << "Generate MEDIUM: choice " << std::dec << choice << std::endl; | 424 | std::cout << "Generate MEDIUM: choice " << std::dec << choice << std::endl; |
| 425 | 425 | ||
| 426 | switch (choice) { | 426 | switch (choice) { |
| @@ -1015,6 +1015,33 @@ Rice::Object wittle_generator_generate_medium(Rice::Object /* self */) { | |||
| 1015 | {Decoration::Dot_Intersection, 25}}}); | 1015 | {Decoration::Dot_Intersection, 25}}}); |
| 1016 | break; | 1016 | break; |
| 1017 | } | 1017 | } |
| 1018 | case 66: { | ||
| 1019 | generator.setSymmetry(Panel::Symmetry::FlipNegXY); | ||
| 1020 | generator.generate(7, 7, | ||
| 1021 | {{{Decoration::Gap, 10}, | ||
| 1022 | {Decoration::Dot_Intersection, 8}, | ||
| 1023 | {Decoration::Start, 2}, | ||
| 1024 | {Decoration::Exit, 1}}}); | ||
| 1025 | break; | ||
| 1026 | } | ||
| 1027 | case 67: { | ||
| 1028 | generator.setSymmetry(Panel::Symmetry::ParallelV); | ||
| 1029 | generator.generate(7, 7, | ||
| 1030 | {{{Decoration::Gap, 12}, | ||
| 1031 | {Decoration::Dot_Intersection, 10}, | ||
| 1032 | {Decoration::Start, 2}, | ||
| 1033 | {Decoration::Exit, 1}}}); | ||
| 1034 | break; | ||
| 1035 | } | ||
| 1036 | case 68: { | ||
| 1037 | generator.setSymmetry(Panel::Symmetry::ParallelHFlip); | ||
| 1038 | generator.generate(7, 7, | ||
| 1039 | {{{Decoration::Gap, 12}, | ||
| 1040 | {Decoration::Dot_Intersection, 10}, | ||
| 1041 | {Decoration::Start, 2}, | ||
| 1042 | {Decoration::Exit, 1}}}); | ||
| 1043 | break; | ||
| 1044 | } | ||
| 1018 | } | 1045 | } |
| 1019 | 1046 | ||
| 1020 | Rice::String str(generator.AsCode()); | 1047 | Rice::String str(generator.AsCode()); |
| @@ -1024,7 +1051,7 @@ Rice::Object wittle_generator_generate_medium(Rice::Object /* self */) { | |||
| 1024 | Rice::Object wittle_generator_generate_expert(Rice::Object /* self */) { | 1051 | Rice::Object wittle_generator_generate_expert(Rice::Object /* self */) { |
| 1025 | Generate generator; | 1052 | Generate generator; |
| 1026 | 1053 | ||
| 1027 | int choice = Random::rand() % 40; | 1054 | int choice = Random::rand() % 46; |
| 1028 | std::cout << "Generate EXPERT: choice " << std::dec << choice << std::endl; | 1055 | std::cout << "Generate EXPERT: choice " << std::dec << choice << std::endl; |
| 1029 | 1056 | ||
| 1030 | switch (choice) { | 1057 | switch (choice) { |
| @@ -1497,6 +1524,91 @@ Rice::Object wittle_generator_generate_expert(Rice::Object /* self */) { | |||
| 1497 | {Decoration::Dot_Intersection, 36}}}); | 1524 | {Decoration::Dot_Intersection, 36}}}); |
| 1498 | break; | 1525 | break; |
| 1499 | } | 1526 | } |
| 1527 | case 40: { | ||
| 1528 | generator.setGridSize(7, 7); | ||
| 1529 | generator.setFlag(Generate::RequireCombineShapes); | ||
| 1530 | generator.setSymmetry(Panel::ParallelV); | ||
| 1531 | generator.setSymbol(Decoration::Start, 0, 14); | ||
| 1532 | generator.setSymbol(Decoration::Start, 8, 14); | ||
| 1533 | generator.setSymbol(Decoration::Exit, 6, 0); | ||
| 1534 | generator.setSymbol(Decoration::Exit, 14, 0); | ||
| 1535 | generator.generate(7, 7, | ||
| 1536 | {{{Decoration::Poly | Decoration::Color::Orange, 5}}}); | ||
| 1537 | break; | ||
| 1538 | } | ||
| 1539 | case 41: { | ||
| 1540 | generator.setGridSize(7, 7); | ||
| 1541 | generator.setFlag(Generate::RequireCombineShapes); | ||
| 1542 | generator.setSymmetry(Panel::ParallelHFlip); | ||
| 1543 | generator.setSymbol(Decoration::Start, 0, 14); | ||
| 1544 | generator.setSymbol(Decoration::Start, 14, 6); | ||
| 1545 | generator.setSymbol(Decoration::Exit, 0, 0); | ||
| 1546 | generator.setSymbol(Decoration::Exit, 14, 8); | ||
| 1547 | generator.generate(7, 7, | ||
| 1548 | {{{Decoration::Poly | Decoration::Color::Orange, 5}}}); | ||
| 1549 | break; | ||
| 1550 | } | ||
| 1551 | case 42: { | ||
| 1552 | generator.setGridSize(7, 7); | ||
| 1553 | generator.setFlag(Generate::RequireCombineShapes); | ||
| 1554 | generator.setSymmetry(Panel::ParallelVFlip); | ||
| 1555 | generator.setSymbol(Decoration::Start, 0, 14); | ||
| 1556 | generator.setSymbol(Decoration::Start, 8, 0); | ||
| 1557 | generator.setSymbol(Decoration::Exit, 6, 0); | ||
| 1558 | generator.setSymbol(Decoration::Exit, 14, 14); | ||
| 1559 | generator.generate(7, 7, | ||
| 1560 | {{{Decoration::Poly | Decoration::Color::Orange, 5}}}); | ||
| 1561 | break; | ||
| 1562 | } | ||
| 1563 | case 43: { | ||
| 1564 | generator.setSymmetry(Panel::Symmetry::RotateLeft); | ||
| 1565 | generator.setSymbol(Decoration::Start, 4, 4); | ||
| 1566 | generator.setSymbol(Decoration::Start, 10, 4); | ||
| 1567 | generator.setSymbol(Decoration::Start, 4, 10); | ||
| 1568 | generator.setSymbol(Decoration::Start, 10, 10); | ||
| 1569 | generator.setSymbol(Decoration::Exit, 4, 0); | ||
| 1570 | generator.setSymbol(Decoration::Exit, 14, 4); | ||
| 1571 | generator.setSymbol(Decoration::Exit, 0, 10); | ||
| 1572 | generator.setSymbol(Decoration::Exit, 10, 14); | ||
| 1573 | generator.generate( | ||
| 1574 | 7, 7, | ||
| 1575 | {{{Decoration::Triangle4 | Decoration::Color::Orange, 1}, | ||
| 1576 | {Decoration::Triangle | Decoration::Color::Orange, 4}}}); | ||
| 1577 | break; | ||
| 1578 | } | ||
| 1579 | case 44: { | ||
| 1580 | generator.setFlag(Generate::WriteInvisible); | ||
| 1581 | generator.setFlag(Generate::StartEdgeOnly); | ||
| 1582 | generator.setSymmetry(Panel::Symmetry::FlipXY); | ||
| 1583 | generator.setSymbol(Decoration::Exit, 0, 8); | ||
| 1584 | generator.setSymbol(Decoration::Exit, 8, 0); | ||
| 1585 | generator.generate(7, 7, | ||
| 1586 | {{{Decoration::Dot | Decoration::Color::Blue, 2}, | ||
| 1587 | {Decoration::Dot | Decoration::Color::Yellow, 2}, | ||
| 1588 | {Decoration::Dot, 8}, | ||
| 1589 | {Decoration::Eraser | Decoration::Color::White, 1}, | ||
| 1590 | {Decoration::Start, 1}}}); | ||
| 1591 | break; | ||
| 1592 | } | ||
| 1593 | case 45: { | ||
| 1594 | generator.setFlag(Generate::WriteInvisible); | ||
| 1595 | generator.setSymmetry(Panel::Symmetry::FlipXY); | ||
| 1596 | generator.setSymbol(Decoration::Start, 0, 16); | ||
| 1597 | generator.setSymbol(Decoration::Start, 16, 0); | ||
| 1598 | generator.setSymbol(Decoration::Exit, 8, 0); | ||
| 1599 | generator.setSymbol(Decoration::Exit, 8, 16); | ||
| 1600 | generator.setSymbol(Decoration::Exit, 0, 8); | ||
| 1601 | generator.setSymbol(Decoration::Exit, 16, 8); | ||
| 1602 | generator.generate( | ||
| 1603 | 8, 8, | ||
| 1604 | {{{Decoration::Triangle | Decoration::Color::Cyan, 3}, | ||
| 1605 | {Decoration::Triangle | Decoration::Color::Yellow, 2}, | ||
| 1606 | {Decoration::Star | Decoration::Color::Cyan, 3}, | ||
| 1607 | {Decoration::Star | Decoration::Color::Yellow, 3}, | ||
| 1608 | {Decoration::Stone | Decoration::Color::Cyan, 2}, | ||
| 1609 | {Decoration::Stone | Decoration::Color::Yellow, 3}}}); | ||
| 1610 | break; | ||
| 1611 | } | ||
| 1500 | } | 1612 | } |
| 1501 | 1613 | ||
| 1502 | Rice::String str(generator.AsCode()); | 1614 | Rice::String str(generator.AsCode()); |
