Skip to content

Commit

Permalink
Implement Zipper lines.
Browse files Browse the repository at this point in the history
  • Loading branch information
sigh committed Mar 19, 2024
1 parent 07fc7e4 commit 744ce23
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 1 deletion.
10 changes: 10 additions & 0 deletions data/example_puzzles.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,16 @@ const EXAMPLES = {
input: '.~R1C1_1_2~R2C2_1_2_9~R2C4_1_3~R1C5_1_4_6~R2C5_8_9~R4C2_2_3~R5C2_7_9~R9C1_2_3~R7C3_8_9~R8C3_1_2_3_8_9~R6C3_6_7~R3C3_5_6_9~R4C4_3_4_5~R4C5_4_9~R5C5_6_7_8~R8C5_1_2~R7C4_4_6~R9C5_5_6~R1C6_6_9~R3C6_5_7~R4C6_6_9~R6C6_1_4_7~R8C6_1_8~R9C9_3_4_5~R8C8_2_8_9~R7C7_6_7_8~R6C8_4_8~R5C9_4_6~R4C7_5_6~R3C7_7_9~R2C8_1_2_3_5_8_9~R1C8_1_9~R1C9_1_3',
solution: '278569413916384752435127968123496587894275136567831249759643821642718395381952674',
},
'Zipper lines - easy': {
src: 'https://logic-masters.de/Raetselportal/Raetsel/zeigen.php?chlang=en&id=000FNA',
input: '.Zipper~R5C1~R5C2~R5C3.Zipper~R7C2~R7C1~R8C1~R9C1~R9C2~R9C3~R8C3.Zipper~R8C2~R7C3~R6C4~R7C5~R8C6.Zipper~R8C5~R9C5~R9C6~R9C7~R8C7~R7C7~R7C6.Zipper~R4C8~R4C7~R5C7~R6C7~R6C8~R6C9~R5C9.Zipper~R2C9~R3C9~R3C8~R3C7~R2C7~R1C7~R1C8.Zipper~R2C6~R1C6~R1C5~R1C4~R2C4~R3C4~R3C5.Zipper~R2C5~R3C6~R4C5.',
solution: '329764518547182396168359742695213487473598621281647935734825169856931274912476853',
},
'Zipper lines': {
src: 'https://www.youtube.com/watch?v=qP_oxUzGD5g',
input: '.Zipper~R1C2~R1C1~R2C1~R2C2~R3C2~R3C1~R4C1~R5C1~R4C2.Zipper~R2C3~R1C3~R1C4~R2C4~R3C4.Zipper~R2C6~R3C5~R3C6~R2C7~R1C6~R1C5.Zipper~R9C3~R8C2~R7C1~R6C1~R5C2~R4C3~R4C4~R5C4~R6C3.Zipper~R8C3~R7C3~R6C4~R6C5~R5C5~R4C5~R4C6~R5C6~R6C6~R6C7~R6C8~R6C9.Zipper~R5C7~R5C8~R4C7~R3C7~R2C8.Zipper~R7C5~R7C6~R8C6~R8C7~R7C7~R7C8~R7C9~R8C9~R9C9~R9C8~R9C7~R9C6~R9C5~R8C5.',
solution: '354897126672451839189632574231564987597328641846719352415973268968245713723186495'
},

// Classic grids that used to be slow. 3 and 4 used to take 2+ seconds.
'Classic sudoku, was slow (1)': {
Expand Down
1 change: 1 addition & 0 deletions js/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ const runSolveTests = async (onFailure) => {
'Quadruple - repeated values',
'Odd-even thermo',
'Nabner thermo - easy',
'Zipper lines - easy',
], onFailure);
result.collection = '9x9';
results.push(result);
Expand Down
17 changes: 16 additions & 1 deletion js/render_page.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class ExampleHandler {
'Between lines',
'Lockout lines',
'Palindromes',
'Zipper lines',
'Jigsaw',
'X-Windoku',
'Region sum lines',
Expand Down Expand Up @@ -731,6 +732,7 @@ class ConstraintManager {
case 'Modular':
case 'Entropic':
case 'Palindrome':
case 'Zipper':
case 'Between':
case 'Lockout':
case 'RegionSumLine':
Expand Down Expand Up @@ -1024,10 +1026,23 @@ class ConstraintManager {
},
Palindrome: {
text: 'Palindrome',
displayConfig: { color: 'rgb(200, 200, 255)' },
displayConfig: {
color: 'rgb(200, 200, 255)'
},
description:
"The values along the line form a palindrome."
},
Zipper: {
text: 'Zipper Line',
displayConfig: {
color: 'rgb(200, 200, 255)',
},
description:
`
Digits which are equal distance from the center of the zipper have the
same sum. For odd length lines, the center digit is the sum.
`
},
WhiteDot: {
validateFn: ConstraintManager._cellsAreAdjacent,
text: '○ ±1',
Expand Down
38 changes: 38 additions & 0 deletions js/sudoku_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,13 @@ class SudokuConstraint {
);
}

static Zipper = class Zipper extends SudokuConstraintBase {
constructor(...cells) {
super(arguments);
this.cells = cells;
}
}

static NoBoxes = class NoBoxes extends SudokuConstraintBase._Meta { }
static StrictKropki = class StrictKropki extends SudokuConstraintBase._Meta {
static fnKey = memoize((numValues) =>
Expand Down Expand Up @@ -1386,6 +1393,37 @@ class SudokuBuilder {
SudokuConstraint.Palindrome.fnKey(shape.numValues));
}
break;
case 'Zipper':
cells = constraint.cells.map(c => shape.parseCellId(c).cell);
{
const pairs = [];
const numCells = cells.length;
for (let i = 0; i < ((numCells / 2) | 0); i++) {
pairs.push([cells[i], cells[numCells - 1 - i]]);
}
if (numCells % 2 == 1) {
// If there are an odd numbers of cells, then treat this as a
// set of arrows from the center cell to each pair.
// We don't bother to also add constraints between each pair, as
// the constraint on the total sum should propagate through the
// center cell.
const centerCell = [cells[(numCells / 2) | 0]];
for (const pair of pairs) {
yield new SudokuConstraintHandler.SumWithNegative(
pair, centerCell, 0);
}
} else {
// Otherwise create an equal sum constraint between each pair.
const numPairs = pairs.length;
for (let i = 1; i < numPairs; i++) {
for (let j = 0; j < i; j++) {
yield new SudokuConstraintHandler.SumWithNegative(
pairs[i], pairs[j], 0);
}
}
}
}
break;

case 'WhiteDot':
cells = constraint.cells.map(c => shape.parseCellId(c).cell);
Expand Down

0 comments on commit 744ce23

Please sign in to comment.