@logic-pad/core 0.4.6 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/logic-core.global.d.ts +134 -25
- package/dist/data/grid.d.ts +44 -14
- package/dist/data/grid.js +43 -36
- package/dist/data/primitives.d.ts +19 -1
- package/dist/data/primitives.js +20 -0
- package/dist/data/rules/banPatternRule.js +1 -1
- package/dist/data/rules/customRule.js +1 -1
- package/dist/data/rules/lyingSymbolRule.d.ts +30 -0
- package/dist/data/rules/lyingSymbolRule.js +239 -0
- package/dist/data/rules/musicGridRule.js +1 -1
- package/dist/data/rules/mysteryRule.js +2 -2
- package/dist/data/rules/offByXRule.d.ts +1 -1
- package/dist/data/rules/offByXRule.js +7 -3
- package/dist/data/rules/regionAreaRule.js +3 -3
- package/dist/data/rules/rules.gen.d.ts +1 -0
- package/dist/data/rules/rules.gen.js +1 -0
- package/dist/data/serializer/serializer_v0.js +1 -1
- package/dist/data/solver/allSolvers.js +2 -2
- package/dist/data/solver/backtrack/backtrackSolver.d.ts +3 -4
- package/dist/data/solver/backtrack/backtrackSolver.js +4 -30
- package/dist/data/solver/backtrack/backtrackWorker.d.ts +1 -2
- package/dist/data/solver/backtrack/backtrackWorker.js +12 -8
- package/dist/data/solver/eventIteratingSolver.d.ts +6 -0
- package/dist/data/solver/eventIteratingSolver.js +33 -0
- package/dist/data/solver/solver.d.ts +6 -1
- package/dist/data/solver/solver.js +2 -1
- package/dist/data/solver/universal/universalSolver.d.ts +7 -0
- package/dist/data/solver/universal/universalSolver.js +30 -0
- package/dist/data/solver/universal/universalWorker.d.ts +1 -0
- package/dist/data/solver/universal/universalWorker.js +119 -0
- package/dist/data/symbols/customIconSymbol.js +2 -2
- package/dist/data/symbols/customTextSymbol.js +2 -2
- package/dist/data/validate.d.ts +1 -1
- package/dist/data/validate.js +3 -3
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/package.json +1 -1
- package/dist/data/solver/underclued/undercluedSolver.d.ts +0 -8
- package/dist/data/solver/underclued/undercluedSolver.js +0 -55
- package/dist/data/solver/underclued/undercluedWorker.d.ts +0 -2
- package/dist/data/solver/underclued/undercluedWorker.js +0 -135
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Color, State } from '../../primitives.js';
|
|
2
|
+
import { Serializer } from '../../serializer/allSerializers.js';
|
|
3
|
+
import { instance as undercluedInstance } from '../../rules/undercluedRule.js';
|
|
4
|
+
import { array } from '../../dataHelper.js';
|
|
5
|
+
import validateGrid from '../../validate.js';
|
|
6
|
+
function gridToRawTiles(grid) {
|
|
7
|
+
return array(grid.width, grid.height, (x, y) => grid.getTile(x, y).color);
|
|
8
|
+
}
|
|
9
|
+
function rawTilesToGrid(rawTiles, grid) {
|
|
10
|
+
return grid.fastCopyWith({
|
|
11
|
+
tiles: array(grid.width, grid.height, (x, y) => grid.getTile(x, y).withColor(rawTiles[y][x])),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function getNextTile(grid, rawTiles) {
|
|
15
|
+
for (let y = 0; y < grid.height; y++) {
|
|
16
|
+
for (let x = 0; x < grid.width; x++) {
|
|
17
|
+
const tile = grid.getTile(x, y);
|
|
18
|
+
if (!tile.exists || tile.fixed)
|
|
19
|
+
continue;
|
|
20
|
+
if (rawTiles[y][x] === Color.Gray)
|
|
21
|
+
return [{ x, y }, Color.Dark];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
function backtrack(grid, rawTiles, submitSolution) {
|
|
27
|
+
// Find the best empty cell to guess
|
|
28
|
+
const target = getNextTile(grid, rawTiles);
|
|
29
|
+
// Found a solution
|
|
30
|
+
if (!target)
|
|
31
|
+
return !submitSolution(rawTiles);
|
|
32
|
+
const [pos, color] = target;
|
|
33
|
+
const positions = grid.connections.getConnectedTiles(pos);
|
|
34
|
+
for (let i = 0; i <= 1; i++) {
|
|
35
|
+
const tile = i === 0 ? color : color === Color.Dark ? Color.Light : Color.Dark;
|
|
36
|
+
positions.forEach(({ x, y }) => (rawTiles[y][x] = tile));
|
|
37
|
+
const newGrid = rawTilesToGrid(rawTiles, grid);
|
|
38
|
+
const isValid = validateGrid(newGrid, null);
|
|
39
|
+
if (isValid.final !== State.Error &&
|
|
40
|
+
backtrack(newGrid, rawTiles, submitSolution))
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
positions.forEach(({ x, y }) => (rawTiles[y][x] = Color.Gray));
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
function solveNormal(input, submitSolution) {
|
|
47
|
+
// Call backtrack
|
|
48
|
+
backtrack(input, gridToRawTiles(input), rawTiles => submitSolution(rawTiles ? rawTilesToGrid(rawTiles, input) : null));
|
|
49
|
+
}
|
|
50
|
+
function solveUnderclued(input) {
|
|
51
|
+
let grid = input;
|
|
52
|
+
const possibles = array(grid.width, grid.height, () => ({
|
|
53
|
+
dark: false,
|
|
54
|
+
light: false,
|
|
55
|
+
}));
|
|
56
|
+
function search(x, y, tile, color) {
|
|
57
|
+
const newGrid = grid.fastCopyWith({
|
|
58
|
+
tiles: grid.setTile(x, y, tile.withColor(color)),
|
|
59
|
+
});
|
|
60
|
+
// Solve
|
|
61
|
+
let solution;
|
|
62
|
+
solveNormal(newGrid, sol => {
|
|
63
|
+
solution = sol;
|
|
64
|
+
return false;
|
|
65
|
+
});
|
|
66
|
+
if (!solution)
|
|
67
|
+
return false;
|
|
68
|
+
// Update the new possible states
|
|
69
|
+
solution.forEach((solTile, solX, solY) => {
|
|
70
|
+
if (solTile.color === Color.Dark) {
|
|
71
|
+
possibles[solY][solX].dark = true;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
possibles[solY][solX].light = true;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
for (let y = 0; y < grid.height; y++) {
|
|
80
|
+
for (let x = 0; x < grid.width; x++) {
|
|
81
|
+
const tile = grid.getTile(x, y);
|
|
82
|
+
if (!tile.exists || tile.color !== Color.Gray)
|
|
83
|
+
continue;
|
|
84
|
+
// We can skip this solve if it is proved to be solvable
|
|
85
|
+
const darkPossible = possibles[y][x].dark || search(x, y, tile, Color.Dark);
|
|
86
|
+
const lightPossible = possibles[y][x].light || search(x, y, tile, Color.Light);
|
|
87
|
+
// No solution
|
|
88
|
+
if (!darkPossible && !lightPossible)
|
|
89
|
+
return null;
|
|
90
|
+
if (darkPossible && !lightPossible)
|
|
91
|
+
grid = grid.fastCopyWith({
|
|
92
|
+
tiles: grid.setTile(x, y, tile.withColor(Color.Dark)),
|
|
93
|
+
});
|
|
94
|
+
if (!darkPossible && lightPossible)
|
|
95
|
+
grid = grid.fastCopyWith({
|
|
96
|
+
tiles: grid.setTile(x, y, tile.withColor(Color.Light)),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return grid;
|
|
101
|
+
}
|
|
102
|
+
function solve(grid, submitSolution) {
|
|
103
|
+
if (grid.findRule(rule => rule.id === undercluedInstance.id)) {
|
|
104
|
+
submitSolution(solveUnderclued(grid));
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
solveNormal(grid, submitSolution);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
onmessage = e => {
|
|
111
|
+
const grid = Serializer.parseGrid(e.data);
|
|
112
|
+
let count = 0;
|
|
113
|
+
solve(grid, solution => {
|
|
114
|
+
postMessage(solution ? Serializer.stringifyGrid(solution) : null);
|
|
115
|
+
count += 1;
|
|
116
|
+
return count < 2;
|
|
117
|
+
});
|
|
118
|
+
postMessage(null);
|
|
119
|
+
};
|
|
@@ -49,7 +49,7 @@ Object.defineProperty(CustomIconSymbol, "EXAMPLE_GRID", {
|
|
|
49
49
|
enumerable: true,
|
|
50
50
|
configurable: true,
|
|
51
51
|
writable: true,
|
|
52
|
-
value: Object.freeze(
|
|
52
|
+
value: Object.freeze(GridData.create(5, 4))
|
|
53
53
|
});
|
|
54
54
|
Object.defineProperty(CustomIconSymbol, "CONFIGS", {
|
|
55
55
|
enumerable: true,
|
|
@@ -102,4 +102,4 @@ Object.defineProperty(CustomIconSymbol, "CONFIGS", {
|
|
|
102
102
|
])
|
|
103
103
|
});
|
|
104
104
|
export default CustomIconSymbol;
|
|
105
|
-
export const instance = new CustomIconSymbol('A *custom* icon symbol',
|
|
105
|
+
export const instance = new CustomIconSymbol('A *custom* icon symbol', GridData.create(5, 4), 0, 0, 'MdQuestionMark');
|
|
@@ -49,7 +49,7 @@ Object.defineProperty(CustomTextSymbol, "EXAMPLE_GRID", {
|
|
|
49
49
|
enumerable: true,
|
|
50
50
|
configurable: true,
|
|
51
51
|
writable: true,
|
|
52
|
-
value: Object.freeze(
|
|
52
|
+
value: Object.freeze(GridData.create(5, 4))
|
|
53
53
|
});
|
|
54
54
|
Object.defineProperty(CustomTextSymbol, "CONFIGS", {
|
|
55
55
|
enumerable: true,
|
|
@@ -103,4 +103,4 @@ Object.defineProperty(CustomTextSymbol, "CONFIGS", {
|
|
|
103
103
|
])
|
|
104
104
|
});
|
|
105
105
|
export default CustomTextSymbol;
|
|
106
|
-
export const instance = new CustomTextSymbol('A *custom* text symbol',
|
|
106
|
+
export const instance = new CustomTextSymbol('A *custom* text symbol', GridData.create(5, 4), 0, 0, 'X');
|
package/dist/data/validate.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import GridData from './grid.js';
|
|
2
2
|
import { GridState, RuleState, State } from './primitives.js';
|
|
3
|
-
export declare function aggregateState(rules: RuleState[], grid: GridData, symbols:
|
|
3
|
+
export declare function aggregateState(rules: readonly RuleState[], grid: GridData, symbols: ReadonlyMap<string, State[]>): State.Error | State.Satisfied | State.Incomplete;
|
|
4
4
|
export declare function applyFinalOverrides(grid: GridData, solution: GridData | null, state: GridState): GridState;
|
|
5
5
|
export default function validateGrid(grid: GridData, solution: GridData | null): GridState;
|
package/dist/data/validate.js
CHANGED
|
@@ -72,18 +72,18 @@ export default function validateGrid(grid, solution) {
|
|
|
72
72
|
return;
|
|
73
73
|
if (states.some(s => s === State.Error))
|
|
74
74
|
ruleStates[i] = { state: State.Error, positions: [] };
|
|
75
|
-
else if (states.length > 0 && states.every(s =>
|
|
75
|
+
else if (states.length > 0 && states.every(s => State.isSatisfied(s)))
|
|
76
76
|
ruleStates[i] = { state: State.Satisfied };
|
|
77
77
|
});
|
|
78
78
|
let final = aggregateState(ruleStates, grid, symbolStates);
|
|
79
79
|
// in addition to satisfying all rules and symbols, a solution must also fill the grid completely
|
|
80
|
-
if (!requireSolution &&
|
|
80
|
+
if (!requireSolution && State.isSatisfied(final)) {
|
|
81
81
|
final = grid.forEach(tile => tile.exists && tile.color === Color.Gray ? true : undefined)
|
|
82
82
|
? State.Incomplete
|
|
83
83
|
: State.Satisfied;
|
|
84
84
|
}
|
|
85
85
|
// return early if there is no need to validate against a solution
|
|
86
|
-
if (
|
|
86
|
+
if (State.isSatisfied(final) ||
|
|
87
87
|
!requireSolution ||
|
|
88
88
|
!solution ||
|
|
89
89
|
solution.width !== grid.width ||
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ import ConnectAllRule from './data/rules/connectAllRule.js';
|
|
|
22
22
|
import CustomRule from './data/rules/customRule.js';
|
|
23
23
|
import ForesightRule from './data/rules/foresightRule.js';
|
|
24
24
|
import { allRules } from './data/rules/index.js';
|
|
25
|
+
import LyingSymbolRule from './data/rules/lyingSymbolRule.js';
|
|
25
26
|
import { ControlLine, Row } from './data/rules/musicControlLine.js';
|
|
26
27
|
import MusicGridRule from './data/rules/musicGridRule.js';
|
|
27
28
|
import MysteryRule from './data/rules/mysteryRule.js';
|
|
@@ -63,8 +64,9 @@ import LotusBTModule from './data/solver/backtrack/symbols/lotus.js';
|
|
|
63
64
|
import MinesweeperBTModule from './data/solver/backtrack/symbols/minesweeper.js';
|
|
64
65
|
import MyopiaBTModule from './data/solver/backtrack/symbols/myopia.js';
|
|
65
66
|
import ViewpointBTModule from './data/solver/backtrack/symbols/viewpoint.js';
|
|
67
|
+
import EventIteratingSolver from './data/solver/eventIteratingSolver.js';
|
|
66
68
|
import Solver from './data/solver/solver.js';
|
|
67
|
-
import
|
|
69
|
+
import UniversalSolver from './data/solver/universal/universalSolver.js';
|
|
68
70
|
import AreaNumberModule from './data/solver/z3/modules/areaNumberModule.js';
|
|
69
71
|
import CellCountModule from './data/solver/z3/modules/cellCountModule.js';
|
|
70
72
|
import ConnectAllModule from './data/solver/z3/modules/connectAllModule.js';
|
|
@@ -98,4 +100,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
98
100
|
import TileData from './data/tile.js';
|
|
99
101
|
import TileConnections from './data/tileConnections.js';
|
|
100
102
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
101
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver,
|
|
103
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import ConnectAllRule from './data/rules/connectAllRule.js';
|
|
|
25
25
|
import CustomRule from './data/rules/customRule.js';
|
|
26
26
|
import ForesightRule from './data/rules/foresightRule.js';
|
|
27
27
|
import { allRules } from './data/rules/index.js';
|
|
28
|
+
import LyingSymbolRule from './data/rules/lyingSymbolRule.js';
|
|
28
29
|
import { ControlLine, Row } from './data/rules/musicControlLine.js';
|
|
29
30
|
import MusicGridRule from './data/rules/musicGridRule.js';
|
|
30
31
|
import MysteryRule from './data/rules/mysteryRule.js';
|
|
@@ -66,8 +67,9 @@ import LotusBTModule from './data/solver/backtrack/symbols/lotus.js';
|
|
|
66
67
|
import MinesweeperBTModule from './data/solver/backtrack/symbols/minesweeper.js';
|
|
67
68
|
import MyopiaBTModule from './data/solver/backtrack/symbols/myopia.js';
|
|
68
69
|
import ViewpointBTModule from './data/solver/backtrack/symbols/viewpoint.js';
|
|
70
|
+
import EventIteratingSolver from './data/solver/eventIteratingSolver.js';
|
|
69
71
|
import Solver from './data/solver/solver.js';
|
|
70
|
-
import
|
|
72
|
+
import UniversalSolver from './data/solver/universal/universalSolver.js';
|
|
71
73
|
import AreaNumberModule from './data/solver/z3/modules/areaNumberModule.js';
|
|
72
74
|
import CellCountModule from './data/solver/z3/modules/cellCountModule.js';
|
|
73
75
|
import ConnectAllModule from './data/solver/z3/modules/connectAllModule.js';
|
|
@@ -101,4 +103,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
101
103
|
import TileData from './data/tile.js';
|
|
102
104
|
import TileConnections from './data/tileConnections.js';
|
|
103
105
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
104
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver,
|
|
106
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import GridData from '../../grid.js';
|
|
2
|
-
import Solver from '../solver.js';
|
|
3
|
-
export default class UndercluedSolver extends Solver {
|
|
4
|
-
readonly id = "underclued";
|
|
5
|
-
readonly description = "Solves every puzzle as if it were underclued. Supports all rules and symbols and is decently fast for small puzzles. Very slow for large puzzles.";
|
|
6
|
-
solve(grid: GridData): AsyncGenerator<GridData | null>;
|
|
7
|
-
isInstructionSupported(instructionId: string): boolean;
|
|
8
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Color } from '../../primitives.js';
|
|
2
|
-
import { instance as undercluedInstance } from '../../rules/undercluedRule.js';
|
|
3
|
-
import { Serializer } from '../../serializer/allSerializers.js';
|
|
4
|
-
import Solver from '../solver.js';
|
|
5
|
-
export default class UndercluedSolver extends Solver {
|
|
6
|
-
constructor() {
|
|
7
|
-
super(...arguments);
|
|
8
|
-
Object.defineProperty(this, "id", {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
configurable: true,
|
|
11
|
-
writable: true,
|
|
12
|
-
value: 'underclued'
|
|
13
|
-
});
|
|
14
|
-
Object.defineProperty(this, "description", {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
configurable: true,
|
|
17
|
-
writable: true,
|
|
18
|
-
value: 'Solves every puzzle as if it were underclued. Supports all rules and symbols and is decently fast for small puzzles. Very slow for large puzzles.'
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
async *solve(grid) {
|
|
22
|
-
const worker = new Worker(new URL('./undercluedWorker.js', import.meta.url), {
|
|
23
|
-
type: 'module',
|
|
24
|
-
});
|
|
25
|
-
try {
|
|
26
|
-
const solved = await new Promise(resolve => {
|
|
27
|
-
worker.addEventListener('message', e => {
|
|
28
|
-
const solution = Serializer.parseGrid(e.data);
|
|
29
|
-
// console.timeEnd('Solve time');
|
|
30
|
-
if (solution.resetTiles().equals(solution))
|
|
31
|
-
resolve(null);
|
|
32
|
-
else
|
|
33
|
-
resolve(solution);
|
|
34
|
-
});
|
|
35
|
-
worker.postMessage(Serializer.stringifyGrid(grid));
|
|
36
|
-
// console.time('Solve time');
|
|
37
|
-
});
|
|
38
|
-
yield solved;
|
|
39
|
-
if (solved) {
|
|
40
|
-
if (solved.getTileCount(true, undefined, Color.Gray) === 0) {
|
|
41
|
-
yield null; // the grid is completely filled, which means the solution is unique
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
finally {
|
|
46
|
-
worker.terminate();
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
isInstructionSupported(instructionId) {
|
|
50
|
-
if (super.isInstructionSupported(instructionId)) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
return instructionId === undercluedInstance.id;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { Color, State } from '../../primitives.js';
|
|
2
|
-
import { Serializer } from '../../serializer/allSerializers.js';
|
|
3
|
-
import validateGrid from '../../validate.js';
|
|
4
|
-
function posToCoords(pos, width) {
|
|
5
|
-
if (pos === undefined) {
|
|
6
|
-
throw new Error('pos is undefined');
|
|
7
|
-
}
|
|
8
|
-
return [pos % width, Math.floor(pos / width)];
|
|
9
|
-
}
|
|
10
|
-
function coordsToPos(a, width) {
|
|
11
|
-
return a[0] + a[1] * width;
|
|
12
|
-
}
|
|
13
|
-
function getValidGrid(grid, assumptions, canAssump) {
|
|
14
|
-
while (true) {
|
|
15
|
-
// Get assumption
|
|
16
|
-
const newAssump = canAssump.findIndex((a, i) => a && !assumptions.includes(i));
|
|
17
|
-
if (newAssump === -1) {
|
|
18
|
-
return [grid, assumptions, true];
|
|
19
|
-
}
|
|
20
|
-
// Set assumption's color to dark
|
|
21
|
-
const coords = posToCoords(newAssump, grid.width);
|
|
22
|
-
grid = grid.setTile(coords[0], coords[1], tile => tile.withColor(Color.Dark));
|
|
23
|
-
assumptions.push(newAssump);
|
|
24
|
-
for (const a of grid.connections.getConnectedTiles({
|
|
25
|
-
x: coords[0],
|
|
26
|
-
y: coords[1],
|
|
27
|
-
})) {
|
|
28
|
-
canAssump[coordsToPos([a.x, a.y], grid.width)] =
|
|
29
|
-
a.x === coords[0] && a.y === coords[1];
|
|
30
|
-
}
|
|
31
|
-
const state = validateGrid(grid, null);
|
|
32
|
-
// If the grid is invalid, try to backtrack to a right assumption
|
|
33
|
-
if (state.final === State.Error) {
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
35
|
-
[grid, assumptions] = tryToBacktrack(grid, assumptions);
|
|
36
|
-
if (assumptions.length === 0) {
|
|
37
|
-
return [grid, assumptions, false];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function tryToBacktrack(grid, assumptions) {
|
|
43
|
-
while (assumptions.length > 0) {
|
|
44
|
-
const coords = posToCoords(assumptions[assumptions.length - 1], grid.width);
|
|
45
|
-
if (grid.getTile(coords[0], coords[1]).color === Color.Light) {
|
|
46
|
-
grid = grid.setTile(coords[0], coords[1], tile => tile.withColor(Color.Gray));
|
|
47
|
-
assumptions.pop();
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
grid = grid.setTile(coords[0], coords[1], tile => tile.withColor(Color.Light));
|
|
51
|
-
const state = validateGrid(grid, null);
|
|
52
|
-
if (state.final === State.Error) {
|
|
53
|
-
grid = grid.setTile(coords[0], coords[1], tile => tile.withColor(Color.Gray));
|
|
54
|
-
assumptions.pop();
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
return [grid, assumptions];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return [grid, assumptions];
|
|
62
|
-
}
|
|
63
|
-
function computeSolution(initialGrid) {
|
|
64
|
-
const canAssump = initialGrid.tiles
|
|
65
|
-
.map(row => row.map(t => t.exists && !t.fixed))
|
|
66
|
-
.flat();
|
|
67
|
-
let lastValidGrid = [];
|
|
68
|
-
let assumptions = [];
|
|
69
|
-
let currentGrid = initialGrid.copyWith({});
|
|
70
|
-
let anyNewGrid;
|
|
71
|
-
while (assumptions.length > 0 || lastValidGrid.length === 0) {
|
|
72
|
-
[currentGrid, assumptions, anyNewGrid] = getValidGrid(currentGrid, assumptions, canAssump);
|
|
73
|
-
// console.log(
|
|
74
|
-
// currentGrid.tiles
|
|
75
|
-
// .map(row =>
|
|
76
|
-
// row
|
|
77
|
-
// .map(t => {
|
|
78
|
-
// const color = t.color === Color.Light ? 'w' : 'b';
|
|
79
|
-
// if (t.color === Color.Gray) return 'n';
|
|
80
|
-
// if (!t.exists) return '.';
|
|
81
|
-
// return t.fixed ? color.toUpperCase() : color;
|
|
82
|
-
// })
|
|
83
|
-
// .join('')
|
|
84
|
-
// )
|
|
85
|
-
// .join('\n')
|
|
86
|
-
// );
|
|
87
|
-
if (!anyNewGrid) {
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
const newLastValidGrid = currentGrid.tiles
|
|
91
|
-
.map(row => row.map(t => t.color))
|
|
92
|
-
.flat();
|
|
93
|
-
if (lastValidGrid.length !== 0) {
|
|
94
|
-
const diff = newLastValidGrid.map((color, i) => color === lastValidGrid[i]);
|
|
95
|
-
diff.forEach((same, i) => {
|
|
96
|
-
if (!same) {
|
|
97
|
-
newLastValidGrid[i] = Color.Gray;
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
[currentGrid, assumptions] = tryToBacktrack(currentGrid, assumptions);
|
|
102
|
-
lastValidGrid = newLastValidGrid;
|
|
103
|
-
}
|
|
104
|
-
// Create a new grid with lastValidGrid
|
|
105
|
-
let solutionGrid = initialGrid.copyWith({});
|
|
106
|
-
lastValidGrid.forEach((color, i) => {
|
|
107
|
-
const coords = posToCoords(i, solutionGrid.width);
|
|
108
|
-
solutionGrid = solutionGrid.setTile(coords[0], coords[1], tile => tile.withColor(color));
|
|
109
|
-
});
|
|
110
|
-
// console.log(
|
|
111
|
-
// solutionGrid.tiles
|
|
112
|
-
// .map(row =>
|
|
113
|
-
// row
|
|
114
|
-
// .map(t => {
|
|
115
|
-
// const color = t.color === Color.Light ? 'w' : 'b';
|
|
116
|
-
// if (t.color === Color.Gray) return 'n';
|
|
117
|
-
// if (!t.exists) return '.';
|
|
118
|
-
// return t.fixed ? color.toUpperCase() : color;
|
|
119
|
-
// })
|
|
120
|
-
// .join('')
|
|
121
|
-
// )
|
|
122
|
-
// .join('\n')
|
|
123
|
-
// );
|
|
124
|
-
return solutionGrid;
|
|
125
|
-
}
|
|
126
|
-
onmessage = e => {
|
|
127
|
-
if (!e.data || typeof e.data !== 'string')
|
|
128
|
-
return;
|
|
129
|
-
const grid = Serializer.parseGrid(e.data);
|
|
130
|
-
const solved = computeSolution(grid);
|
|
131
|
-
postMessage(Serializer.stringifyGrid(solved));
|
|
132
|
-
};
|
|
133
|
-
// make typescript happy
|
|
134
|
-
// eslint-disable-next-line import/no-anonymous-default-export
|
|
135
|
-
export default null;
|