@logic-pad/core 0.26.2 → 0.27.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.
Files changed (240) hide show
  1. package/assets/logic-core.global.d.ts +3263 -3264
  2. package/dist/benchmark/helper.d.ts +22 -0
  3. package/dist/benchmark/helper.js +46 -0
  4. package/dist/benchmark/prepareBench.d.ts +1 -0
  5. package/dist/benchmark/prepareBench.js +154 -0
  6. package/dist/benchmark/runBench.d.ts +1 -0
  7. package/dist/benchmark/runBench.js +224 -0
  8. package/dist/src/data/config.d.ts +119 -0
  9. package/dist/src/data/config.js +72 -0
  10. package/dist/src/data/configurable.d.ts +14 -0
  11. package/dist/src/data/configurable.js +26 -0
  12. package/dist/src/data/dataHelper.d.ts +92 -0
  13. package/dist/src/data/dataHelper.js +217 -0
  14. package/dist/src/data/events/eventHelper.d.ts +1 -0
  15. package/dist/src/data/events/eventHelper.js +6 -0
  16. package/dist/src/data/events/onFinalValidation.d.ts +14 -0
  17. package/dist/src/data/events/onFinalValidation.js +4 -0
  18. package/dist/src/data/events/onGetTile.d.ts +7 -0
  19. package/dist/src/data/events/onGetTile.js +4 -0
  20. package/dist/src/data/events/onGridChange.d.ts +6 -0
  21. package/dist/src/data/events/onGridChange.js +4 -0
  22. package/dist/src/data/events/onGridResize.d.ts +9 -0
  23. package/dist/src/data/events/onGridResize.js +4 -0
  24. package/dist/src/data/events/onSetGrid.d.ts +7 -0
  25. package/dist/src/data/events/onSetGrid.js +19 -0
  26. package/dist/src/data/events/onSymbolDisplay.d.ts +16 -0
  27. package/dist/src/data/events/onSymbolDisplay.js +4 -0
  28. package/dist/src/data/events/onSymbolMerge.d.ts +10 -0
  29. package/dist/src/data/events/onSymbolMerge.js +4 -0
  30. package/dist/src/data/events/onSymbolValidation.d.ts +18 -0
  31. package/dist/src/data/events/onSymbolValidation.js +4 -0
  32. package/dist/src/data/grid.d.ts +410 -0
  33. package/dist/src/data/grid.js +1106 -0
  34. package/dist/src/data/gridConnections.d.ts +25 -0
  35. package/dist/src/data/gridConnections.js +309 -0
  36. package/dist/src/data/gridZones.d.ts +26 -0
  37. package/dist/src/data/gridZones.js +117 -0
  38. package/dist/src/data/instruction.d.ts +26 -0
  39. package/dist/src/data/instruction.js +29 -0
  40. package/dist/src/data/primitives.d.ts +138 -0
  41. package/dist/src/data/primitives.js +177 -0
  42. package/dist/src/data/puzzle.d.ts +73 -0
  43. package/dist/src/data/puzzle.js +105 -0
  44. package/dist/src/data/rules/banPatternRule.d.ts +30 -0
  45. package/dist/src/data/rules/banPatternRule.js +125 -0
  46. package/dist/src/data/rules/cellCountPerZoneRule.d.ts +23 -0
  47. package/dist/src/data/rules/cellCountPerZoneRule.js +39 -0
  48. package/dist/src/data/rules/cellCountRule.d.ts +33 -0
  49. package/dist/src/data/rules/cellCountRule.js +138 -0
  50. package/dist/src/data/rules/completePatternRule.d.ts +24 -0
  51. package/dist/src/data/rules/completePatternRule.js +46 -0
  52. package/dist/src/data/rules/connectAllRule.d.ts +29 -0
  53. package/dist/src/data/rules/connectAllRule.js +88 -0
  54. package/dist/src/data/rules/connectZonesRule.d.ts +29 -0
  55. package/dist/src/data/rules/connectZonesRule.js +111 -0
  56. package/dist/src/data/rules/containsShapeRule.d.ts +34 -0
  57. package/dist/src/data/rules/containsShapeRule.js +125 -0
  58. package/dist/src/data/rules/customRule.d.ts +34 -0
  59. package/dist/src/data/rules/customRule.js +74 -0
  60. package/dist/src/data/rules/differentCountPerZoneRule.d.ts +30 -0
  61. package/dist/src/data/rules/differentCountPerZoneRule.js +96 -0
  62. package/dist/src/data/rules/exactCountPerZoneRule.d.ts +33 -0
  63. package/dist/src/data/rules/exactCountPerZoneRule.js +99 -0
  64. package/dist/src/data/rules/foresightRule.d.ts +36 -0
  65. package/dist/src/data/rules/foresightRule.js +107 -0
  66. package/dist/src/data/rules/index.d.ts +3 -0
  67. package/dist/src/data/rules/index.js +10 -0
  68. package/dist/src/data/rules/lyingSymbolRule.d.ts +31 -0
  69. package/dist/src/data/rules/lyingSymbolRule.js +207 -0
  70. package/dist/src/data/rules/musicControlLine.d.ts +82 -0
  71. package/dist/src/data/rules/musicControlLine.js +167 -0
  72. package/dist/src/data/rules/musicGridRule.d.ts +51 -0
  73. package/dist/src/data/rules/musicGridRule.js +212 -0
  74. package/dist/src/data/rules/mysteryRule.d.ts +39 -0
  75. package/dist/src/data/rules/mysteryRule.js +146 -0
  76. package/dist/src/data/rules/noLoopsRule.d.ts +29 -0
  77. package/dist/src/data/rules/noLoopsRule.js +218 -0
  78. package/dist/src/data/rules/offByXRule.d.ts +32 -0
  79. package/dist/src/data/rules/offByXRule.js +124 -0
  80. package/dist/src/data/rules/perfectionRule.d.ts +45 -0
  81. package/dist/src/data/rules/perfectionRule.js +158 -0
  82. package/dist/src/data/rules/regionAreaRule.d.ts +34 -0
  83. package/dist/src/data/rules/regionAreaRule.js +149 -0
  84. package/dist/src/data/rules/regionShapeRule.d.ts +22 -0
  85. package/dist/src/data/rules/regionShapeRule.js +58 -0
  86. package/dist/src/data/rules/rule.d.ts +18 -0
  87. package/dist/src/data/rules/rule.js +19 -0
  88. package/dist/src/data/rules/rules.gen.d.ts +23 -0
  89. package/dist/src/data/rules/rules.gen.js +27 -0
  90. package/dist/src/data/rules/sameCountPerZoneRule.d.ts +30 -0
  91. package/dist/src/data/rules/sameCountPerZoneRule.js +95 -0
  92. package/dist/src/data/rules/sameShapeRule.d.ts +28 -0
  93. package/dist/src/data/rules/sameShapeRule.js +68 -0
  94. package/dist/src/data/rules/symbolsPerRegionRule.d.ts +37 -0
  95. package/dist/src/data/rules/symbolsPerRegionRule.js +194 -0
  96. package/dist/src/data/rules/undercluedRule.d.ts +24 -0
  97. package/dist/src/data/rules/undercluedRule.js +53 -0
  98. package/dist/src/data/rules/uniqueShapeRule.d.ts +28 -0
  99. package/dist/src/data/rules/uniqueShapeRule.js +65 -0
  100. package/dist/src/data/rules/wrapAroundRule.d.ts +36 -0
  101. package/dist/src/data/rules/wrapAroundRule.js +241 -0
  102. package/dist/src/data/serializer/allSerializers.d.ts +35 -0
  103. package/dist/src/data/serializer/allSerializers.js +78 -0
  104. package/dist/src/data/serializer/compressor/allCompressors.d.ts +14 -0
  105. package/dist/src/data/serializer/compressor/allCompressors.js +43 -0
  106. package/dist/src/data/serializer/compressor/checksumCompressor.d.ts +6 -0
  107. package/dist/src/data/serializer/compressor/checksumCompressor.js +21 -0
  108. package/dist/src/data/serializer/compressor/compressorBase.d.ts +16 -0
  109. package/dist/src/data/serializer/compressor/compressorBase.js +2 -0
  110. package/dist/src/data/serializer/compressor/deflateCompressor.d.ts +7 -0
  111. package/dist/src/data/serializer/compressor/deflateCompressor.js +17 -0
  112. package/dist/src/data/serializer/compressor/gzipCompressor.d.ts +5 -0
  113. package/dist/src/data/serializer/compressor/gzipCompressor.js +9 -0
  114. package/dist/src/data/serializer/compressor/streamCompressor.d.ts +6 -0
  115. package/dist/src/data/serializer/compressor/streamCompressor.js +41 -0
  116. package/dist/src/data/serializer/serializerBase.d.ts +32 -0
  117. package/dist/src/data/serializer/serializerBase.js +2 -0
  118. package/dist/src/data/serializer/serializer_checksum.d.ts +35 -0
  119. package/dist/src/data/serializer/serializer_checksum.js +179 -0
  120. package/dist/src/data/serializer/serializer_v0.d.ts +55 -0
  121. package/dist/src/data/serializer/serializer_v0.js +484 -0
  122. package/dist/src/data/shapes.d.ts +19 -0
  123. package/dist/src/data/shapes.js +137 -0
  124. package/dist/src/data/solver/allSolvers.d.ts +3 -0
  125. package/dist/src/data/solver/allSolvers.js +13 -0
  126. package/dist/src/data/solver/auto/autoSolver.d.ts +18 -0
  127. package/dist/src/data/solver/auto/autoSolver.js +156 -0
  128. package/dist/src/data/solver/backtrack/backtrackSolver.d.ts +11 -0
  129. package/dist/src/data/solver/backtrack/backtrackSolver.js +54 -0
  130. package/dist/src/data/solver/backtrack/backtrackWorker.d.ts +1 -0
  131. package/dist/src/data/solver/backtrack/backtrackWorker.js +312 -0
  132. package/dist/src/data/solver/backtrack/data.d.ts +47 -0
  133. package/dist/src/data/solver/backtrack/data.js +151 -0
  134. package/dist/src/data/solver/backtrack/rules/banPattern.d.ts +9 -0
  135. package/dist/src/data/solver/backtrack/rules/banPattern.js +77 -0
  136. package/dist/src/data/solver/backtrack/rules/cellCount.d.ts +7 -0
  137. package/dist/src/data/solver/backtrack/rules/cellCount.js +25 -0
  138. package/dist/src/data/solver/backtrack/rules/connectAll.d.ts +7 -0
  139. package/dist/src/data/solver/backtrack/rules/connectAll.js +44 -0
  140. package/dist/src/data/solver/backtrack/rules/regionArea.d.ts +8 -0
  141. package/dist/src/data/solver/backtrack/rules/regionArea.js +71 -0
  142. package/dist/src/data/solver/backtrack/rules/regionShape.d.ts +8 -0
  143. package/dist/src/data/solver/backtrack/rules/regionShape.js +57 -0
  144. package/dist/src/data/solver/backtrack/rules/sameShape.d.ts +8 -0
  145. package/dist/src/data/solver/backtrack/rules/sameShape.js +14 -0
  146. package/dist/src/data/solver/backtrack/rules/symbolsPerRegion.d.ts +10 -0
  147. package/dist/src/data/solver/backtrack/rules/symbolsPerRegion.js +102 -0
  148. package/dist/src/data/solver/backtrack/rules/uniqueShape.d.ts +8 -0
  149. package/dist/src/data/solver/backtrack/rules/uniqueShape.js +14 -0
  150. package/dist/src/data/solver/backtrack/symbols/areaNumber.d.ts +9 -0
  151. package/dist/src/data/solver/backtrack/symbols/areaNumber.js +75 -0
  152. package/dist/src/data/solver/backtrack/symbols/dart.d.ts +8 -0
  153. package/dist/src/data/solver/backtrack/symbols/dart.js +45 -0
  154. package/dist/src/data/solver/backtrack/symbols/directionLinker.d.ts +11 -0
  155. package/dist/src/data/solver/backtrack/symbols/directionLinker.js +121 -0
  156. package/dist/src/data/solver/backtrack/symbols/focus.d.ts +9 -0
  157. package/dist/src/data/solver/backtrack/symbols/focus.js +48 -0
  158. package/dist/src/data/solver/backtrack/symbols/galaxy.d.ts +9 -0
  159. package/dist/src/data/solver/backtrack/symbols/galaxy.js +14 -0
  160. package/dist/src/data/solver/backtrack/symbols/letter.d.ts +9 -0
  161. package/dist/src/data/solver/backtrack/symbols/letter.js +95 -0
  162. package/dist/src/data/solver/backtrack/symbols/lotus.d.ts +11 -0
  163. package/dist/src/data/solver/backtrack/symbols/lotus.js +55 -0
  164. package/dist/src/data/solver/backtrack/symbols/minesweeper.d.ts +9 -0
  165. package/dist/src/data/solver/backtrack/symbols/minesweeper.js +44 -0
  166. package/dist/src/data/solver/backtrack/symbols/myopia.d.ts +7 -0
  167. package/dist/src/data/solver/backtrack/symbols/myopia.js +73 -0
  168. package/dist/src/data/solver/backtrack/symbols/viewpoint.d.ts +7 -0
  169. package/dist/src/data/solver/backtrack/symbols/viewpoint.js +51 -0
  170. package/dist/src/data/solver/cspuz/cspuzSolver.d.ts +13 -0
  171. package/dist/src/data/solver/cspuz/cspuzSolver.js +124 -0
  172. package/dist/src/data/solver/cspuz/cspuzWorker.d.ts +1 -0
  173. package/dist/src/data/solver/cspuz/cspuzWorker.js +82 -0
  174. package/dist/src/data/solver/cspuz/jsonify.d.ts +3 -0
  175. package/dist/src/data/solver/cspuz/jsonify.js +215 -0
  176. package/dist/src/data/solver/eventIteratingSolver.d.ts +8 -0
  177. package/dist/src/data/solver/eventIteratingSolver.js +54 -0
  178. package/dist/src/data/solver/solver.d.ts +77 -0
  179. package/dist/src/data/solver/solver.js +59 -0
  180. package/dist/src/data/solver/universal/universalSolver.d.ts +7 -0
  181. package/dist/src/data/solver/universal/universalSolver.js +13 -0
  182. package/dist/src/data/solver/universal/universalWorker.d.ts +1 -0
  183. package/dist/src/data/solver/universal/universalWorker.js +128 -0
  184. package/dist/src/data/symbols/areaNumberSymbol.d.ts +31 -0
  185. package/dist/src/data/symbols/areaNumberSymbol.js +80 -0
  186. package/dist/src/data/symbols/customIconSymbol.d.ts +35 -0
  187. package/dist/src/data/symbols/customIconSymbol.js +94 -0
  188. package/dist/src/data/symbols/customSymbol.d.ts +25 -0
  189. package/dist/src/data/symbols/customSymbol.js +45 -0
  190. package/dist/src/data/symbols/customTextSymbol.d.ts +35 -0
  191. package/dist/src/data/symbols/customTextSymbol.js +95 -0
  192. package/dist/src/data/symbols/dartSymbol.d.ts +36 -0
  193. package/dist/src/data/symbols/dartSymbol.js +96 -0
  194. package/dist/src/data/symbols/directionLinkerSymbol.d.ts +29 -0
  195. package/dist/src/data/symbols/directionLinkerSymbol.js +232 -0
  196. package/dist/src/data/symbols/everyLetterSymbol.d.ts +32 -0
  197. package/dist/src/data/symbols/everyLetterSymbol.js +119 -0
  198. package/dist/src/data/symbols/focusSymbol.d.ts +40 -0
  199. package/dist/src/data/symbols/focusSymbol.js +159 -0
  200. package/dist/src/data/symbols/galaxySymbol.d.ts +27 -0
  201. package/dist/src/data/symbols/galaxySymbol.js +61 -0
  202. package/dist/src/data/symbols/hiddenSymbol.d.ts +38 -0
  203. package/dist/src/data/symbols/hiddenSymbol.js +113 -0
  204. package/dist/src/data/symbols/houseSymbol.d.ts +33 -0
  205. package/dist/src/data/symbols/houseSymbol.js +104 -0
  206. package/dist/src/data/symbols/index.d.ts +3 -0
  207. package/dist/src/data/symbols/index.js +10 -0
  208. package/dist/src/data/symbols/letterSymbol.d.ts +32 -0
  209. package/dist/src/data/symbols/letterSymbol.js +118 -0
  210. package/dist/src/data/symbols/lotusSymbol.d.ts +30 -0
  211. package/dist/src/data/symbols/lotusSymbol.js +132 -0
  212. package/dist/src/data/symbols/minesweeperSymbol.d.ts +33 -0
  213. package/dist/src/data/symbols/minesweeperSymbol.js +106 -0
  214. package/dist/src/data/symbols/myopiaSymbol.d.ts +37 -0
  215. package/dist/src/data/symbols/myopiaSymbol.js +182 -0
  216. package/dist/src/data/symbols/numberSymbol.d.ts +19 -0
  217. package/dist/src/data/symbols/numberSymbol.js +32 -0
  218. package/dist/src/data/symbols/symbol.d.ts +29 -0
  219. package/dist/src/data/symbols/symbol.js +87 -0
  220. package/dist/src/data/symbols/symbols.gen.d.ts +15 -0
  221. package/dist/src/data/symbols/symbols.gen.js +19 -0
  222. package/dist/src/data/symbols/unsupportedSymbol.d.ts +23 -0
  223. package/dist/src/data/symbols/unsupportedSymbol.js +47 -0
  224. package/dist/src/data/symbols/viewpointSymbol.d.ts +32 -0
  225. package/dist/src/data/symbols/viewpointSymbol.js +95 -0
  226. package/dist/src/data/tile.d.ts +26 -0
  227. package/dist/src/data/tile.js +56 -0
  228. package/dist/src/data/tileConnections.d.ts +25 -0
  229. package/dist/src/data/tileConnections.js +74 -0
  230. package/dist/src/data/validate.d.ts +5 -0
  231. package/dist/src/data/validate.js +131 -0
  232. package/dist/src/data/validateAsync.d.ts +15 -0
  233. package/dist/src/data/validateAsync.js +71 -0
  234. package/dist/src/data/validateAsyncWorker.d.ts +1 -0
  235. package/dist/src/data/validateAsyncWorker.js +9 -0
  236. package/dist/src/index.d.ts +109 -0
  237. package/dist/src/index.js +112 -0
  238. package/dist/src/polyfill/streamPolyfill.d.ts +2 -0
  239. package/dist/src/polyfill/streamPolyfill.js +1 -0
  240. package/package.json +3 -1
