@logic-pad/core 0.1.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/LICENSE +661 -0
- package/README.md +19 -0
- package/assets/logic-core.global.d.ts +5865 -0
- package/assets/z3-built.js +14723 -0
- package/assets/z3-built.wasm +0 -0
- package/assets/z3-built.worker.js +206 -0
- package/dist/data/config.d.ts +101 -0
- package/dist/data/config.js +55 -0
- package/dist/data/configurable.d.ts +12 -0
- package/dist/data/configurable.js +26 -0
- package/dist/data/dataHelper.d.ts +77 -0
- package/dist/data/dataHelper.js +190 -0
- package/dist/data/events/eventHelper.d.ts +1 -0
- package/dist/data/events/eventHelper.js +6 -0
- package/dist/data/events/onFinalValidation.d.ts +14 -0
- package/dist/data/events/onFinalValidation.js +4 -0
- package/dist/data/events/onGridChange.d.ts +6 -0
- package/dist/data/events/onGridChange.js +4 -0
- package/dist/data/events/onGridResize.d.ts +9 -0
- package/dist/data/events/onGridResize.js +4 -0
- package/dist/data/events/onSetGrid.d.ts +6 -0
- package/dist/data/events/onSetGrid.js +4 -0
- package/dist/data/events/onSymbolValidation.d.ts +18 -0
- package/dist/data/events/onSymbolValidation.js +4 -0
- package/dist/data/grid.d.ts +362 -0
- package/dist/data/grid.js +886 -0
- package/dist/data/gridConnections.d.ts +38 -0
- package/dist/data/gridConnections.js +328 -0
- package/dist/data/instruction.d.ts +19 -0
- package/dist/data/instruction.js +23 -0
- package/dist/data/primitives.d.ts +85 -0
- package/dist/data/primitives.js +90 -0
- package/dist/data/puzzle.d.ts +86 -0
- package/dist/data/puzzle.js +22 -0
- package/dist/data/rules/banPatternRule.d.ts +29 -0
- package/dist/data/rules/banPatternRule.js +133 -0
- package/dist/data/rules/cellCountRule.d.ts +32 -0
- package/dist/data/rules/cellCountRule.js +166 -0
- package/dist/data/rules/completePatternRule.d.ts +22 -0
- package/dist/data/rules/completePatternRule.js +53 -0
- package/dist/data/rules/connectAllRule.d.ts +28 -0
- package/dist/data/rules/connectAllRule.js +113 -0
- package/dist/data/rules/customRule.d.ts +32 -0
- package/dist/data/rules/customRule.js +92 -0
- package/dist/data/rules/foresightRule.d.ts +30 -0
- package/dist/data/rules/foresightRule.js +107 -0
- package/dist/data/rules/index.d.ts +3 -0
- package/dist/data/rules/index.js +10 -0
- package/dist/data/rules/musicControlLine.d.ts +64 -0
- package/dist/data/rules/musicControlLine.js +178 -0
- package/dist/data/rules/musicGridRule.d.ts +46 -0
- package/dist/data/rules/musicGridRule.js +211 -0
- package/dist/data/rules/mysteryRule.d.ts +37 -0
- package/dist/data/rules/mysteryRule.js +164 -0
- package/dist/data/rules/offByXRule.d.ts +30 -0
- package/dist/data/rules/offByXRule.js +134 -0
- package/dist/data/rules/regionAreaRule.d.ts +33 -0
- package/dist/data/rules/regionAreaRule.js +182 -0
- package/dist/data/rules/regionShapeRule.d.ts +22 -0
- package/dist/data/rules/regionShapeRule.js +58 -0
- package/dist/data/rules/rule.d.ts +18 -0
- package/dist/data/rules/rule.js +19 -0
- package/dist/data/rules/rules.gen.d.ts +14 -0
- package/dist/data/rules/rules.gen.js +18 -0
- package/dist/data/rules/sameShapeRule.d.ts +27 -0
- package/dist/data/rules/sameShapeRule.js +88 -0
- package/dist/data/rules/symbolsPerRegionRule.d.ts +37 -0
- package/dist/data/rules/symbolsPerRegionRule.js +211 -0
- package/dist/data/rules/undercluedRule.d.ts +22 -0
- package/dist/data/rules/undercluedRule.js +60 -0
- package/dist/data/rules/uniqueShapeRule.d.ts +27 -0
- package/dist/data/rules/uniqueShapeRule.js +85 -0
- package/dist/data/serializer/allSerializers.d.ts +30 -0
- package/dist/data/serializer/allSerializers.js +64 -0
- package/dist/data/serializer/compressor/allCompressors.d.ts +14 -0
- package/dist/data/serializer/compressor/allCompressors.js +43 -0
- package/dist/data/serializer/compressor/compressorBase.d.ts +16 -0
- package/dist/data/serializer/compressor/compressorBase.js +2 -0
- package/dist/data/serializer/compressor/deflateCompressor.d.ts +7 -0
- package/dist/data/serializer/compressor/deflateCompressor.js +17 -0
- package/dist/data/serializer/compressor/gzipCompressor.d.ts +5 -0
- package/dist/data/serializer/compressor/gzipCompressor.js +9 -0
- package/dist/data/serializer/compressor/streamCompressor.d.ts +6 -0
- package/dist/data/serializer/compressor/streamCompressor.js +36 -0
- package/dist/data/serializer/serializerBase.d.ts +27 -0
- package/dist/data/serializer/serializerBase.js +2 -0
- package/dist/data/serializer/serializer_v0.d.ts +36 -0
- package/dist/data/serializer/serializer_v0.js +426 -0
- package/dist/data/shapes.d.ts +17 -0
- package/dist/data/shapes.js +117 -0
- package/dist/data/solver/allSolvers.d.ts +3 -0
- package/dist/data/solver/allSolvers.js +11 -0
- package/dist/data/solver/backtrack/backtrackSolver.d.ts +9 -0
- package/dist/data/solver/backtrack/backtrackSolver.js +92 -0
- package/dist/data/solver/backtrack/backtrackWorker.d.ts +2 -0
- package/dist/data/solver/backtrack/backtrackWorker.js +295 -0
- package/dist/data/solver/backtrack/data.d.ts +46 -0
- package/dist/data/solver/backtrack/data.js +140 -0
- package/dist/data/solver/backtrack/rules/banPattern.d.ts +9 -0
- package/dist/data/solver/backtrack/rules/banPattern.js +66 -0
- package/dist/data/solver/backtrack/rules/cellCount.d.ts +7 -0
- package/dist/data/solver/backtrack/rules/cellCount.js +30 -0
- package/dist/data/solver/backtrack/rules/connectAll.d.ts +7 -0
- package/dist/data/solver/backtrack/rules/connectAll.js +49 -0
- package/dist/data/solver/backtrack/rules/regionArea.d.ts +8 -0
- package/dist/data/solver/backtrack/rules/regionArea.js +76 -0
- package/dist/data/solver/backtrack/rules/regionShape.d.ts +8 -0
- package/dist/data/solver/backtrack/rules/regionShape.js +62 -0
- package/dist/data/solver/backtrack/rules/sameShape.d.ts +8 -0
- package/dist/data/solver/backtrack/rules/sameShape.js +19 -0
- package/dist/data/solver/backtrack/rules/symbolsPerRegion.d.ts +10 -0
- package/dist/data/solver/backtrack/rules/symbolsPerRegion.js +92 -0
- package/dist/data/solver/backtrack/rules/uniqueShape.d.ts +8 -0
- package/dist/data/solver/backtrack/rules/uniqueShape.js +19 -0
- package/dist/data/solver/backtrack/symbols/areaNumber.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/areaNumber.js +77 -0
- package/dist/data/solver/backtrack/symbols/dart.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/dart.js +58 -0
- package/dist/data/solver/backtrack/symbols/directionLinker.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/directionLinker.js +50 -0
- package/dist/data/solver/backtrack/symbols/galaxy.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/galaxy.js +19 -0
- package/dist/data/solver/backtrack/symbols/letter.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/letter.js +100 -0
- package/dist/data/solver/backtrack/symbols/lotus.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/lotus.js +36 -0
- package/dist/data/solver/backtrack/symbols/minesweeper.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/minesweeper.js +55 -0
- package/dist/data/solver/backtrack/symbols/myopia.d.ts +7 -0
- package/dist/data/solver/backtrack/symbols/myopia.js +79 -0
- package/dist/data/solver/backtrack/symbols/viewpoint.d.ts +7 -0
- package/dist/data/solver/backtrack/symbols/viewpoint.js +56 -0
- package/dist/data/solver/solver.d.ts +61 -0
- package/dist/data/solver/solver.js +55 -0
- package/dist/data/solver/underclued/undercluedSolver.d.ts +8 -0
- package/dist/data/solver/underclued/undercluedSolver.js +55 -0
- package/dist/data/solver/underclued/undercluedWorker.d.ts +2 -0
- package/dist/data/solver/underclued/undercluedWorker.js +131 -0
- package/dist/data/solver/z3/modules/areaNumberModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/areaNumberModule.js +35 -0
- package/dist/data/solver/z3/modules/cellCountModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/cellCountModule.js +59 -0
- package/dist/data/solver/z3/modules/connectAllModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/connectAllModule.js +32 -0
- package/dist/data/solver/z3/modules/dartModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/dartModule.js +69 -0
- package/dist/data/solver/z3/modules/index.d.ts +3 -0
- package/dist/data/solver/z3/modules/index.js +10 -0
- package/dist/data/solver/z3/modules/letterModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/letterModule.js +41 -0
- package/dist/data/solver/z3/modules/modules.gen.d.ts +8 -0
- package/dist/data/solver/z3/modules/modules.gen.js +12 -0
- package/dist/data/solver/z3/modules/myopiaModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/myopiaModule.js +64 -0
- package/dist/data/solver/z3/modules/regionAreaModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/regionAreaModule.js +48 -0
- package/dist/data/solver/z3/modules/viewpointModule.d.ts +9 -0
- package/dist/data/solver/z3/modules/viewpointModule.js +37 -0
- package/dist/data/solver/z3/modules/z3Module.d.ts +7 -0
- package/dist/data/solver/z3/modules/z3Module.js +3 -0
- package/dist/data/solver/z3/utils.d.ts +2 -0
- package/dist/data/solver/z3/utils.js +26 -0
- package/dist/data/solver/z3/z3Solver.d.ts +10 -0
- package/dist/data/solver/z3/z3Solver.js +134 -0
- package/dist/data/solver/z3/z3SolverContext.d.ts +808 -0
- package/dist/data/solver/z3/z3SolverContext.js +49 -0
- package/dist/data/symbols/areaNumberSymbol.d.ts +30 -0
- package/dist/data/symbols/areaNumberSymbol.js +88 -0
- package/dist/data/symbols/customIconSymbol.d.ts +35 -0
- package/dist/data/symbols/customIconSymbol.js +105 -0
- package/dist/data/symbols/customSymbol.d.ts +23 -0
- package/dist/data/symbols/customSymbol.js +48 -0
- package/dist/data/symbols/customTextSymbol.d.ts +33 -0
- package/dist/data/symbols/customTextSymbol.js +106 -0
- package/dist/data/symbols/dartSymbol.d.ts +35 -0
- package/dist/data/symbols/dartSymbol.js +110 -0
- package/dist/data/symbols/directionLinkerSymbol.d.ts +36 -0
- package/dist/data/symbols/directionLinkerSymbol.js +259 -0
- package/dist/data/symbols/galaxySymbol.d.ts +26 -0
- package/dist/data/symbols/galaxySymbol.js +74 -0
- package/dist/data/symbols/index.d.ts +3 -0
- package/dist/data/symbols/index.js +10 -0
- package/dist/data/symbols/letterSymbol.d.ts +31 -0
- package/dist/data/symbols/letterSymbol.js +137 -0
- package/dist/data/symbols/lotusSymbol.d.ts +29 -0
- package/dist/data/symbols/lotusSymbol.js +132 -0
- package/dist/data/symbols/minesweeperSymbol.d.ts +31 -0
- package/dist/data/symbols/minesweeperSymbol.js +100 -0
- package/dist/data/symbols/multiEntrySymbol.d.ts +11 -0
- package/dist/data/symbols/multiEntrySymbol.js +14 -0
- package/dist/data/symbols/myopiaSymbol.d.ts +34 -0
- package/dist/data/symbols/myopiaSymbol.js +187 -0
- package/dist/data/symbols/numberSymbol.d.ts +19 -0
- package/dist/data/symbols/numberSymbol.js +41 -0
- package/dist/data/symbols/symbol.d.ts +16 -0
- package/dist/data/symbols/symbol.js +51 -0
- package/dist/data/symbols/symbols.gen.d.ts +10 -0
- package/dist/data/symbols/symbols.gen.js +14 -0
- package/dist/data/symbols/viewpointSymbol.d.ts +31 -0
- package/dist/data/symbols/viewpointSymbol.js +106 -0
- package/dist/data/tile.d.ts +26 -0
- package/dist/data/tile.js +68 -0
- package/dist/data/tileConnections.d.ts +25 -0
- package/dist/data/tileConnections.js +74 -0
- package/dist/data/validate.d.ts +5 -0
- package/dist/data/validate.js +131 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.js +100 -0
- package/dist/polyfill/streamPolyfill.d.ts +2 -0
- package/dist/polyfill/streamPolyfill.js +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import LetterSymbol from '../../../symbols/letterSymbol';
|
|
2
|
+
import BTModule, { BTGridData, CheckResult } from '../data';
|
|
3
|
+
export default class LetterBTModule extends BTModule {
|
|
4
|
+
private letters;
|
|
5
|
+
private letterGrid;
|
|
6
|
+
constructor(instrs: LetterSymbol[], width: number, height: number);
|
|
7
|
+
checkGlobal(grid: BTGridData): CheckResult | false;
|
|
8
|
+
private visitArea;
|
|
9
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import BTModule, { BTTile, IntArray2D } from '../data';
|
|
2
|
+
export default class LetterBTModule extends BTModule {
|
|
3
|
+
constructor(instrs, width, height) {
|
|
4
|
+
super();
|
|
5
|
+
Object.defineProperty(this, "letters", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(this, "letterGrid", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: void 0
|
|
16
|
+
});
|
|
17
|
+
this.letters = [];
|
|
18
|
+
this.letterGrid = IntArray2D.create(width, height);
|
|
19
|
+
const letterMap = new Map();
|
|
20
|
+
let letterCount = 0;
|
|
21
|
+
for (const instr of instrs) {
|
|
22
|
+
if (!letterMap.has(instr.letter)) {
|
|
23
|
+
letterMap.set(instr.letter, letterCount);
|
|
24
|
+
this.letters[letterCount] = [];
|
|
25
|
+
letterCount += 1;
|
|
26
|
+
}
|
|
27
|
+
const id = letterMap.get(instr.letter);
|
|
28
|
+
this.letters[id].push(instr);
|
|
29
|
+
this.letterGrid.set(Math.floor(instr.x), Math.floor(instr.y), id + 1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
checkGlobal(grid) {
|
|
33
|
+
const visited = IntArray2D.create(grid.width, grid.height);
|
|
34
|
+
for (let id = 0; id < this.letters.length; id++) {
|
|
35
|
+
for (const symbol of this.letters[id]) {
|
|
36
|
+
const symbolX = Math.floor(symbol.x);
|
|
37
|
+
const symbolY = Math.floor(symbol.y);
|
|
38
|
+
if (grid.getTile(symbolX, symbolY) === BTTile.Empty)
|
|
39
|
+
continue;
|
|
40
|
+
if (!this.visitArea(grid, visited, { x: symbolX, y: symbolY }, id + 1))
|
|
41
|
+
return false;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { tilesNeedCheck: null, ratings: null };
|
|
46
|
+
}
|
|
47
|
+
visitArea(grid, visited, pos, id) {
|
|
48
|
+
const tile = grid.getTile(pos.x, pos.y);
|
|
49
|
+
const sameTileQueue = [pos];
|
|
50
|
+
const usableTileQueue = [];
|
|
51
|
+
let letterVisited = 0;
|
|
52
|
+
visited.set(pos.x, pos.y, id);
|
|
53
|
+
// Count same tile
|
|
54
|
+
while (sameTileQueue.length > 0) {
|
|
55
|
+
const curPos = sameTileQueue.pop();
|
|
56
|
+
const letterId = this.letterGrid.get(curPos.x, curPos.y);
|
|
57
|
+
if (letterId === id) {
|
|
58
|
+
letterVisited += 1;
|
|
59
|
+
}
|
|
60
|
+
else if (letterId !== 0) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
for (const edge of grid.getEdges(curPos)) {
|
|
64
|
+
if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
|
|
65
|
+
continue;
|
|
66
|
+
const edgeTile = grid.getTile(edge.x, edge.y);
|
|
67
|
+
if (edgeTile === BTTile.Empty) {
|
|
68
|
+
usableTileQueue.push(edge);
|
|
69
|
+
visited.set(edge.x, edge.y, id | 0b10000000);
|
|
70
|
+
}
|
|
71
|
+
else if (edgeTile === tile) {
|
|
72
|
+
sameTileQueue.push(edge);
|
|
73
|
+
visited.set(edge.x, edge.y, id);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (letterVisited === this.letters[id - 1].length)
|
|
78
|
+
return true;
|
|
79
|
+
// Count usable tile
|
|
80
|
+
while (usableTileQueue.length > 0) {
|
|
81
|
+
const curPos = usableTileQueue.pop();
|
|
82
|
+
const letterId = this.letterGrid.get(curPos.x, curPos.y);
|
|
83
|
+
if (letterId === id) {
|
|
84
|
+
letterVisited += 1;
|
|
85
|
+
if (letterVisited === this.letters[id - 1].length)
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
for (const edge of grid.getEdges(curPos)) {
|
|
89
|
+
if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
|
|
90
|
+
continue;
|
|
91
|
+
const edgeTile = grid.getTile(edge.x, edge.y);
|
|
92
|
+
if (edgeTile === BTTile.Empty || edgeTile === tile) {
|
|
93
|
+
usableTileQueue.push(edge);
|
|
94
|
+
visited.set(edge.x, edge.y, id | 0b10000000);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return letterVisited === this.letters[id - 1].length;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Position } from '../../../primitives';
|
|
2
|
+
import LotusSymbol from '../../../symbols/lotusSymbol';
|
|
3
|
+
import { BTGridData } from '../data';
|
|
4
|
+
import DirectionLinkerBTModule from './directionLinker';
|
|
5
|
+
export default class LotusBTModule extends DirectionLinkerBTModule {
|
|
6
|
+
instr: LotusSymbol;
|
|
7
|
+
constructor(instr: LotusSymbol);
|
|
8
|
+
protected movePos(grid: BTGridData, x: number, y: number): Position | null;
|
|
9
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Orientation } from '../../../primitives';
|
|
2
|
+
import DirectionLinkerBTModule from './directionLinker';
|
|
3
|
+
export default class LotusBTModule extends DirectionLinkerBTModule {
|
|
4
|
+
constructor(instr) {
|
|
5
|
+
super(instr);
|
|
6
|
+
Object.defineProperty(this, "instr", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
writable: true,
|
|
10
|
+
value: void 0
|
|
11
|
+
});
|
|
12
|
+
this.instr = instr;
|
|
13
|
+
}
|
|
14
|
+
// Translate a position in relative to a lotus symbol
|
|
15
|
+
movePos(grid, x, y) {
|
|
16
|
+
const symbol = this.instr;
|
|
17
|
+
let pos;
|
|
18
|
+
if (symbol.orientation === Orientation.Up ||
|
|
19
|
+
symbol.orientation === Orientation.Down) {
|
|
20
|
+
pos = { x: 2 * symbol.x - x, y };
|
|
21
|
+
}
|
|
22
|
+
else if (symbol.orientation === Orientation.UpRight ||
|
|
23
|
+
symbol.orientation === Orientation.DownLeft) {
|
|
24
|
+
pos = { x: symbol.y + symbol.x - y, y: symbol.y + symbol.x - x };
|
|
25
|
+
}
|
|
26
|
+
else if (symbol.orientation === Orientation.Right ||
|
|
27
|
+
symbol.orientation === Orientation.Left) {
|
|
28
|
+
pos = { x, y: 2 * symbol.y - y };
|
|
29
|
+
}
|
|
30
|
+
else if (symbol.orientation === Orientation.DownRight ||
|
|
31
|
+
symbol.orientation === Orientation.UpLeft) {
|
|
32
|
+
pos = { x: symbol.x - symbol.y + y, y: symbol.y - symbol.x + x };
|
|
33
|
+
}
|
|
34
|
+
return grid.isInBound(pos.x, pos.y) ? pos : null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import MinesweeperSymbol from '../../../symbols/minesweeperSymbol';
|
|
2
|
+
import BTModule, { BTGridData, CheckResult } from '../data';
|
|
3
|
+
export default class MinesweeperBTModule extends BTModule {
|
|
4
|
+
instr: MinesweeperSymbol;
|
|
5
|
+
private cachedCheckResult?;
|
|
6
|
+
constructor(instr: MinesweeperSymbol);
|
|
7
|
+
checkGlobal(grid: BTGridData): CheckResult | false;
|
|
8
|
+
private buildCheckAndRating;
|
|
9
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import BTModule, { BTTile, IntArray2D, createOneTileResult, getOppositeColor, } from '../data';
|
|
2
|
+
export default class MinesweeperBTModule extends BTModule {
|
|
3
|
+
constructor(instr) {
|
|
4
|
+
super();
|
|
5
|
+
Object.defineProperty(this, "instr", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(this, "cachedCheckResult", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: void 0
|
|
16
|
+
});
|
|
17
|
+
this.instr = instr;
|
|
18
|
+
}
|
|
19
|
+
checkGlobal(grid) {
|
|
20
|
+
const tile = grid.getTile(this.instr.x, this.instr.y);
|
|
21
|
+
if (tile === BTTile.Empty)
|
|
22
|
+
return createOneTileResult(grid, { x: this.instr.x, y: this.instr.y });
|
|
23
|
+
let gray = 0;
|
|
24
|
+
let opposite = 0;
|
|
25
|
+
for (let y = this.instr.y - 1; y <= this.instr.y + 1; y++) {
|
|
26
|
+
for (let x = this.instr.x - 1; x <= this.instr.x + 1; x++) {
|
|
27
|
+
if (!grid.isInBound(x, y) || (x === this.instr.x && y === this.instr.y))
|
|
28
|
+
continue;
|
|
29
|
+
const checkTile = grid.getTile(x, y);
|
|
30
|
+
if (checkTile === BTTile.Empty)
|
|
31
|
+
gray++;
|
|
32
|
+
else if (checkTile === getOppositeColor(tile))
|
|
33
|
+
opposite++;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (opposite > this.instr.number || opposite + gray < this.instr.number)
|
|
37
|
+
return false;
|
|
38
|
+
if (!this.cachedCheckResult)
|
|
39
|
+
this.cachedCheckResult = this.buildCheckAndRating(grid);
|
|
40
|
+
return this.cachedCheckResult;
|
|
41
|
+
}
|
|
42
|
+
buildCheckAndRating(grid) {
|
|
43
|
+
const tilesNeedCheck = IntArray2D.create(grid.width, grid.height);
|
|
44
|
+
const ratings = [];
|
|
45
|
+
for (let y = this.instr.y - 1; y <= this.instr.y + 1; y++) {
|
|
46
|
+
for (let x = this.instr.x - 1; x <= this.instr.x + 1; x++) {
|
|
47
|
+
if (!grid.isInBound(x, y) || (x === this.instr.x && y === this.instr.y))
|
|
48
|
+
continue;
|
|
49
|
+
tilesNeedCheck.set(x, y, 1);
|
|
50
|
+
ratings.push({ pos: { x, y }, score: 1 });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { tilesNeedCheck, ratings };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import MyopiaSymbol from '../../../symbols/myopiaSymbol';
|
|
2
|
+
import BTModule, { BTGridData, CheckResult } from '../data';
|
|
3
|
+
export default class MyopiaBTModule extends BTModule {
|
|
4
|
+
instr: MyopiaSymbol;
|
|
5
|
+
constructor(instr: MyopiaSymbol);
|
|
6
|
+
checkGlobal(grid: BTGridData): CheckResult | false;
|
|
7
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { move } from '../../../dataHelper';
|
|
2
|
+
import { ORIENTATIONS, Orientation } from '../../../primitives';
|
|
3
|
+
import BTModule, { BTTile, createOneTileResult, getOppositeColor, } from '../data';
|
|
4
|
+
export default class MyopiaBTModule extends BTModule {
|
|
5
|
+
constructor(instr) {
|
|
6
|
+
super();
|
|
7
|
+
Object.defineProperty(this, "instr", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
writable: true,
|
|
11
|
+
value: void 0
|
|
12
|
+
});
|
|
13
|
+
this.instr = instr;
|
|
14
|
+
}
|
|
15
|
+
checkGlobal(grid) {
|
|
16
|
+
// TODO: Optimize myopia symbol
|
|
17
|
+
// TODO: What to do if a non-existence tile is in front?
|
|
18
|
+
const tile = grid.getTile(this.instr.x, this.instr.y);
|
|
19
|
+
if (tile === BTTile.Empty)
|
|
20
|
+
return createOneTileResult(grid, { x: this.instr.x, y: this.instr.y });
|
|
21
|
+
const traverse = (dir) => {
|
|
22
|
+
let min = 0;
|
|
23
|
+
let max = 0;
|
|
24
|
+
let connected = true;
|
|
25
|
+
let stopped = false;
|
|
26
|
+
let pos = move(this.instr, dir);
|
|
27
|
+
while (grid.isInBound(pos.x, pos.y)) {
|
|
28
|
+
const curTile = grid.getTile(pos.x, pos.y);
|
|
29
|
+
if (connected) {
|
|
30
|
+
if (tile === curTile) {
|
|
31
|
+
min += 1;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
connected = false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (getOppositeColor(tile) === curTile ||
|
|
38
|
+
curTile === BTTile.NonExist) {
|
|
39
|
+
stopped = true;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
max += 1;
|
|
43
|
+
pos = move(pos, dir);
|
|
44
|
+
}
|
|
45
|
+
return [min, stopped ? max : Number.MAX_SAFE_INTEGER, connected];
|
|
46
|
+
};
|
|
47
|
+
const allDirections = this.instr.diagonals
|
|
48
|
+
? ORIENTATIONS
|
|
49
|
+
: [Orientation.Up, Orientation.Down, Orientation.Left, Orientation.Right];
|
|
50
|
+
const pointedDirections = [];
|
|
51
|
+
const otherDirections = [];
|
|
52
|
+
for (const dir of allDirections) {
|
|
53
|
+
const res = traverse(dir);
|
|
54
|
+
if (this.instr.directions[dir]) {
|
|
55
|
+
pointedDirections.push(res);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
otherDirections.push(res);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (let i = 0; i < pointedDirections.length; i++) {
|
|
62
|
+
const direction1 = pointedDirections[i];
|
|
63
|
+
for (let j = i + 1; j < pointedDirections.length; j++) {
|
|
64
|
+
const direction2 = pointedDirections[j];
|
|
65
|
+
if (direction1[0] > direction2[1] || direction2[0] > direction1[1])
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (Math.min(...otherDirections.map(d => d[1])) <=
|
|
70
|
+
Math.max(...pointedDirections.map(d => d[0])))
|
|
71
|
+
return false;
|
|
72
|
+
if (pointedDirections.length === 0 &&
|
|
73
|
+
otherDirections.some(d => d[1] !== Number.MAX_SAFE_INTEGER))
|
|
74
|
+
return false;
|
|
75
|
+
if (pointedDirections.some(d => d[2] && d[1] === Number.MAX_SAFE_INTEGER))
|
|
76
|
+
return false;
|
|
77
|
+
return { tilesNeedCheck: null, ratings: null };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import ViewpointSymbol from '../../../symbols/viewpointSymbol';
|
|
2
|
+
import BTModule, { BTGridData, CheckResult } from '../data';
|
|
3
|
+
export default class ViewpointBTModule extends BTModule {
|
|
4
|
+
instr: ViewpointSymbol;
|
|
5
|
+
constructor(instr: ViewpointSymbol);
|
|
6
|
+
checkGlobal(grid: BTGridData): CheckResult | false;
|
|
7
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import BTModule, { BTTile, IntArray2D, createOneTileResult, getOppositeColor, } from '../data';
|
|
2
|
+
export default class ViewpointBTModule extends BTModule {
|
|
3
|
+
constructor(instr) {
|
|
4
|
+
super();
|
|
5
|
+
Object.defineProperty(this, "instr", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
this.instr = instr;
|
|
12
|
+
}
|
|
13
|
+
checkGlobal(grid) {
|
|
14
|
+
const tile = grid.getTile(this.instr.x, this.instr.y);
|
|
15
|
+
if (tile === BTTile.Empty)
|
|
16
|
+
return createOneTileResult(grid, { x: this.instr.x, y: this.instr.y });
|
|
17
|
+
const tilesNeedCheck = IntArray2D.create(grid.width, grid.height);
|
|
18
|
+
const ratings = [];
|
|
19
|
+
let completed = 1;
|
|
20
|
+
let possible = 1;
|
|
21
|
+
const traverse = (dirX, dirY) => {
|
|
22
|
+
let connected = true;
|
|
23
|
+
let x = this.instr.x + dirX;
|
|
24
|
+
let y = this.instr.y + dirY;
|
|
25
|
+
while (grid.isInBound(x, y)) {
|
|
26
|
+
const curTile = grid.getTile(x, y);
|
|
27
|
+
if (connected) {
|
|
28
|
+
if (tile === curTile) {
|
|
29
|
+
completed += 1;
|
|
30
|
+
if (completed > this.instr.number)
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
if (curTile === BTTile.Empty) {
|
|
35
|
+
tilesNeedCheck.set(x, y, 1);
|
|
36
|
+
ratings.push({ pos: { x, y }, score: 1 });
|
|
37
|
+
}
|
|
38
|
+
connected = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (getOppositeColor(tile) === curTile ||
|
|
42
|
+
curTile === BTTile.NonExist)
|
|
43
|
+
break;
|
|
44
|
+
possible += 1;
|
|
45
|
+
x += dirX;
|
|
46
|
+
y += dirY;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
};
|
|
50
|
+
if (traverse(-1, 0) || traverse(1, 0) || traverse(0, -1) || traverse(0, 1))
|
|
51
|
+
return false;
|
|
52
|
+
if (possible < this.instr.number)
|
|
53
|
+
return false;
|
|
54
|
+
return { tilesNeedCheck, ratings };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import GridData from '../grid';
|
|
2
|
+
/**
|
|
3
|
+
* Base class that all solvers must extend.
|
|
4
|
+
*/
|
|
5
|
+
export default abstract class Solver {
|
|
6
|
+
/**
|
|
7
|
+
* The unique identifier of the solver.
|
|
8
|
+
*
|
|
9
|
+
* This is also displayed to the user when selecting a solver.
|
|
10
|
+
*/
|
|
11
|
+
abstract get id(): string;
|
|
12
|
+
/**
|
|
13
|
+
* A short paragraph describing when the user should use this solver.
|
|
14
|
+
*/
|
|
15
|
+
abstract get description(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Solve the given grid. The implementation should delegate long-running tasks to a worker thread and yield solutions
|
|
18
|
+
* asynchronously.
|
|
19
|
+
*
|
|
20
|
+
* The solver must yield at least once, otherwise the UI will not update.
|
|
21
|
+
*
|
|
22
|
+
* If the solver finds no solution other than those already yielded, it should yield `null`. Yielding `null` on the
|
|
23
|
+
* first iteration indicates that the grid is unsolvable. Yielding `null` on the second iteration indicates that the
|
|
24
|
+
* solution is unique.
|
|
25
|
+
*
|
|
26
|
+
* In the current UI implementation, the solver will be terminated after yielding `null`, or after 2 iterations if
|
|
27
|
+
* `null` is never yielded. The solver should perform any necessary cleanup in the `finally` block of the generator.
|
|
28
|
+
*
|
|
29
|
+
* @param grid The grid to solve. The provided grid is guaranteed to be supported by the solver. Some tiles in the
|
|
30
|
+
* grid may already be filled by the user. It is up to the solver to decide whether to respect these tiles or not.
|
|
31
|
+
*/
|
|
32
|
+
abstract solve(grid: GridData): AsyncGenerator<GridData | null>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if the solver supports the current browser environment. This method is called once when the user first clicks
|
|
35
|
+
* the "Solve" button, and the result is cached for the duration of the editor session.
|
|
36
|
+
*
|
|
37
|
+
* The `solve` method will not be called if this method returns `false`, and a message will be displayed to the user
|
|
38
|
+
* indicating that the solver is not supported.
|
|
39
|
+
*
|
|
40
|
+
* @returns A promise that resolves to `true` if the environment is supported, or `false` otherwise.
|
|
41
|
+
*/
|
|
42
|
+
isEnvironmentSupported(): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if the solver supports the given instruction. This is used to render a small indication in the UI for each
|
|
45
|
+
* instruction in the editor.
|
|
46
|
+
*
|
|
47
|
+
* @param instructionId The unique identifier of the instruction.
|
|
48
|
+
*/
|
|
49
|
+
isInstructionSupported(instructionId: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Check if the solver supports the given grid. This methid is frequently called when the user changes the grid, and
|
|
52
|
+
* the result is used to enable or disable the "Solve" button.
|
|
53
|
+
*
|
|
54
|
+
* The `solve` method will not be called if this method returns `false`, and a message will be displayed to the user
|
|
55
|
+
* indicating that the grid is not supported by this solver.
|
|
56
|
+
*
|
|
57
|
+
* @param grid The grid to check.
|
|
58
|
+
* @returns `true` if the grid is supported, or `false` otherwise.
|
|
59
|
+
*/
|
|
60
|
+
isGridSupported(grid: GridData): boolean;
|
|
61
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { allRules } from '../rules';
|
|
2
|
+
import { allSymbols } from '../symbols';
|
|
3
|
+
/**
|
|
4
|
+
* Base class that all solvers must extend.
|
|
5
|
+
*/
|
|
6
|
+
export default class Solver {
|
|
7
|
+
/**
|
|
8
|
+
* Check if the solver supports the current browser environment. This method is called once when the user first clicks
|
|
9
|
+
* the "Solve" button, and the result is cached for the duration of the editor session.
|
|
10
|
+
*
|
|
11
|
+
* The `solve` method will not be called if this method returns `false`, and a message will be displayed to the user
|
|
12
|
+
* indicating that the solver is not supported.
|
|
13
|
+
*
|
|
14
|
+
* @returns A promise that resolves to `true` if the environment is supported, or `false` otherwise.
|
|
15
|
+
*/
|
|
16
|
+
isEnvironmentSupported() {
|
|
17
|
+
return Promise.resolve(true);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if the solver supports the given instruction. This is used to render a small indication in the UI for each
|
|
21
|
+
* instruction in the editor.
|
|
22
|
+
*
|
|
23
|
+
* @param instructionId The unique identifier of the instruction.
|
|
24
|
+
*/
|
|
25
|
+
isInstructionSupported(instructionId) {
|
|
26
|
+
const symbol = allSymbols.get(instructionId);
|
|
27
|
+
if (symbol) {
|
|
28
|
+
return !symbol.validateWithSolution;
|
|
29
|
+
}
|
|
30
|
+
const rule = allRules.get(instructionId);
|
|
31
|
+
if (rule) {
|
|
32
|
+
return !rule.validateWithSolution;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if the solver supports the given grid. This methid is frequently called when the user changes the grid, and
|
|
38
|
+
* the result is used to enable or disable the "Solve" button.
|
|
39
|
+
*
|
|
40
|
+
* The `solve` method will not be called if this method returns `false`, and a message will be displayed to the user
|
|
41
|
+
* indicating that the grid is not supported by this solver.
|
|
42
|
+
*
|
|
43
|
+
* @param grid The grid to check.
|
|
44
|
+
* @returns `true` if the grid is supported, or `false` otherwise.
|
|
45
|
+
*/
|
|
46
|
+
isGridSupported(grid) {
|
|
47
|
+
if (grid.rules.some(rule => rule.necessaryForCompletion && !this.isInstructionSupported(rule.id))) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if ([...grid.symbols.keys()].some(id => !this.isInstructionSupported(id))) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import GridData from '../../grid';
|
|
2
|
+
import Solver from '../solver';
|
|
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
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Color } from '../../primitives';
|
|
2
|
+
import { instance as undercluedInstance } from '../../rules/undercluedRule';
|
|
3
|
+
import { Serializer } from '../../serializer/allSerializers';
|
|
4
|
+
import Solver from '../solver';
|
|
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
|
+
}
|