@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.
Files changed (211) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +19 -0
  3. package/assets/logic-core.global.d.ts +5865 -0
  4. package/assets/z3-built.js +14723 -0
  5. package/assets/z3-built.wasm +0 -0
  6. package/assets/z3-built.worker.js +206 -0
  7. package/dist/data/config.d.ts +101 -0
  8. package/dist/data/config.js +55 -0
  9. package/dist/data/configurable.d.ts +12 -0
  10. package/dist/data/configurable.js +26 -0
  11. package/dist/data/dataHelper.d.ts +77 -0
  12. package/dist/data/dataHelper.js +190 -0
  13. package/dist/data/events/eventHelper.d.ts +1 -0
  14. package/dist/data/events/eventHelper.js +6 -0
  15. package/dist/data/events/onFinalValidation.d.ts +14 -0
  16. package/dist/data/events/onFinalValidation.js +4 -0
  17. package/dist/data/events/onGridChange.d.ts +6 -0
  18. package/dist/data/events/onGridChange.js +4 -0
  19. package/dist/data/events/onGridResize.d.ts +9 -0
  20. package/dist/data/events/onGridResize.js +4 -0
  21. package/dist/data/events/onSetGrid.d.ts +6 -0
  22. package/dist/data/events/onSetGrid.js +4 -0
  23. package/dist/data/events/onSymbolValidation.d.ts +18 -0
  24. package/dist/data/events/onSymbolValidation.js +4 -0
  25. package/dist/data/grid.d.ts +362 -0
  26. package/dist/data/grid.js +886 -0
  27. package/dist/data/gridConnections.d.ts +38 -0
  28. package/dist/data/gridConnections.js +328 -0
  29. package/dist/data/instruction.d.ts +19 -0
  30. package/dist/data/instruction.js +23 -0
  31. package/dist/data/primitives.d.ts +85 -0
  32. package/dist/data/primitives.js +90 -0
  33. package/dist/data/puzzle.d.ts +86 -0
  34. package/dist/data/puzzle.js +22 -0
  35. package/dist/data/rules/banPatternRule.d.ts +29 -0
  36. package/dist/data/rules/banPatternRule.js +133 -0
  37. package/dist/data/rules/cellCountRule.d.ts +32 -0
  38. package/dist/data/rules/cellCountRule.js +166 -0
  39. package/dist/data/rules/completePatternRule.d.ts +22 -0
  40. package/dist/data/rules/completePatternRule.js +53 -0
  41. package/dist/data/rules/connectAllRule.d.ts +28 -0
  42. package/dist/data/rules/connectAllRule.js +113 -0
  43. package/dist/data/rules/customRule.d.ts +32 -0
  44. package/dist/data/rules/customRule.js +92 -0
  45. package/dist/data/rules/foresightRule.d.ts +30 -0
  46. package/dist/data/rules/foresightRule.js +107 -0
  47. package/dist/data/rules/index.d.ts +3 -0
  48. package/dist/data/rules/index.js +10 -0
  49. package/dist/data/rules/musicControlLine.d.ts +64 -0
  50. package/dist/data/rules/musicControlLine.js +178 -0
  51. package/dist/data/rules/musicGridRule.d.ts +46 -0
  52. package/dist/data/rules/musicGridRule.js +211 -0
  53. package/dist/data/rules/mysteryRule.d.ts +37 -0
  54. package/dist/data/rules/mysteryRule.js +164 -0
  55. package/dist/data/rules/offByXRule.d.ts +30 -0
  56. package/dist/data/rules/offByXRule.js +134 -0
  57. package/dist/data/rules/regionAreaRule.d.ts +33 -0
  58. package/dist/data/rules/regionAreaRule.js +182 -0
  59. package/dist/data/rules/regionShapeRule.d.ts +22 -0
  60. package/dist/data/rules/regionShapeRule.js +58 -0
  61. package/dist/data/rules/rule.d.ts +18 -0
  62. package/dist/data/rules/rule.js +19 -0
  63. package/dist/data/rules/rules.gen.d.ts +14 -0
  64. package/dist/data/rules/rules.gen.js +18 -0
  65. package/dist/data/rules/sameShapeRule.d.ts +27 -0
  66. package/dist/data/rules/sameShapeRule.js +88 -0
  67. package/dist/data/rules/symbolsPerRegionRule.d.ts +37 -0
  68. package/dist/data/rules/symbolsPerRegionRule.js +211 -0
  69. package/dist/data/rules/undercluedRule.d.ts +22 -0
  70. package/dist/data/rules/undercluedRule.js +60 -0
  71. package/dist/data/rules/uniqueShapeRule.d.ts +27 -0
  72. package/dist/data/rules/uniqueShapeRule.js +85 -0
  73. package/dist/data/serializer/allSerializers.d.ts +30 -0
  74. package/dist/data/serializer/allSerializers.js +64 -0
  75. package/dist/data/serializer/compressor/allCompressors.d.ts +14 -0
  76. package/dist/data/serializer/compressor/allCompressors.js +43 -0
  77. package/dist/data/serializer/compressor/compressorBase.d.ts +16 -0
  78. package/dist/data/serializer/compressor/compressorBase.js +2 -0
  79. package/dist/data/serializer/compressor/deflateCompressor.d.ts +7 -0
  80. package/dist/data/serializer/compressor/deflateCompressor.js +17 -0
  81. package/dist/data/serializer/compressor/gzipCompressor.d.ts +5 -0
  82. package/dist/data/serializer/compressor/gzipCompressor.js +9 -0
  83. package/dist/data/serializer/compressor/streamCompressor.d.ts +6 -0
  84. package/dist/data/serializer/compressor/streamCompressor.js +36 -0
  85. package/dist/data/serializer/serializerBase.d.ts +27 -0
  86. package/dist/data/serializer/serializerBase.js +2 -0
  87. package/dist/data/serializer/serializer_v0.d.ts +36 -0
  88. package/dist/data/serializer/serializer_v0.js +426 -0
  89. package/dist/data/shapes.d.ts +17 -0
  90. package/dist/data/shapes.js +117 -0
  91. package/dist/data/solver/allSolvers.d.ts +3 -0
  92. package/dist/data/solver/allSolvers.js +11 -0
  93. package/dist/data/solver/backtrack/backtrackSolver.d.ts +9 -0
  94. package/dist/data/solver/backtrack/backtrackSolver.js +92 -0
  95. package/dist/data/solver/backtrack/backtrackWorker.d.ts +2 -0
  96. package/dist/data/solver/backtrack/backtrackWorker.js +295 -0
  97. package/dist/data/solver/backtrack/data.d.ts +46 -0
  98. package/dist/data/solver/backtrack/data.js +140 -0
  99. package/dist/data/solver/backtrack/rules/banPattern.d.ts +9 -0
  100. package/dist/data/solver/backtrack/rules/banPattern.js +66 -0
  101. package/dist/data/solver/backtrack/rules/cellCount.d.ts +7 -0
  102. package/dist/data/solver/backtrack/rules/cellCount.js +30 -0
  103. package/dist/data/solver/backtrack/rules/connectAll.d.ts +7 -0
  104. package/dist/data/solver/backtrack/rules/connectAll.js +49 -0
  105. package/dist/data/solver/backtrack/rules/regionArea.d.ts +8 -0
  106. package/dist/data/solver/backtrack/rules/regionArea.js +76 -0
  107. package/dist/data/solver/backtrack/rules/regionShape.d.ts +8 -0
  108. package/dist/data/solver/backtrack/rules/regionShape.js +62 -0
  109. package/dist/data/solver/backtrack/rules/sameShape.d.ts +8 -0
  110. package/dist/data/solver/backtrack/rules/sameShape.js +19 -0
  111. package/dist/data/solver/backtrack/rules/symbolsPerRegion.d.ts +10 -0
  112. package/dist/data/solver/backtrack/rules/symbolsPerRegion.js +92 -0
  113. package/dist/data/solver/backtrack/rules/uniqueShape.d.ts +8 -0
  114. package/dist/data/solver/backtrack/rules/uniqueShape.js +19 -0
  115. package/dist/data/solver/backtrack/symbols/areaNumber.d.ts +9 -0
  116. package/dist/data/solver/backtrack/symbols/areaNumber.js +77 -0
  117. package/dist/data/solver/backtrack/symbols/dart.d.ts +9 -0
  118. package/dist/data/solver/backtrack/symbols/dart.js +58 -0
  119. package/dist/data/solver/backtrack/symbols/directionLinker.d.ts +9 -0
  120. package/dist/data/solver/backtrack/symbols/directionLinker.js +50 -0
  121. package/dist/data/solver/backtrack/symbols/galaxy.d.ts +9 -0
  122. package/dist/data/solver/backtrack/symbols/galaxy.js +19 -0
  123. package/dist/data/solver/backtrack/symbols/letter.d.ts +9 -0
  124. package/dist/data/solver/backtrack/symbols/letter.js +100 -0
  125. package/dist/data/solver/backtrack/symbols/lotus.d.ts +9 -0
  126. package/dist/data/solver/backtrack/symbols/lotus.js +36 -0
  127. package/dist/data/solver/backtrack/symbols/minesweeper.d.ts +9 -0
  128. package/dist/data/solver/backtrack/symbols/minesweeper.js +55 -0
  129. package/dist/data/solver/backtrack/symbols/myopia.d.ts +7 -0
  130. package/dist/data/solver/backtrack/symbols/myopia.js +79 -0
  131. package/dist/data/solver/backtrack/symbols/viewpoint.d.ts +7 -0
  132. package/dist/data/solver/backtrack/symbols/viewpoint.js +56 -0
  133. package/dist/data/solver/solver.d.ts +61 -0
  134. package/dist/data/solver/solver.js +55 -0
  135. package/dist/data/solver/underclued/undercluedSolver.d.ts +8 -0
  136. package/dist/data/solver/underclued/undercluedSolver.js +55 -0
  137. package/dist/data/solver/underclued/undercluedWorker.d.ts +2 -0
  138. package/dist/data/solver/underclued/undercluedWorker.js +131 -0
  139. package/dist/data/solver/z3/modules/areaNumberModule.d.ts +9 -0
  140. package/dist/data/solver/z3/modules/areaNumberModule.js +35 -0
  141. package/dist/data/solver/z3/modules/cellCountModule.d.ts +9 -0
  142. package/dist/data/solver/z3/modules/cellCountModule.js +59 -0
  143. package/dist/data/solver/z3/modules/connectAllModule.d.ts +9 -0
  144. package/dist/data/solver/z3/modules/connectAllModule.js +32 -0
  145. package/dist/data/solver/z3/modules/dartModule.d.ts +9 -0
  146. package/dist/data/solver/z3/modules/dartModule.js +69 -0
  147. package/dist/data/solver/z3/modules/index.d.ts +3 -0
  148. package/dist/data/solver/z3/modules/index.js +10 -0
  149. package/dist/data/solver/z3/modules/letterModule.d.ts +9 -0
  150. package/dist/data/solver/z3/modules/letterModule.js +41 -0
  151. package/dist/data/solver/z3/modules/modules.gen.d.ts +8 -0
  152. package/dist/data/solver/z3/modules/modules.gen.js +12 -0
  153. package/dist/data/solver/z3/modules/myopiaModule.d.ts +9 -0
  154. package/dist/data/solver/z3/modules/myopiaModule.js +64 -0
  155. package/dist/data/solver/z3/modules/regionAreaModule.d.ts +9 -0
  156. package/dist/data/solver/z3/modules/regionAreaModule.js +48 -0
  157. package/dist/data/solver/z3/modules/viewpointModule.d.ts +9 -0
  158. package/dist/data/solver/z3/modules/viewpointModule.js +37 -0
  159. package/dist/data/solver/z3/modules/z3Module.d.ts +7 -0
  160. package/dist/data/solver/z3/modules/z3Module.js +3 -0
  161. package/dist/data/solver/z3/utils.d.ts +2 -0
  162. package/dist/data/solver/z3/utils.js +26 -0
  163. package/dist/data/solver/z3/z3Solver.d.ts +10 -0
  164. package/dist/data/solver/z3/z3Solver.js +134 -0
  165. package/dist/data/solver/z3/z3SolverContext.d.ts +808 -0
  166. package/dist/data/solver/z3/z3SolverContext.js +49 -0
  167. package/dist/data/symbols/areaNumberSymbol.d.ts +30 -0
  168. package/dist/data/symbols/areaNumberSymbol.js +88 -0
  169. package/dist/data/symbols/customIconSymbol.d.ts +35 -0
  170. package/dist/data/symbols/customIconSymbol.js +105 -0
  171. package/dist/data/symbols/customSymbol.d.ts +23 -0
  172. package/dist/data/symbols/customSymbol.js +48 -0
  173. package/dist/data/symbols/customTextSymbol.d.ts +33 -0
  174. package/dist/data/symbols/customTextSymbol.js +106 -0
  175. package/dist/data/symbols/dartSymbol.d.ts +35 -0
  176. package/dist/data/symbols/dartSymbol.js +110 -0
  177. package/dist/data/symbols/directionLinkerSymbol.d.ts +36 -0
  178. package/dist/data/symbols/directionLinkerSymbol.js +259 -0
  179. package/dist/data/symbols/galaxySymbol.d.ts +26 -0
  180. package/dist/data/symbols/galaxySymbol.js +74 -0
  181. package/dist/data/symbols/index.d.ts +3 -0
  182. package/dist/data/symbols/index.js +10 -0
  183. package/dist/data/symbols/letterSymbol.d.ts +31 -0
  184. package/dist/data/symbols/letterSymbol.js +137 -0
  185. package/dist/data/symbols/lotusSymbol.d.ts +29 -0
  186. package/dist/data/symbols/lotusSymbol.js +132 -0
  187. package/dist/data/symbols/minesweeperSymbol.d.ts +31 -0
  188. package/dist/data/symbols/minesweeperSymbol.js +100 -0
  189. package/dist/data/symbols/multiEntrySymbol.d.ts +11 -0
  190. package/dist/data/symbols/multiEntrySymbol.js +14 -0
  191. package/dist/data/symbols/myopiaSymbol.d.ts +34 -0
  192. package/dist/data/symbols/myopiaSymbol.js +187 -0
  193. package/dist/data/symbols/numberSymbol.d.ts +19 -0
  194. package/dist/data/symbols/numberSymbol.js +41 -0
  195. package/dist/data/symbols/symbol.d.ts +16 -0
  196. package/dist/data/symbols/symbol.js +51 -0
  197. package/dist/data/symbols/symbols.gen.d.ts +10 -0
  198. package/dist/data/symbols/symbols.gen.js +14 -0
  199. package/dist/data/symbols/viewpointSymbol.d.ts +31 -0
  200. package/dist/data/symbols/viewpointSymbol.js +106 -0
  201. package/dist/data/tile.d.ts +26 -0
  202. package/dist/data/tile.js +68 -0
  203. package/dist/data/tileConnections.d.ts +25 -0
  204. package/dist/data/tileConnections.js +74 -0
  205. package/dist/data/validate.d.ts +5 -0
  206. package/dist/data/validate.js +131 -0
  207. package/dist/index.d.ts +96 -0
  208. package/dist/index.js +100 -0
  209. package/dist/polyfill/streamPolyfill.d.ts +2 -0
  210. package/dist/polyfill/streamPolyfill.js +1 -0
  211. package/package.json +75 -0