@@ -0,0 +1,156 @@
1
+ import { Color, State } from '../../primitives.js';
2
+ import { instance as lyingSymbolInstance } from '../../rules/lyingSymbolRule.js';
3
+ import { instance as offByXInstance } from '../../rules/offByXRule.js';
4
+ import { instance as wrapAroundInstance } from '../../rules/wrapAroundRule.js';
5
+ import { instance as areaNumberInstance } from '../../symbols/areaNumberSymbol.js';
6
+ import { instance as letterInstance } from '../../symbols/letterSymbol.js';
7
+ import { allSolvers } from '../allSolvers.js';
8
+ import Solver from '../solver.js';
9
+ import UndercluedRule from '../../rules/undercluedRule.js';
10
+ import validateGrid from '../../validate.js';
11
+ import UnsupportedSymbol from '../../symbols/unsupportedSymbol.js';
12
+ export default class AutoSolver extends Solver {
13
+ id = 'auto';
14
+ author = 'various contributors';
15
+ description = 'Automatically select the fastest solver based on supported instructions and environment.';
16
+ supportsCancellation = true;
17
+ static nonAdditiveInstructions = new Set([
18
+ offByXInstance.id,
19
+ lyingSymbolInstance.id,
20
+ wrapAroundInstance.id,
21
+ ]);
22
+ isGridSupported(grid) {
23
+ for (const solver of allSolvers.values()) {
24
+ if (solver.id === this.id)
25
+ continue;
26
+ if (solver.isGridSupported(grid)) {
27
+ return true;
28
+ }
29
+ }
30
+ return false;
31
+ }
32
+ isInstructionSupported(grid, instruction) {
33
+ for (const solver of allSolvers.values()) {
34
+ if (solver.id === this.id)
35
+ continue;
36
+ if (solver.isInstructionSupported(grid, instruction)) {
37
+ return true;
38
+ }
39
+ }
40
+ return false;
41
+ }
42
+ async isEnvironmentSupported() {
43
+ for (const solver of allSolvers.values()) {
44
+ if (solver.id === this.id)
45
+ continue;
46
+ if (await solver.environmentCheck.value) {
47
+ return true;
48
+ }
49
+ }
50
+ return false;
51
+ }
52
+ fillSolution(grid, solution) {
53
+ return grid.withTiles(tiles => {
54
+ return tiles.map((row, y) => row.map((tile, x) => {
55
+ if (!tile.exists || tile.fixed)
56
+ return tile;
57
+ const solutionTile = solution.tiles[y][x];
58
+ return tile.withColor(solutionTile.color);
59
+ }));
60
+ });
61
+ }
62
+ fixGrid(grid) {
63
+ return grid.withTiles(tiles => {
64
+ return tiles.map(row => row.map(tile => {
65
+ if (tile.fixed)
66
+ return tile;
67
+ return tile.withFixed(tile.color !== Color.Gray);
68
+ }));
69
+ });
70
+ }
71
+ async *solveWithProgress(solver, grid, progress, abortSignal) {
72
+ for await (const updatedGrid of solver.solve(progress, abortSignal)) {
73
+ if (abortSignal?.aborted)
74
+ return;
75
+ if (!updatedGrid) {
76
+ yield updatedGrid;
77
+ return;
78
+ }
79
+ yield this.fillSolution(grid, updatedGrid);
80
+ }
81
+ }
82
+ async solveOne(generator) {
83
+ for await (const grid of generator) {
84
+ return grid;
85
+ }
86
+ return null;
87
+ }
88
+ async *solve(grid, abortSignal) {
89
+ if (!!grid.findRule(r => AutoSolver.nonAdditiveInstructions.has(r.id)) ||
90
+ !!grid.findSymbol(s => AutoSolver.nonAdditiveInstructions.has(s.id))) {
91
+ for (const solver of allSolvers.values()) {
92
+ if (solver.id === this.id)
93
+ continue;
94
+ if (solver.isGridSupported(grid)) {
95
+ yield* solver.solve(grid, abortSignal);
96
+ return;
97
+ }
98
+ }
99
+ throw new Error('No solver supports the given grid');
100
+ }
101
+ else {
102
+ let progressGrid = grid;
103
+ for (const solver of allSolvers.values()) {
104
+ if (solver.id === this.id)
105
+ continue;
106
+ if (solver.isGridSupported(progressGrid)) {
107
+ yield* this.solveWithProgress(solver, grid, progressGrid, abortSignal);
108
+ return;
109
+ }
110
+ else if (solver.isGridSupported(grid)) {
111
+ yield* solver.solve(grid, abortSignal);
112
+ return;
113
+ }
114
+ else {
115
+ const undercluedGrid = progressGrid
116
+ .withRules(rules => rules.filter(r => solver.isInstructionSupported(progressGrid, r)))
117
+ .withSymbols(symbols => {
118
+ for (const [id, symbolList] of symbols.entries()) {
119
+ symbols.set(id, symbolList.map(symbol => {
120
+ // special handling: do not delete area number and letter symbols as they can be solved
121
+ // underclued even if the solver doesn't fully support them
122
+ if (symbol.id === areaNumberInstance.id ||
123
+ symbol.id === letterInstance.id)
124
+ return symbol;
125
+ if (solver.isInstructionSupported(progressGrid, symbol))
126
+ return symbol;
127
+ return new UnsupportedSymbol(symbol.x, symbol.y);
128
+ }));
129
+ }
130
+ return symbols;
131
+ })
132
+ .addRule(new UndercluedRule());
133
+ if (!solver.isGridSupported(undercluedGrid))
134
+ continue;
135
+ const undercluedSolution = await this.solveOne(this.solveWithProgress(solver, progressGrid, undercluedGrid, abortSignal));
136
+ if (undercluedSolution === null)
137
+ continue;
138
+ if (undercluedSolution.getTileCount(true, false, Color.Gray) === 0) {
139
+ const result = this.fillSolution(grid, undercluedSolution);
140
+ if (validateGrid(result, null).final !== State.Error) {
141
+ yield result;
142
+ yield null;
143
+ return;
144
+ }
145
+ else {
146
+ yield null;
147
+ return;
148
+ }
149
+ }
150
+ progressGrid = this.fixGrid(undercluedSolution);
151
+ }
152
+ }
153
+ yield this.fillSolution(grid, progressGrid);
154
+ }
155
+ }
156
+ }
@@ -0,0 +1,11 @@
1
+ import EventIteratingSolver from '../eventIteratingSolver.js';
2
+ import Instruction from '../../instruction.js';
3
+ import GridData from '../../grid.js';
4
+ export default class BacktrackSolver extends EventIteratingSolver {
5
+ private static readonly supportedInstrs;
6
+ readonly id = "backtrack";
7
+ readonly author = "ALaggyDev";
8
+ readonly description = "Solves puzzles pretty fast using backtracking with optimizations. Support most rules and symbols (including underclued).";
9
+ protected createWorker(): Worker;
10
+ isInstructionSupported(_grid: GridData, instruction: Instruction): boolean;
11
+ }
@@ -0,0 +1,54 @@
1
+ import { instance as banPatternInstance } from '../../rules/banPatternRule.js';
2
+ import { instance as cellCountInstance } from '../../rules/cellCountRule.js';
3
+ import { instance as regionAreaInstance } from '../../rules/regionAreaRule.js';
4
+ import { instance as sameShapeInstance } from '../../rules/sameShapeRule.js';
5
+ import { instance as symbolsPerRegionInstance } from '../../rules/symbolsPerRegionRule.js';
6
+ import { instance as undercluedInstance } from '../../rules/undercluedRule.js';
7
+ import { instance as uniqueShapeInstance } from '../../rules/uniqueShapeRule.js';
8
+ import { instance as areaNumberInstance } from '../../symbols/areaNumberSymbol.js';
9
+ import { instance as dartInstance } from '../../symbols/dartSymbol.js';
10
+ import { instance as galaxyInstance } from '../../symbols/galaxySymbol.js';
11
+ import { instance as letterInstance } from '../../symbols/letterSymbol.js';
12
+ import { instance as lotusInstance } from '../../symbols/lotusSymbol.js';
13
+ import { instance as minesweeperInstance } from '../../symbols/minesweeperSymbol.js';
14
+ import { instance as focusInstance } from '../../symbols/focusSymbol.js';
15
+ import { instance as myopiaInstance } from '../../symbols/myopiaSymbol.js';
16
+ import { instance as viewpointInstance } from '../../symbols/viewpointSymbol.js';
17
+ import { instance as connectAllInstance } from '../../rules/connectAllRule.js';
18
+ import { instance as unsupportedInstance } from '../../symbols/unsupportedSymbol.js';
19
+ import EventIteratingSolver from '../eventIteratingSolver.js';
20
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
21
+ ('vite-apply-code-mod');
22
+ export default class BacktrackSolver extends EventIteratingSolver {
23
+ static supportedInstrs = [
24
+ areaNumberInstance.id,
25
+ viewpointInstance.id,
26
+ dartInstance.id,
27
+ galaxyInstance.id,
28
+ lotusInstance.id,
29
+ myopiaInstance.id,
30
+ minesweeperInstance.id,
31
+ focusInstance.id,
32
+ letterInstance.id,
33
+ undercluedInstance.id,
34
+ connectAllInstance.id,
35
+ banPatternInstance.id,
36
+ regionAreaInstance.id,
37
+ symbolsPerRegionInstance.id,
38
+ cellCountInstance.id,
39
+ sameShapeInstance.id,
40
+ uniqueShapeInstance.id,
41
+ unsupportedInstance.id,
42
+ ];
43
+ id = 'backtrack';
44
+ author = 'ALaggyDev';
45
+ description = 'Solves puzzles pretty fast using backtracking with optimizations. Support most rules and symbols (including underclued).';
46
+ createWorker() {
47
+ return new Worker(new URL(`./backtrackWorker.js`, import.meta.url), {
48
+ type: 'module',
49
+ });
50
+ }
51
+ isInstructionSupported(_grid, instruction) {
52
+ return BacktrackSolver.supportedInstrs.includes(instruction.id);
53
+ }
54
+ }
@@ -0,0 +1,312 @@
1
+ import { array } from '../../dataHelper.js';
2
+ import { Color } from '../../primitives.js';
3
+ import { instance as banPatternInstance, } from '../../rules/banPatternRule.js';
4
+ import { instance as cellCountInstance, } from '../../rules/cellCountRule.js';
5
+ import { instance as connectAllInstance, } from '../../rules/connectAllRule.js';
6
+ import { instance as regionAreaInstance, } from '../../rules/regionAreaRule.js';
7
+ import { instance as sameShapeInstance, } from '../../rules/sameShapeRule.js';
8
+ import { instance as symbolsPerRegionInstance, } from '../../rules/symbolsPerRegionRule.js';
9
+ import { instance as undercluedInstance } from '../../rules/undercluedRule.js';
10
+ import { instance as uniqueShapeInstance, } from '../../rules/uniqueShapeRule.js';
11
+ import { Serializer } from '../../serializer/allSerializers.js';
12
+ import { instance as areaNumberInstance, } from '../../symbols/areaNumberSymbol.js';
13
+ import { instance as dartInstance, } from '../../symbols/dartSymbol.js';
14
+ import { instance as galaxyInstance, } from '../../symbols/galaxySymbol.js';
15
+ import { instance as letterInstance, } from '../../symbols/letterSymbol.js';
16
+ import { instance as lotusInstance, } from '../../symbols/lotusSymbol.js';
17
+ import { instance as minesweeperInstance, } from '../../symbols/minesweeperSymbol.js';
18
+ import { instance as focusInstance, } from '../../symbols/focusSymbol.js';
19
+ import { instance as myopiaInstance, } from '../../symbols/myopiaSymbol.js';
20
+ import { instance as viewpointInstance, } from '../../symbols/viewpointSymbol.js';
21
+ import { instance as unsupportedInstance } from '../../symbols/unsupportedSymbol.js';
22
+ import { BTGridData, BTTile } from './data.js';
23
+ import BanPatternBTModule from './rules/banPattern.js';
24
+ import CellCountBTModule from './rules/cellCount.js';
25
+ import ConnectAllBTModule from './rules/connectAll.js';
26
+ import RegionAreaBTModule from './rules/regionArea.js';
27
+ import SameShapeBTModule from './rules/sameShape.js';
28
+ import SymbolsPerRegionBTModule from './rules/symbolsPerRegion.js';
29
+ import UniqueShapeBTModule from './rules/uniqueShape.js';
30
+ import AreaNumberBTModule from './symbols/areaNumber.js';
31
+ import DartBTModule from './symbols/dart.js';
32
+ import GalaxyBTModule from './symbols/galaxy.js';
33
+ import LetterBTModule from './symbols/letter.js';
34
+ import LotusBTModule from './symbols/lotus.js';
35
+ import MinesweeperBTModule from './symbols/minesweeper.js';
36
+ import MyopiaBTModule from './symbols/myopia.js';
37
+ import ViewpointBTModule from './symbols/viewpoint.js';
38
+ import FocusBTModule from './symbols/focus.js';
39
+ function translateToBTGridData(grid) {
40
+ const tiles = array(grid.width, grid.height, (x, y) => {
41
+ const tile = grid.getTile(x, y);
42
+ if (!tile.exists)
43
+ return BTTile.NonExist;
44
+ else if (tile.color === Color.Dark)
45
+ return BTTile.Dark;
46
+ else if (tile.color === Color.Light)
47
+ return BTTile.Light;
48
+ else
49
+ return BTTile.Empty;
50
+ });
51
+ const connections = array(grid.width, grid.height, (x, y) => grid.connections.getConnectedTiles({ x, y }));
52
+ const modules = [];
53
+ for (const [id, symbolList] of grid.symbols) {
54
+ for (const symbol of symbolList) {
55
+ let module;
56
+ if (id === areaNumberInstance.id) {
57
+ module = new AreaNumberBTModule(symbol);
58
+ }
59
+ else if (id === dartInstance.id) {
60
+ module = new DartBTModule(symbol);
61
+ }
62
+ else if (id === viewpointInstance.id) {
63
+ module = new ViewpointBTModule(symbol);
64
+ }
65
+ else if (id === galaxyInstance.id) {
66
+ module = new GalaxyBTModule(symbol);
67
+ }
68
+ else if (id === lotusInstance.id) {
69
+ module = new LotusBTModule(symbol);
70
+ }
71
+ else if (id === myopiaInstance.id) {
72
+ module = new MyopiaBTModule(symbol);
73
+ }
74
+ else if (id === minesweeperInstance.id) {
75
+ module = new MinesweeperBTModule(symbol);
76
+ }
77
+ else if (id === focusInstance.id) {
78
+ module = new FocusBTModule(symbol);
79
+ }
80
+ else if (id === letterInstance.id) {
81
+ continue;
82
+ }
83
+ else if (id === unsupportedInstance.id) {
84
+ continue;
85
+ }
86
+ if (!module && symbol.necessaryForCompletion)
87
+ throw new Error('Symbol not supported.');
88
+ if (module)
89
+ modules.push(module);
90
+ }
91
+ }
92
+ const letterSymbols = grid.symbols.get(letterInstance.id);
93
+ if (letterSymbols) {
94
+ modules.push(new LetterBTModule(letterSymbols, grid.width, grid.height));
95
+ }
96
+ for (const rule of grid.rules) {
97
+ if (!rule.necessaryForCompletion)
98
+ continue;
99
+ let module;
100
+ if (rule.id === connectAllInstance.id) {
101
+ module = new ConnectAllBTModule(rule);
102
+ }
103
+ else if (rule.id === regionAreaInstance.id) {
104
+ module = new RegionAreaBTModule(rule);
105
+ }
106
+ else if (rule.id === banPatternInstance.id) {
107
+ module = new BanPatternBTModule(rule);
108
+ }
109
+ else if (rule.id === symbolsPerRegionInstance.id) {
110
+ const allSymbols = [];
111
+ grid.symbols.forEach(symbols => allSymbols.push(...symbols.filter(symbol => symbol.necessaryForCompletion)));
112
+ module = new SymbolsPerRegionBTModule(rule, grid.width, grid.height, allSymbols);
113
+ }
114
+ else if (rule.id === cellCountInstance.id) {
115
+ module = new CellCountBTModule(rule);
116
+ }
117
+ else if (rule.id === sameShapeInstance.id) {
118
+ module = new SameShapeBTModule(rule);
119
+ }
120
+ else if (rule.id === uniqueShapeInstance.id) {
121
+ module = new UniqueShapeBTModule(rule);
122
+ }
123
+ else if (rule.id === undercluedInstance.id) {
124
+ continue;
125
+ }
126
+ if (!module)
127
+ throw new Error('Rule not supported.');
128
+ modules.push(module);
129
+ }
130
+ return new BTGridData(tiles, connections, modules, grid.width, grid.height);
131
+ }
132
+ function translateBackGridData(grid, btGrid) {
133
+ const tiles = array(grid.width, grid.height, (x, y) => {
134
+ const origTile = grid.getTile(x, y);
135
+ if (!origTile.exists || origTile.fixed || origTile.color !== Color.Gray)
136
+ return origTile;
137
+ else
138
+ return origTile.withColor(btGrid.getTile(x, y) === BTTile.Dark ? Color.Dark : Color.Light);
139
+ });
140
+ return grid.withTiles(tiles);
141
+ }
142
+ function isValid(grid, places, checkable, ratings) {
143
+ const newCheckable = [...checkable];
144
+ const newRatings = [...ratings];
145
+ for (let i = 0; i < grid.modules.length; i++) {
146
+ const module = grid.modules[i];
147
+ // Check if skippable
148
+ if (checkable[i] && !places.some(pos => checkable[i].get(pos.x, pos.y)))
149
+ continue;
150
+ const result = module.checkLocal(grid, places);
151
+ if (!result)
152
+ return false;
153
+ // If returns true, it means do not change checkable and ratings
154
+ if (result === true)
155
+ continue;
156
+ newCheckable[i] = result.tilesNeedCheck;
157
+ newRatings[i] = result.ratings;
158
+ }
159
+ return [newCheckable, newRatings];
160
+ }
161
+ // This function chooses the next empty tile to search.
162
+ function getNextTile(grid, ratings) {
163
+ const scores = [];
164
+ // TODO: Sum up all the scores of connected tiles without overcounting
165
+ for (let y = 0; y < grid.height; y++) {
166
+ scores[y] = [];
167
+ for (let x = 0; x < grid.width; x++) {
168
+ scores[y][x] = 0;
169
+ }
170
+ }
171
+ for (const rating of ratings) {
172
+ if (!rating)
173
+ continue;
174
+ for (const score of rating) {
175
+ scores[score.pos.y][score.pos.x] += score.score;
176
+ }
177
+ }
178
+ let highest = 0;
179
+ let pos = null;
180
+ let fallback = null;
181
+ for (let y = 0; y < grid.height; y++) {
182
+ for (let x = 0; x < grid.width; x++) {
183
+ if (grid.getTile(x, y) !== BTTile.Empty)
184
+ continue;
185
+ if (scores[y][x] > highest) {
186
+ highest = scores[y][x];
187
+ pos = { x, y };
188
+ }
189
+ fallback ??= { x, y };
190
+ }
191
+ }
192
+ return pos ?? fallback;
193
+ }
194
+ function backtrack(grid, checkable, ratings, solutionFn) {
195
+ // Find the best empty cell to guess
196
+ const pos = getNextTile(grid, ratings);
197
+ // Found a solution
198
+ if (!pos)
199
+ return !solutionFn(grid.clone());
200
+ for (let i = 0; i <= 1; i++) {
201
+ // TODO: Use a better method to determine the order
202
+ const tile = i === 0 ? BTTile.Light : BTTile.Dark;
203
+ grid.setTileWithConnection(pos.x, pos.y, tile);
204
+ const places = grid.connections[pos.y][pos.x];
205
+ const result = isValid(grid, places, checkable, ratings);
206
+ if (result && backtrack(grid, result[0], result[1], solutionFn))
207
+ return true;
208
+ }
209
+ // If both fail, returns to initial state
210
+ grid.setTileWithConnection(pos.x, pos.y, BTTile.Empty);
211
+ return false;
212
+ }
213
+ function solveNormal(input, solutionFn) {
214
+ // Translate to BT data types
215
+ const grid = translateToBTGridData(input);
216
+ const checkable = [];
217
+ const ratings = [];
218
+ for (const module of grid.modules) {
219
+ const res = module.checkGlobal(grid);
220
+ if (!res)
221
+ return [];
222
+ checkable.push(res.tilesNeedCheck);
223
+ ratings.push(res.ratings);
224
+ }
225
+ // Call backtrack
226
+ backtrack(grid, checkable, ratings, sol => solutionFn(translateBackGridData(input, sol)));
227
+ }
228
+ function solveUnderclued(input) {
229
+ let grid = input;
230
+ // let count = 0;
231
+ const possibles = array(grid.width, grid.height, () => ({
232
+ dark: false,
233
+ light: false,
234
+ }));
235
+ function search(x, y, tile, color) {
236
+ // count++;
237
+ // console.log(`Trying (${x}, ${y}) with ${color}`);
238
+ const newGrid = grid.copyWith({
239
+ tiles: grid.setTile(x, y, tile.withColor(color)),
240
+ }, false, false);
241
+ // Solve
242
+ let solution;
243
+ solveNormal(newGrid, sol => {
244
+ solution = sol;
245
+ return false;
246
+ });
247
+ if (!solution)
248
+ return false;
249
+ // Update the new possible states
250
+ solution.forEach((solTile, solX, solY) => {
251
+ if (solTile.color === Color.Dark) {
252
+ possibles[solY][solX].dark = true;
253
+ }
254
+ else {
255
+ possibles[solY][solX].light = true;
256
+ }
257
+ });
258
+ return true;
259
+ }
260
+ for (let y = 0; y < grid.height; y++) {
261
+ for (let x = 0; x < grid.width; x++) {
262
+ const tile = grid.getTile(x, y);
263
+ if (!tile.exists || tile.color !== Color.Gray)
264
+ continue;
265
+ // We can skip this solve if it is proved to be solvable
266
+ const darkPossible = possibles[y][x].dark || search(x, y, tile, Color.Dark);
267
+ const lightPossible = possibles[y][x].light || search(x, y, tile, Color.Light);
268
+ // No solution
269
+ if (!darkPossible && !lightPossible)
270
+ return null;
271
+ if (darkPossible && !lightPossible)
272
+ grid = grid.copyWith({
273
+ tiles: grid.setTile(x, y, tile.withColor(Color.Dark)),
274
+ }, false, false);
275
+ if (!darkPossible && lightPossible)
276
+ grid = grid.copyWith({
277
+ tiles: grid.setTile(x, y, tile.withColor(Color.Light)),
278
+ }, false, false);
279
+ }
280
+ }
281
+ // console.log(`Solve count: ${count}`);
282
+ return grid;
283
+ }
284
+ function solve(grid, solutionFn) {
285
+ if (grid.findRule(rule => rule.id === undercluedInstance.id)) {
286
+ const res = solveUnderclued(grid);
287
+ if (res)
288
+ solutionFn(res);
289
+ }
290
+ else {
291
+ solveNormal(grid, solutionFn);
292
+ }
293
+ }
294
+ onmessage = e => {
295
+ const grid = Serializer.parseGrid(e.data);
296
+ // console.time('Solve time');
297
+ let count = 0;
298
+ solve(grid, solution => {
299
+ // if (count === 0) console.timeLog('Solve time', 'First solution');
300
+ // if (solution) {
301
+ // if (solution.resetTiles().colorEquals(solution)) {
302
+ // postMessage(null);
303
+ // return false;
304
+ // }
305
+ // }
306
+ postMessage(Serializer.stringifyGrid(solution));
307
+ count += 1;
308
+ return count < 2;
309
+ });
310
+ // console.timeEnd('Solve time');
311
+ postMessage(null);
312
+ };
@@ -0,0 +1,47 @@
1
+ import { Color, Position } from '../../primitives.js';
2
+ export declare enum BTTile {
3
+ Empty = 0,
4
+ Dark = 1,
5
+ Light = 2,
6
+ NonExist = 3
7
+ }
8
+ export type BTColor = BTTile.Dark | BTTile.Light;
9
+ export declare class BTGridData {
10
+ readonly tiles: BTTile[][];
11
+ readonly connections: Position[][][];
12
+ readonly modules: BTModule[];
13
+ readonly width: number;
14
+ readonly height: number;
15
+ constructor(tiles: BTTile[][], connections: Position[][][], modules: BTModule[], width: number, height: number);
16
+ getTile(x: number, y: number): BTTile;
17
+ setTileWithConnection(x: number, y: number, tile: BTTile): void;
18
+ isInBound(x: number, y: number): boolean;
19
+ getEdges(pos: Position): Position[];
20
+ clone(): BTGridData;
21
+ }
22
+ export declare class IntArray2D {
23
+ private readonly array;
24
+ readonly width: number;
25
+ readonly height: number;
26
+ private constructor();
27
+ static create(width: number, height: number): IntArray2D;
28
+ set(x: number, y: number, value: number): void;
29
+ get(x: number, y: number): number;
30
+ clone(): IntArray2D;
31
+ }
32
+ export interface CheckResult {
33
+ tilesNeedCheck: IntArray2D | null;
34
+ ratings: Rating[] | null;
35
+ }
36
+ export interface Rating {
37
+ pos: Position;
38
+ score: number;
39
+ }
40
+ export default abstract class BTModule {
41
+ abstract checkGlobal(grid: BTGridData): CheckResult | false;
42
+ checkLocal(grid: BTGridData, _: Position[]): CheckResult | boolean;
43
+ }
44
+ export declare function getOppositeColor(color: BTColor): BTColor;
45
+ export declare function colorToBTTile(color: Color): BTTile;
46
+ export declare function createOneTileResult(grid: BTGridData, pos: Position, score?: number | undefined): CheckResult;
47
+ export declare function checkSubtilePlacement(grid: BTGridData, pos: Position): CheckResult | false | undefined;