@@ -0,0 +1,30 @@
1
+ import BTModule, { BTTile, colorToBTTile, } from '../data';
2
+ export default class CellCountBTModule 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 color = colorToBTTile(this.instr.color);
15
+ let colored = 0;
16
+ let possible = 0;
17
+ for (let y = 0; y < grid.height; y++) {
18
+ for (let x = 0; x < grid.width; x++) {
19
+ const tile = grid.getTile(x, y);
20
+ if (tile === color)
21
+ colored += 1;
22
+ else if (tile === BTTile.Empty)
23
+ possible += 1;
24
+ }
25
+ }
26
+ if (colored > this.instr.count || colored + possible < this.instr.count)
27
+ return false;
28
+ return { tilesNeedCheck: null, ratings: null };
29
+ }
30
+ }
@@ -0,0 +1,7 @@
1
+ import ConnectAllRule from '../../../rules/connectAllRule';
2
+ import BTModule, { BTGridData, CheckResult } from '../data';
3
+ export default class ConnectAllBTModule extends BTModule {
4
+ instr: ConnectAllRule;
5
+ constructor(instr: ConnectAllRule);
6
+ checkGlobal(grid: BTGridData): CheckResult | false;
7
+ }
@@ -0,0 +1,49 @@
1
+ import BTModule, { IntArray2D, colorToBTTile, getOppositeColor, } from '../data';
2
+ export default class ConnectAllBTModule 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 color = colorToBTTile(this.instr.color);
15
+ // Find all same cells
16
+ const sameCells = [];
17
+ for (let y = 0; y < grid.height; y++) {
18
+ for (let x = 0; x < grid.width; x++) {
19
+ if (grid.getTile(x, y) === color) {
20
+ sameCells.push({ x, y });
21
+ }
22
+ }
23
+ }
24
+ // If there are no same cells, return true
25
+ if (sameCells.length === 0)
26
+ return { tilesNeedCheck: null, ratings: null };
27
+ const queue = [sameCells[0]];
28
+ const visited = IntArray2D.create(grid.width, grid.height);
29
+ // Perform flood fill
30
+ visited.set(sameCells[0].x, sameCells[0].y, 1);
31
+ while (queue.length > 0) {
32
+ const curPos = queue.pop();
33
+ for (const edge of grid.getEdges(curPos)) {
34
+ if (visited.get(edge.x, edge.y) ||
35
+ grid.getTile(edge.x, edge.y) === getOppositeColor(color)) {
36
+ continue;
37
+ }
38
+ visited.set(edge.x, edge.y, 1);
39
+ queue.push(edge);
40
+ }
41
+ }
42
+ // Check if any same cell is not reachable
43
+ for (const cell of sameCells) {
44
+ if (!visited.get(cell.x, cell.y))
45
+ return false;
46
+ }
47
+ return { tilesNeedCheck: null, ratings: null };
48
+ }
49
+ }
@@ -0,0 +1,8 @@
1
+ import RegionAreaRule from '../../../rules/regionAreaRule';
2
+ import BTModule, { BTGridData, CheckResult } from '../data';
3
+ export default class RegionAreaBTModule extends BTModule {
4
+ instr: RegionAreaRule;
5
+ constructor(instr: RegionAreaRule);
6
+ checkGlobal(grid: BTGridData): CheckResult | false;
7
+ private visitArea;
8
+ }
@@ -0,0 +1,76 @@
1
+ import BTModule, { BTTile, IntArray2D, colorToBTTile, } from '../data';
2
+ export default class RegionAreaBTModule 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 color = colorToBTTile(this.instr.color);
15
+ const visited = IntArray2D.create(grid.width, grid.height);
16
+ let id = 0;
17
+ for (let y = 0; y < grid.height; y++) {
18
+ for (let x = 0; x < grid.width; x++) {
19
+ if (visited.get(x, y) & 0b01111111)
20
+ continue;
21
+ if (grid.getTile(x, y) !== color)
22
+ continue;
23
+ id += 1;
24
+ if (id > 127)
25
+ throw new Error('Too many regions!');
26
+ if (!this.visitArea(grid, color, visited, { x, y }, id))
27
+ return false;
28
+ }
29
+ }
30
+ return { tilesNeedCheck: null, ratings: null };
31
+ }
32
+ visitArea(grid, tile, visited, pos, id) {
33
+ const sameTileQueue = [pos];
34
+ const usableTileQueue = [];
35
+ let sameCellCount = 0;
36
+ let usableCellCount = 0;
37
+ visited.set(pos.x, pos.y, id);
38
+ // Count same tile
39
+ while (sameTileQueue.length > 0) {
40
+ const curPos = sameTileQueue.pop();
41
+ sameCellCount += 1;
42
+ for (const edge of grid.getEdges(curPos)) {
43
+ if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
44
+ continue;
45
+ const edgeTile = grid.getTile(edge.x, edge.y);
46
+ if (edgeTile === BTTile.Empty) {
47
+ usableTileQueue.push(edge);
48
+ visited.set(edge.x, edge.y, id | 0b10000000);
49
+ }
50
+ else if (edgeTile === tile) {
51
+ sameTileQueue.push(edge);
52
+ visited.set(edge.x, edge.y, id);
53
+ }
54
+ }
55
+ }
56
+ if (sameCellCount > this.instr.size)
57
+ return false;
58
+ // Count usable tile
59
+ while (usableTileQueue.length > 0) {
60
+ const curPos = usableTileQueue.pop();
61
+ usableCellCount += 1;
62
+ if (sameCellCount + usableCellCount >= this.instr.size)
63
+ return true;
64
+ for (const edge of grid.getEdges(curPos)) {
65
+ if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
66
+ continue;
67
+ const edgeTile = grid.getTile(edge.x, edge.y);
68
+ if (edgeTile === BTTile.Empty || edgeTile === tile) {
69
+ usableTileQueue.push(edge);
70
+ visited.set(edge.x, edge.y, id | 0b10000000);
71
+ }
72
+ }
73
+ }
74
+ return sameCellCount + usableCellCount >= this.instr.size;
75
+ }
76
+ }
@@ -0,0 +1,8 @@
1
+ import RegionShapeRule, { ShapeRegions } from '../../../rules/regionShapeRule';
2
+ import BTModule, { BTGridData } from '../data';
3
+ export default abstract class RegionShapeBTModule extends BTModule {
4
+ instr: RegionShapeRule;
5
+ constructor(instr: RegionShapeRule);
6
+ protected getShapeRegions(grid: BTGridData): ShapeRegions['regions'];
7
+ private visitArea;
8
+ }
@@ -0,0 +1,62 @@
1
+ import { normalizeShape, positionsToShape, shapeEquals } from '../../../shapes';
2
+ import BTModule, { BTTile, IntArray2D, colorToBTTile, } from '../data';
3
+ export default class RegionShapeBTModule extends BTModule {
4
+ constructor(instr) {
5
+ super();
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
+ getShapeRegions(grid) {
15
+ // TODO: This is extremely slow, because it doesn't check shapes when shapes are not fully enclosed
16
+ const visited = IntArray2D.create(grid.width, grid.height);
17
+ const regions = [];
18
+ for (let y = 0; y < grid.height; y++) {
19
+ for (let x = 0; x < grid.width; x++) {
20
+ const tile = grid.getTile(x, y);
21
+ if (tile !== colorToBTTile(this.instr.color) || visited.get(x, y))
22
+ continue;
23
+ const positions = this.visitArea(grid, tile, visited, { x, y });
24
+ if (!positions)
25
+ continue;
26
+ const shape = normalizeShape(positionsToShape(positions, this.instr.color));
27
+ const existing = regions.find(island => shapeEquals(island.shape, shape));
28
+ if (existing) {
29
+ existing.count++;
30
+ }
31
+ else {
32
+ regions.push({ positions, shape, count: 1 });
33
+ }
34
+ }
35
+ }
36
+ return regions;
37
+ }
38
+ visitArea(grid, tile, visited, pos) {
39
+ const positions = [pos];
40
+ const sameTileQueue = [pos];
41
+ let incomplete = false;
42
+ visited.set(pos.x, pos.y, 1);
43
+ // Count same tile
44
+ while (sameTileQueue.length > 0) {
45
+ const curPos = sameTileQueue.pop();
46
+ for (const edge of grid.getEdges(curPos)) {
47
+ if (visited.get(edge.x, edge.y))
48
+ continue;
49
+ const edgeTile = grid.getTile(edge.x, edge.y);
50
+ if (edgeTile === BTTile.Empty) {
51
+ incomplete = true;
52
+ }
53
+ else if (edgeTile === tile) {
54
+ positions.push(edge);
55
+ sameTileQueue.push(edge);
56
+ visited.set(edge.x, edge.y, 1);
57
+ }
58
+ }
59
+ }
60
+ return incomplete ? null : positions;
61
+ }
62
+ }
@@ -0,0 +1,8 @@
1
+ import SameShapeRule from '../../../rules/sameShapeRule';
2
+ import { BTGridData, CheckResult } from '../data';
3
+ import RegionShapeBTModule from './regionShape';
4
+ export default class SameShapeBTModule extends RegionShapeBTModule {
5
+ instr: SameShapeRule;
6
+ constructor(instr: SameShapeRule);
7
+ checkGlobal(grid: BTGridData): CheckResult | false;
8
+ }
@@ -0,0 +1,19 @@
1
+ import RegionShapeBTModule from './regionShape';
2
+ export default class SameShapeBTModule extends RegionShapeBTModule {
3
+ constructor(instr) {
4
+ super(instr);
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 regions = this.getShapeRegions(grid);
15
+ return regions.length <= 1
16
+ ? { tilesNeedCheck: null, ratings: null }
17
+ : false;
18
+ }
19
+ }
@@ -0,0 +1,10 @@
1
+ import SymbolsPerRegionRule from '../../../rules/symbolsPerRegionRule';
2
+ import Symbol from '../../../symbols/symbol';
3
+ import BTModule, { BTGridData, CheckResult } from '../data';
4
+ export default class SymbolsPerRegionBTModule extends BTModule {
5
+ instr: SymbolsPerRegionRule;
6
+ private symbolCount;
7
+ constructor(instr: SymbolsPerRegionRule, width: number, height: number, allSymbols: Symbol[]);
8
+ checkGlobal(grid: BTGridData): CheckResult | false;
9
+ private visitArea;
10
+ }
@@ -0,0 +1,92 @@
1
+ import { Comparison } from '../../../primitives';
2
+ import BTModule, { BTTile, IntArray2D, colorToBTTile, } from '../data';
3
+ export default class SymbolsPerRegionBTModule extends BTModule {
4
+ constructor(instr, width, height, allSymbols) {
5
+ super();
6
+ Object.defineProperty(this, "instr", {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value: void 0
11
+ });
12
+ Object.defineProperty(this, "symbolCount", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: void 0
17
+ });
18
+ this.instr = instr;
19
+ this.symbolCount = IntArray2D.create(width, height);
20
+ for (const symbol of allSymbols) {
21
+ const symbolX = Math.floor(symbol.x);
22
+ const symbolY = Math.floor(symbol.y);
23
+ this.symbolCount.set(symbolX, symbolY, this.symbolCount.get(symbolX, symbolY) + 1);
24
+ }
25
+ }
26
+ checkGlobal(grid) {
27
+ const color = colorToBTTile(this.instr.color);
28
+ const visited = IntArray2D.create(grid.width, grid.height);
29
+ let id = 0;
30
+ for (let y = 0; y < grid.height; y++) {
31
+ for (let x = 0; x < grid.width; x++) {
32
+ if (visited.get(x, y) & 0b01111111)
33
+ continue;
34
+ if (grid.getTile(x, y) !== color)
35
+ continue;
36
+ id += 1;
37
+ if (id > 127)
38
+ throw new Error('Too many regions!');
39
+ if (!this.visitArea(grid, color, visited, { x, y }, id))
40
+ return false;
41
+ }
42
+ }
43
+ return { tilesNeedCheck: null, ratings: null };
44
+ }
45
+ visitArea(grid, tile, visited, pos, id) {
46
+ const sameTileQueue = [pos];
47
+ const usableTileQueue = [];
48
+ let completed = 0;
49
+ let possible = 0;
50
+ visited.set(pos.x, pos.y, id);
51
+ // Count same tile
52
+ while (sameTileQueue.length > 0) {
53
+ const curPos = sameTileQueue.pop();
54
+ completed += this.symbolCount.get(curPos.x, curPos.y);
55
+ for (const edge of grid.getEdges(curPos)) {
56
+ if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
57
+ continue;
58
+ const edgeTile = grid.getTile(edge.x, edge.y);
59
+ if (edgeTile === BTTile.Empty) {
60
+ usableTileQueue.push(edge);
61
+ visited.set(edge.x, edge.y, id | 0b10000000);
62
+ }
63
+ else if (edgeTile === tile) {
64
+ sameTileQueue.push(edge);
65
+ visited.set(edge.x, edge.y, id);
66
+ }
67
+ }
68
+ }
69
+ if (completed > this.instr.count) {
70
+ return this.instr.comparison === Comparison.AtLeast;
71
+ }
72
+ if (this.instr.comparison === Comparison.AtMost)
73
+ return true;
74
+ // Count usable tile
75
+ while (usableTileQueue.length > 0) {
76
+ const curPos = usableTileQueue.pop();
77
+ possible += this.symbolCount.get(curPos.x, curPos.y);
78
+ if (completed + possible >= this.instr.count)
79
+ return true;
80
+ for (const edge of grid.getEdges(curPos)) {
81
+ if ((visited.get(edge.x, edge.y) & 0b01111111) === id)
82
+ continue;
83
+ const edgeTile = grid.getTile(edge.x, edge.y);
84
+ if (edgeTile === BTTile.Empty || edgeTile === tile) {
85
+ usableTileQueue.push(edge);
86
+ visited.set(edge.x, edge.y, id | 0b10000000);
87
+ }
88
+ }
89
+ }
90
+ return completed + possible >= this.instr.count;
91
+ }
92
+ }
@@ -0,0 +1,8 @@
1
+ import UniqueShapeRule from '../../../rules/uniqueShapeRule';
2
+ import { BTGridData, CheckResult } from '../data';
3
+ import RegionShapeBTModule from './regionShape';
4
+ export default class UniqueShapeBTModule extends RegionShapeBTModule {
5
+ instr: UniqueShapeRule;
6
+ constructor(instr: UniqueShapeRule);
7
+ checkGlobal(grid: BTGridData): CheckResult | false;
8
+ }
@@ -0,0 +1,19 @@
1
+ import RegionShapeBTModule from './regionShape';
2
+ export default class UniqueShapeBTModule extends RegionShapeBTModule {
3
+ constructor(instr) {
4
+ super(instr);
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 regions = this.getShapeRegions(grid);
15
+ return regions.every(r => r.count === 1)
16
+ ? { tilesNeedCheck: null, ratings: null }
17
+ : false;
18
+ }
19
+ }
@@ -0,0 +1,9 @@
1
+ import { Position } from '../../../primitives';
2
+ import AreaNumberSymbol from '../../../symbols/areaNumberSymbol';
3
+ import BTModule, { BTGridData, CheckResult } from '../data';
4
+ export default class AreaNumberBTModule extends BTModule {
5
+ instr: AreaNumberSymbol;
6
+ constructor(instr: AreaNumberSymbol);
7
+ checkGlobal(grid: BTGridData): CheckResult | false;
8
+ checkLocal(grid: BTGridData, positions: Position[]): CheckResult | boolean;
9
+ }
@@ -0,0 +1,77 @@
1
+ import BTModule, { BTTile, IntArray2D, createOneTileResult, } from '../data';
2
+ export default class AreaNumberBTModule 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 thisX = Math.floor(this.instr.x);
15
+ const thisY = Math.floor(this.instr.y);
16
+ const tile = grid.getTile(thisX, thisY);
17
+ if (tile === BTTile.Empty)
18
+ return createOneTileResult(grid, { x: thisX, y: thisY });
19
+ const visited = IntArray2D.create(grid.width, grid.height);
20
+ const sameTileQueue = [{ x: thisX, y: thisY }];
21
+ const usableTileQueue = [];
22
+ let sameCellCount = 0;
23
+ let usableCellCount = 0;
24
+ visited.set(thisX, thisY, 1);
25
+ // Count same tile
26
+ while (sameTileQueue.length > 0) {
27
+ const curPos = sameTileQueue.pop();
28
+ sameCellCount += 1;
29
+ for (const edge of grid.getEdges(curPos)) {
30
+ if (visited.get(edge.x, edge.y))
31
+ continue;
32
+ const edgeTile = grid.getTile(edge.x, edge.y);
33
+ if (edgeTile === BTTile.Empty) {
34
+ usableTileQueue.push(edge);
35
+ }
36
+ else if (edgeTile === tile) {
37
+ sameTileQueue.push(edge);
38
+ }
39
+ visited.set(edge.x, edge.y, 1);
40
+ }
41
+ }
42
+ if (sameCellCount > this.instr.number)
43
+ return false;
44
+ const ratings = [];
45
+ for (const pos of usableTileQueue) {
46
+ ratings.push({ pos, score: 1 });
47
+ }
48
+ // Count usable tile
49
+ while (usableTileQueue.length > 0) {
50
+ const curPos = usableTileQueue.pop();
51
+ usableCellCount += 1;
52
+ if (sameCellCount + usableCellCount >= this.instr.number)
53
+ return { tilesNeedCheck: null, ratings };
54
+ for (const edge of grid.getEdges(curPos)) {
55
+ if (visited.get(edge.x, edge.y))
56
+ continue;
57
+ const edgeTile = grid.getTile(edge.x, edge.y);
58
+ if (edgeTile === BTTile.Empty || edgeTile === tile) {
59
+ usableTileQueue.push(edge);
60
+ visited.set(edge.x, edge.y, 1);
61
+ }
62
+ }
63
+ }
64
+ return sameCellCount + usableCellCount >= this.instr.number
65
+ ? { tilesNeedCheck: null, ratings }
66
+ : false;
67
+ }
68
+ checkLocal(grid, positions) {
69
+ // TODO: Also skip checks if color is the same and within the zone but not directly affectin
70
+ const thisX = Math.floor(this.instr.x);
71
+ const thisY = Math.floor(this.instr.y);
72
+ // Skip checks if it is too far to affect the symbol
73
+ if (positions.every(pos => Math.abs(pos.x - thisX) + Math.abs(pos.y - thisY) > this.instr.number))
74
+ return true;
75
+ return this.checkGlobal(grid);
76
+ }
77
+ }
@@ -0,0 +1,9 @@
1
+ import DartSymbol from '../../../symbols/dartSymbol';
2
+ import BTModule, { BTGridData, CheckResult } from '../data';
3
+ export default class DartBTModule extends BTModule {
4
+ instr: DartSymbol;
5
+ private cachedCheckResult?;
6
+ constructor(instr: DartSymbol);
7
+ checkGlobal(grid: BTGridData): CheckResult | false;
8
+ private buildCheckAndRating;
9
+ }
@@ -0,0 +1,58 @@
1
+ import { move } from '../../../dataHelper';
2
+ import BTModule, { BTTile, IntArray2D, createOneTileResult, getOppositeColor, } from '../data';
3
+ export default class DartBTModule extends BTModule {
4
+ constructor(instr) {
5
+ super();
6
+ Object.defineProperty(this, "instr", {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value: void 0
11
+ });
12
+ Object.defineProperty(this, "cachedCheckResult", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: void 0
17
+ });
18
+ this.instr = instr;
19
+ }
20
+ checkGlobal(grid) {
21
+ const tile = grid.getTile(this.instr.x, this.instr.y);
22
+ if (tile === BTTile.Empty)
23
+ return createOneTileResult(grid, { x: this.instr.x, y: this.instr.y });
24
+ let pos = move({ x: this.instr.x, y: this.instr.y }, this.instr.orientation);
25
+ let completed = 0;
26
+ let empty = 0;
27
+ while (grid.isInBound(pos.x, pos.y)) {
28
+ // Opposite tiles
29
+ if (grid.getTile(pos.x, pos.y) === getOppositeColor(tile)) {
30
+ completed += 1;
31
+ if (completed > this.instr.number)
32
+ return false;
33
+ }
34
+ // Empty tiles
35
+ if (grid.getTile(pos.x, pos.y) === BTTile.Empty)
36
+ empty += 1;
37
+ pos = move(pos, this.instr.orientation);
38
+ }
39
+ if (completed + empty < this.instr.number)
40
+ return false;
41
+ if (!this.cachedCheckResult)
42
+ this.cachedCheckResult = this.buildCheckAndRating(grid);
43
+ return this.cachedCheckResult;
44
+ }
45
+ buildCheckAndRating(grid) {
46
+ const tilesNeedCheck = IntArray2D.create(grid.width, grid.height);
47
+ const ratings = [];
48
+ let pos = { x: this.instr.x, y: this.instr.y };
49
+ while (grid.isInBound(pos.x, pos.y)) {
50
+ if (grid.getTile(pos.x, pos.y) === BTTile.Empty) {
51
+ tilesNeedCheck.set(pos.x, pos.y, 1);
52
+ ratings.push({ pos, score: 1 });
53
+ }
54
+ pos = move(pos, this.instr.orientation);
55
+ }
56
+ return { tilesNeedCheck, ratings };
57
+ }
58
+ }
@@ -0,0 +1,9 @@
1
+ import { Position } from '../../../primitives';
2
+ import DirectionLinkerSymbol from '../../../symbols/directionLinkerSymbol';
3
+ import BTModule, { BTGridData, CheckResult } from '../data';
4
+ export default abstract class DirectionLinkerBTModule extends BTModule {
5
+ instr: DirectionLinkerSymbol;
6
+ constructor(instr: DirectionLinkerSymbol);
7
+ checkGlobal(grid: BTGridData): CheckResult | false;
8
+ protected abstract movePos(grid: BTGridData, x: number, y: number): Position | null;
9
+ }
@@ -0,0 +1,50 @@
1
+ import BTModule, { BTTile, IntArray2D, createOneTileResult, } from '../data';
2
+ export default class DirectionLinkerBTModule 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 thisX = Math.floor(this.instr.x);
15
+ const thisY = Math.floor(this.instr.y);
16
+ const tile = grid.getTile(thisX, thisY);
17
+ if (tile === BTTile.Empty)
18
+ return createOneTileResult(grid, { x: thisX, y: thisY });
19
+ const tilesNeedCheck = IntArray2D.create(grid.width, grid.height);
20
+ const ratings = [];
21
+ const queue = [{ x: thisX, y: thisY }];
22
+ const visited = IntArray2D.create(grid.width, grid.height);
23
+ // Visit all connected tiles
24
+ while (queue.length > 0) {
25
+ const curPos = queue.pop();
26
+ if (visited.get(curPos.x, curPos.y))
27
+ continue;
28
+ visited.set(curPos.x, curPos.y, 1);
29
+ const oppoPos = this.movePos(grid, curPos.x, curPos.y);
30
+ if (oppoPos === null)
31
+ return false;
32
+ const oppoTile = grid.getTile(oppoPos.x, oppoPos.y);
33
+ if (!(oppoTile === BTTile.Empty || oppoTile === tile))
34
+ return false;
35
+ for (const edge of grid.getEdges(curPos)) {
36
+ if (visited.get(edge.x, edge.y))
37
+ continue;
38
+ const edgeTile = grid.getTile(edge.x, edge.y);
39
+ if (edgeTile === BTTile.Empty) {
40
+ tilesNeedCheck.set(edge.x, edge.y, 1);
41
+ ratings.push({ pos: edge, score: 1 });
42
+ }
43
+ else if (edgeTile === tile) {
44
+ queue.push(edge);
45
+ }
46
+ }
47
+ }
48
+ return { tilesNeedCheck, ratings };
49
+ }
50
+ }
@@ -0,0 +1,9 @@
1
+ import { Position } from '../../../primitives';
2
+ import GalaxySymbol from '../../../symbols/galaxySymbol';
3
+ import { BTGridData } from '../data';
4
+ import DirectionLinkerBTModule from './directionLinker';
5
+ export default class GalaxyBTModule extends DirectionLinkerBTModule {
6
+ instr: GalaxySymbol;
7
+ constructor(instr: GalaxySymbol);
8
+ protected movePos(grid: BTGridData, x: number, y: number): Position | null;
9
+ }
@@ -0,0 +1,19 @@
1
+ import DirectionLinkerBTModule from './directionLinker';
2
+ export default class GalaxyBTModule extends DirectionLinkerBTModule {
3
+ constructor(instr) {
4
+ super(instr);
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
+ // Translate a position in relative to a galaxy symbol
14
+ movePos(grid, x, y) {
15
+ const symbol = this.instr;
16
+ const pos = { x: 2 * symbol.x - x, y: 2 * symbol.y - y };
17
+ return grid.isInBound(pos.x, pos.y) ? pos : null;
18
+ }
19
+ }