@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,211 @@
1
+ import { ConfigType } from '../config';
2
+ import GridData from '../grid';
3
+ import { resize } from '../dataHelper';
4
+ import { Color, State } from '../primitives';
5
+ import CustomIconSymbol from '../symbols/customIconSymbol';
6
+ import { ControlLine, Row } from './musicControlLine';
7
+ import Rule from './rule';
8
+ const DEFAULT_SCALLE = [
9
+ new Row('C5', 0.6),
10
+ new Row('B4', 0.6),
11
+ new Row('A4', 0.6),
12
+ new Row('G4', 0.6),
13
+ new Row('F4', 0.6),
14
+ new Row('E4', 0.6),
15
+ new Row('D4', 0.6),
16
+ new Row('C4', 0.6),
17
+ ];
18
+ class MusicGridRule extends Rule {
19
+ /**
20
+ * **Music Grid: Listen to the solution**
21
+ * @param controlLines Denote changes in the playback settings. At least one control line at column 0 should be present to enable playback.
22
+ * @param track The grid to be played when "listen" is clicked. Set as null to play the solution.
23
+ */
24
+ constructor(controlLines, track) {
25
+ super();
26
+ Object.defineProperty(this, "controlLines", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: controlLines
31
+ });
32
+ Object.defineProperty(this, "track", {
33
+ enumerable: true,
34
+ configurable: true,
35
+ writable: true,
36
+ value: track
37
+ });
38
+ this.controlLines = MusicGridRule.deduplicateControlLines(controlLines);
39
+ this.track = track;
40
+ }
41
+ get id() {
42
+ return `music`;
43
+ }
44
+ get explanation() {
45
+ return `*Music Grid:* Listen to the solution`;
46
+ }
47
+ get configs() {
48
+ return MusicGridRule.CONFIGS;
49
+ }
50
+ createExampleGrid() {
51
+ return MusicGridRule.EXAMPLE_GRID;
52
+ }
53
+ get searchVariants() {
54
+ return MusicGridRule.SEARCH_VARIANTS;
55
+ }
56
+ validateGrid(_grid) {
57
+ return { state: State.Incomplete };
58
+ }
59
+ onSetGrid(_oldGrid, newGrid) {
60
+ if (newGrid.getTileCount(true, undefined, Color.Gray) === 0)
61
+ return newGrid;
62
+ const tiles = newGrid.tiles.map(row => row.map(tile => tile.color === Color.Gray ? tile.withColor(Color.Light) : tile));
63
+ return newGrid.copyWith({ tiles });
64
+ }
65
+ onGridChange(newGrid) {
66
+ if (this.controlLines.length === 0)
67
+ return this;
68
+ if (newGrid.height === this.controlLines[0].rows.length &&
69
+ !this.controlLines.some(line => line.column >= newGrid.width))
70
+ return this;
71
+ const controlLines = this.controlLines
72
+ .filter(line => line.column < newGrid.width)
73
+ .map(line => line.withRows(resize(line.rows, newGrid.height, () => new Row(null, null))));
74
+ return this.copyWith({ controlLines });
75
+ }
76
+ onGridResize(_grid, mode, direction, index) {
77
+ if (mode === 'insert') {
78
+ if (direction === 'row') {
79
+ return this.copyWith({
80
+ controlLines: this.controlLines.map(line => {
81
+ const rows = line.rows.slice();
82
+ rows.splice(index, 0, new Row(null, null));
83
+ return line.withRows(rows);
84
+ }),
85
+ });
86
+ }
87
+ else if (direction === 'column') {
88
+ return this.copyWith({
89
+ controlLines: this.controlLines.map(line => line.column >= index ? line.withColumn(line.column + 1) : line),
90
+ });
91
+ }
92
+ }
93
+ else if (mode === 'remove') {
94
+ if (direction === 'row') {
95
+ return this.copyWith({
96
+ controlLines: this.controlLines.map(line => line.withRows(line.rows.filter((_, idx) => idx !== index))),
97
+ });
98
+ }
99
+ else if (direction === 'column') {
100
+ const lines = [];
101
+ for (const line of this.controlLines) {
102
+ if (line.column === index) {
103
+ const nextLine = this.controlLines.find(l => l.column === index + 1);
104
+ if (nextLine) {
105
+ lines.push(MusicGridRule.mergeControlLines(line, nextLine));
106
+ }
107
+ else {
108
+ lines.push(line.withColumn(index));
109
+ }
110
+ }
111
+ else if (line.column > index) {
112
+ lines.push(line.withColumn(line.column - 1));
113
+ }
114
+ else {
115
+ lines.push(line);
116
+ }
117
+ }
118
+ return this.copyWith({ controlLines: lines });
119
+ }
120
+ }
121
+ return this;
122
+ }
123
+ /**
124
+ * Add or replace a control line.
125
+ * @param controlLine The control line to set.
126
+ * @returns A new rule with the control line set.
127
+ */
128
+ setControlLine(controlLine) {
129
+ const controlLines = this.controlLines.filter(line => line.column !== controlLine.column);
130
+ return this.copyWith({
131
+ controlLines: [...controlLines, controlLine].sort((a, b) => a.column - b.column),
132
+ });
133
+ }
134
+ withTrack(track) {
135
+ return this.copyWith({ track });
136
+ }
137
+ copyWith({ controlLines, track, }) {
138
+ return new MusicGridRule(controlLines ?? this.controlLines, track !== undefined ? track : this.track);
139
+ }
140
+ get validateWithSolution() {
141
+ return true;
142
+ }
143
+ get isSingleton() {
144
+ return true;
145
+ }
146
+ static mergeControlLines(...lines) {
147
+ const rows = Array.from({ length: Math.max(...lines.map(l => l.rows.length)) }, (_, idx) => {
148
+ const note = lines
149
+ .map(l => l.rows[idx]?.note)
150
+ .reduce((a, b) => b ?? a, null);
151
+ const velocity = lines
152
+ .map(l => l.rows[idx]?.velocity)
153
+ .reduce((a, b) => b ?? a, null);
154
+ return new Row(note, velocity);
155
+ });
156
+ const bpm = lines.map(l => l.bpm).reduce((a, b) => b ?? a, null);
157
+ const pedal = lines.map(l => l.pedal).reduce((a, b) => b ?? a, null);
158
+ const checkpoint = lines.some(l => l.checkpoint);
159
+ return new ControlLine(lines[0].column, bpm, pedal, checkpoint, rows);
160
+ }
161
+ static deduplicateControlLines(lines) {
162
+ const columns = new Map();
163
+ for (const line of lines) {
164
+ if (!columns.has(line.column)) {
165
+ columns.set(line.column, [line]);
166
+ }
167
+ else {
168
+ columns.get(line.column).push(line);
169
+ }
170
+ }
171
+ return Array.from(columns.values()).map(lines => lines.length > 1 ? MusicGridRule.mergeControlLines(...lines) : lines[0]);
172
+ }
173
+ }
174
+ Object.defineProperty(MusicGridRule, "EXAMPLE_GRID", {
175
+ enumerable: true,
176
+ configurable: true,
177
+ writable: true,
178
+ value: Object.freeze(GridData.create(['.']).addSymbol(new CustomIconSymbol('', GridData.create([]), 0, 0, 'MdMusicNote')))
179
+ });
180
+ Object.defineProperty(MusicGridRule, "CONFIGS", {
181
+ enumerable: true,
182
+ configurable: true,
183
+ writable: true,
184
+ value: Object.freeze([
185
+ {
186
+ type: ConfigType.ControlLines,
187
+ default: [new ControlLine(0, 120, false, false, DEFAULT_SCALLE)],
188
+ field: 'controlLines',
189
+ description: 'Control Lines',
190
+ configurable: false,
191
+ },
192
+ {
193
+ type: ConfigType.NullableGrid,
194
+ default: null,
195
+ nonNullDefault: new GridData(5, 4).addRule(new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null)),
196
+ field: 'track',
197
+ description: 'Track',
198
+ configurable: true,
199
+ },
200
+ ])
201
+ });
202
+ Object.defineProperty(MusicGridRule, "SEARCH_VARIANTS", {
203
+ enumerable: true,
204
+ configurable: true,
205
+ writable: true,
206
+ value: [
207
+ new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null).searchVariant(),
208
+ ]
209
+ });
210
+ export default MusicGridRule;
211
+ export const instance = new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null);
@@ -0,0 +1,37 @@
1
+ import { AnyConfig } from '../config';
2
+ import { FinalValidationHandler } from '../events/onFinalValidation';
3
+ import { GridChangeHandler } from '../events/onGridChange';
4
+ import { GridResizeHandler } from '../events/onGridResize';
5
+ import GridData from '../grid';
6
+ import { GridState, RuleState } from '../primitives';
7
+ import Rule, { SearchVariant } from './rule';
8
+ export default class MysteryRule extends Rule implements FinalValidationHandler, GridChangeHandler, GridResizeHandler {
9
+ readonly solution: GridData;
10
+ readonly visible: boolean;
11
+ private static readonly EXAMPLE_GRID;
12
+ private static readonly CONFIGS;
13
+ private static readonly SEARCH_VARIANTS;
14
+ /**
15
+ * **Mystery: alternate solution**
16
+ */
17
+ constructor(solution: GridData, visible: boolean);
18
+ get id(): string;
19
+ get explanation(): string;
20
+ get visibleWhenSolving(): boolean;
21
+ get configs(): readonly AnyConfig[] | null;
22
+ createExampleGrid(): GridData;
23
+ get searchVariants(): SearchVariant[];
24
+ validateGrid(grid: GridData): RuleState;
25
+ get necessaryForCompletion(): boolean;
26
+ onFinalValidation(grid: GridData, _solution: GridData | null, state: GridState): GridState;
27
+ onGridChange(newGrid: GridData): this;
28
+ onGridResize(_grid: GridData, mode: 'insert' | 'remove', direction: 'row' | 'column', index: number): this | null;
29
+ copyWith({ solution, visible, }: {
30
+ solution?: GridData;
31
+ visible?: boolean;
32
+ }): this;
33
+ withSolution(solution: GridData): this;
34
+ withVisible(visible: boolean): this;
35
+ static cleanSolution(solution: GridData, baseGrid?: GridData): GridData;
36
+ }
37
+ export declare const instance: MysteryRule;
@@ -0,0 +1,164 @@
1
+ import { ConfigType } from '../config';
2
+ import GridData from '../grid';
3
+ import { array } from '../dataHelper';
4
+ import { Color, State } from '../primitives';
5
+ import CustomTextSymbol from '../symbols/customTextSymbol';
6
+ import Rule from './rule';
7
+ class MysteryRule extends Rule {
8
+ /**
9
+ * **Mystery: alternate solution**
10
+ */
11
+ constructor(solution, visible) {
12
+ super();
13
+ Object.defineProperty(this, "solution", {
14
+ enumerable: true,
15
+ configurable: true,
16
+ writable: true,
17
+ value: solution
18
+ });
19
+ Object.defineProperty(this, "visible", {
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true,
23
+ value: visible
24
+ });
25
+ this.solution = MysteryRule.cleanSolution(solution);
26
+ this.visible = visible;
27
+ }
28
+ get id() {
29
+ return `mystery`;
30
+ }
31
+ get explanation() {
32
+ return `*Mystery:* Alternate solution`;
33
+ }
34
+ get visibleWhenSolving() {
35
+ return this.visible;
36
+ }
37
+ get configs() {
38
+ return MysteryRule.CONFIGS;
39
+ }
40
+ createExampleGrid() {
41
+ return MysteryRule.EXAMPLE_GRID;
42
+ }
43
+ get searchVariants() {
44
+ return MysteryRule.SEARCH_VARIANTS;
45
+ }
46
+ validateGrid(grid) {
47
+ if (grid.colorEquals(this.solution))
48
+ return { state: State.Satisfied };
49
+ return { state: State.Incomplete };
50
+ }
51
+ get necessaryForCompletion() {
52
+ return false;
53
+ }
54
+ onFinalValidation(grid, _solution, state) {
55
+ if (state.final === State.Satisfied)
56
+ return state;
57
+ if (grid.colorEquals(this.solution))
58
+ return {
59
+ final: State.Satisfied,
60
+ symbols: state.symbols,
61
+ rules: state.rules,
62
+ };
63
+ return state;
64
+ }
65
+ onGridChange(newGrid) {
66
+ if (newGrid.width === this.solution.width &&
67
+ newGrid.height === this.solution.height) {
68
+ if (!newGrid.tiles.some((row, y) => row.some((tile, x) => {
69
+ const solutionTile = this.solution.getTile(x, y);
70
+ if (solutionTile.exists !== tile.exists)
71
+ return true;
72
+ if (solutionTile.fixed !== tile.fixed)
73
+ return true;
74
+ if (solutionTile.exists &&
75
+ solutionTile.fixed &&
76
+ solutionTile.color !== tile.color)
77
+ return true;
78
+ return false;
79
+ })))
80
+ return this;
81
+ }
82
+ return this.withSolution(MysteryRule.cleanSolution(this.solution, newGrid));
83
+ }
84
+ onGridResize(_grid, mode, direction, index) {
85
+ if (mode === 'insert') {
86
+ if (direction === 'row') {
87
+ return this.withSolution(this.solution.insertRow(index));
88
+ }
89
+ else if (direction === 'column') {
90
+ return this.withSolution(this.solution.insertColumn(index));
91
+ }
92
+ }
93
+ else if (mode === 'remove') {
94
+ if (direction === 'row') {
95
+ return this.withSolution(this.solution.removeRow(index));
96
+ }
97
+ else if (direction === 'column') {
98
+ return this.withSolution(this.solution.removeColumn(index));
99
+ }
100
+ }
101
+ return this;
102
+ }
103
+ copyWith({ solution, visible, }) {
104
+ return new MysteryRule(solution ?? this.solution, visible ?? this.visible);
105
+ }
106
+ withSolution(solution) {
107
+ return this.copyWith({ solution });
108
+ }
109
+ withVisible(visible) {
110
+ return this.copyWith({ visible });
111
+ }
112
+ static cleanSolution(solution, baseGrid) {
113
+ const tiles = baseGrid
114
+ ? array(baseGrid.width, baseGrid.height, (x, y) => {
115
+ const tile = baseGrid.getTile(x, y);
116
+ if (!tile.exists || tile.fixed)
117
+ return tile;
118
+ const solutionTile = solution.getTile(x, y);
119
+ if (!solutionTile.exists || solutionTile.color === Color.Gray)
120
+ return tile;
121
+ return tile.withColor(solutionTile.color);
122
+ })
123
+ : solution.tiles;
124
+ return new GridData(baseGrid?.width ?? solution.width, baseGrid?.height ?? solution.height, tiles);
125
+ }
126
+ }
127
+ Object.defineProperty(MysteryRule, "EXAMPLE_GRID", {
128
+ enumerable: true,
129
+ configurable: true,
130
+ writable: true,
131
+ value: Object.freeze(GridData.create(['.']).addSymbol(new CustomTextSymbol('', GridData.create([]), 0, 0, '?')))
132
+ });
133
+ Object.defineProperty(MysteryRule, "CONFIGS", {
134
+ enumerable: true,
135
+ configurable: true,
136
+ writable: true,
137
+ value: Object.freeze([
138
+ {
139
+ type: ConfigType.Tile,
140
+ default: MysteryRule.EXAMPLE_GRID,
141
+ resizable: false,
142
+ field: 'solution',
143
+ description: 'Solution',
144
+ configurable: true,
145
+ },
146
+ {
147
+ type: ConfigType.Boolean,
148
+ default: true,
149
+ field: 'visible',
150
+ description: 'Visible',
151
+ configurable: true,
152
+ },
153
+ ])
154
+ });
155
+ Object.defineProperty(MysteryRule, "SEARCH_VARIANTS", {
156
+ enumerable: true,
157
+ configurable: true,
158
+ writable: true,
159
+ value: [
160
+ new MysteryRule(MysteryRule.EXAMPLE_GRID, true).searchVariant(),
161
+ ]
162
+ });
163
+ export default MysteryRule;
164
+ export const instance = new MysteryRule(GridData.create([]), true);
@@ -0,0 +1,30 @@
1
+ import { AnyConfig } from '../config';
2
+ import { SymbolValidationHandler } from '../events/onSymbolValidation';
3
+ import GridData from '../grid';
4
+ import { RuleState, State } from '../primitives';
5
+ import Symbol from '../symbols/symbol';
6
+ import Rule, { SearchVariant } from './rule';
7
+ export default class OffByXRule extends Rule implements SymbolValidationHandler {
8
+ readonly number: number;
9
+ private static readonly CONFIGS;
10
+ private static readonly EXAMPLE_GRID;
11
+ private static readonly SEARCH_VARIANTS;
12
+ /**
13
+ * **All numbers are off by &lt;number&gt;**
14
+ *
15
+ * @param number - The number that all cells are off by.
16
+ */
17
+ constructor(number: number);
18
+ get id(): string;
19
+ get explanation(): string;
20
+ get configs(): readonly AnyConfig[] | null;
21
+ createExampleGrid(): GridData;
22
+ get searchVariants(): SearchVariant[];
23
+ validateGrid(_grid: GridData): RuleState;
24
+ onSymbolValidation(grid: GridData, symbol: Symbol, _validator: (grid: GridData) => State): State | undefined;
25
+ copyWith({ number }: {
26
+ number?: number;
27
+ }): this;
28
+ withNumber(number: number): this;
29
+ }
30
+ export declare const instance: OffByXRule;
@@ -0,0 +1,134 @@
1
+ import { ConfigType } from '../config';
2
+ import GridData from '../grid';
3
+ import { State } from '../primitives';
4
+ import AreaNumberSymbol from '../symbols/areaNumberSymbol';
5
+ import NumberSymbol from '../symbols/numberSymbol';
6
+ import Rule from './rule';
7
+ class OffByXRule extends Rule {
8
+ /**
9
+ * **All numbers are off by &lt;number&gt;**
10
+ *
11
+ * @param number - The number that all cells are off by.
12
+ */
13
+ constructor(number) {
14
+ super();
15
+ Object.defineProperty(this, "number", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: number
20
+ });
21
+ this.number = number;
22
+ }
23
+ get id() {
24
+ return `off_by_x`;
25
+ }
26
+ get explanation() {
27
+ return `All numbers are off by ${this.number}`;
28
+ }
29
+ get configs() {
30
+ return OffByXRule.CONFIGS;
31
+ }
32
+ createExampleGrid() {
33
+ if (this.number < 1 || this.number >= OffByXRule.EXAMPLE_GRID.length) {
34
+ return GridData.create(['bbbbb', 'bbwbb', 'bbbbb', 'bbbbb']).addSymbol(new AreaNumberSymbol(2, 1, this.number + 1));
35
+ }
36
+ return OffByXRule.EXAMPLE_GRID[this.number - 1];
37
+ }
38
+ get searchVariants() {
39
+ return OffByXRule.SEARCH_VARIANTS;
40
+ }
41
+ validateGrid(_grid) {
42
+ return { state: State.Incomplete };
43
+ }
44
+ onSymbolValidation(grid, symbol, _validator) {
45
+ if (symbol instanceof NumberSymbol) {
46
+ const counts = symbol.countTiles(grid);
47
+ if (counts.completed > symbol.number + this.number ||
48
+ counts.possible < symbol.number - this.number ||
49
+ (counts.completed > symbol.number - this.number &&
50
+ counts.possible < symbol.number + this.number)) {
51
+ return State.Error;
52
+ }
53
+ else if ((counts.completed === symbol.number + this.number ||
54
+ counts.completed === symbol.number - this.number) &&
55
+ counts.completed === counts.possible) {
56
+ return State.Satisfied;
57
+ }
58
+ else {
59
+ return State.Incomplete;
60
+ }
61
+ }
62
+ else {
63
+ return undefined;
64
+ }
65
+ }
66
+ copyWith({ number }) {
67
+ return new OffByXRule(number ?? this.number);
68
+ }
69
+ withNumber(number) {
70
+ return this.copyWith({ number });
71
+ }
72
+ }
73
+ Object.defineProperty(OffByXRule, "CONFIGS", {
74
+ enumerable: true,
75
+ configurable: true,
76
+ writable: true,
77
+ value: Object.freeze([
78
+ {
79
+ type: ConfigType.Number,
80
+ default: 1,
81
+ min: 1,
82
+ field: 'number',
83
+ description: 'Number',
84
+ configurable: true,
85
+ },
86
+ ])
87
+ });
88
+ Object.defineProperty(OffByXRule, "EXAMPLE_GRID", {
89
+ enumerable: true,
90
+ configurable: true,
91
+ writable: true,
92
+ value: Object.freeze([
93
+ GridData.create(['bbbbb', 'bwbwb', 'bbwwb', 'bbbbb']).withSymbols([
94
+ new AreaNumberSymbol(1, 1, 2),
95
+ new AreaNumberSymbol(3, 2, 2),
96
+ ]),
97
+ GridData.create(['bbbbb', 'bwbwb', 'bbbwb', 'bwwwb']).withSymbols([
98
+ new AreaNumberSymbol(1, 1, 3),
99
+ new AreaNumberSymbol(3, 3, 3),
100
+ ]),
101
+ GridData.create(['bbbbw', 'bwbbw', 'bbbbw', 'bwwww']).withSymbols([
102
+ new AreaNumberSymbol(1, 1, 4),
103
+ new AreaNumberSymbol(4, 3, 4),
104
+ ]),
105
+ GridData.create(['bbbbw', 'bwbbw', 'bbbww', 'wwwww']).withSymbols([
106
+ new AreaNumberSymbol(1, 1, 5),
107
+ new AreaNumberSymbol(4, 3, 5),
108
+ ]),
109
+ GridData.create(['bbbww', 'bwbww', 'bbbww', 'wwwww']).withSymbols([
110
+ new AreaNumberSymbol(1, 1, 6),
111
+ new AreaNumberSymbol(4, 3, 6),
112
+ ]),
113
+ GridData.create(['wbbww', 'bbwww', 'bbwww', 'wwwww']).withSymbols([
114
+ new AreaNumberSymbol(0, 0, 7),
115
+ new AreaNumberSymbol(4, 3, 7),
116
+ ]),
117
+ GridData.create(['wbbww', 'bwwww', 'bwwww', 'wwwww']).withSymbols([
118
+ new AreaNumberSymbol(0, 0, 8),
119
+ new AreaNumberSymbol(4, 3, 8),
120
+ ]),
121
+ GridData.create(['wbwww', 'bwwww', 'wwwww', 'wwwww']).withSymbols([
122
+ new AreaNumberSymbol(0, 0, 9),
123
+ new AreaNumberSymbol(4, 3, 9),
124
+ ]),
125
+ ])
126
+ });
127
+ Object.defineProperty(OffByXRule, "SEARCH_VARIANTS", {
128
+ enumerable: true,
129
+ configurable: true,
130
+ writable: true,
131
+ value: [new OffByXRule(1).searchVariant()]
132
+ });
133
+ export default OffByXRule;
134
+ export const instance = new OffByXRule(1);
@@ -0,0 +1,33 @@
1
+ import { AnyConfig } from '../config';
2
+ import GridData from '../grid';
3
+ import { Color, RuleState } from '../primitives';
4
+ import Rule, { SearchVariant } from './rule';
5
+ export default class RegionAreaRule extends Rule {
6
+ readonly color: Color;
7
+ readonly size: number;
8
+ private static readonly CONFIGS;
9
+ private static readonly EXAMPLE_GRID_DARK;
10
+ private static readonly EXAMPLE_GRID_LIGHT;
11
+ private static readonly EXAMPLE_GRID_GRAY;
12
+ private static readonly SEARCH_VARIANTS;
13
+ /**
14
+ * **All &lt;color&gt; regions have area &lt;size&gt;**
15
+ *
16
+ * @param color - The color of the regions.
17
+ * @param size - The area of the regions.
18
+ */
19
+ constructor(color: Color, size: number);
20
+ get id(): string;
21
+ get explanation(): string;
22
+ get configs(): readonly AnyConfig[] | null;
23
+ createExampleGrid(): GridData;
24
+ get searchVariants(): SearchVariant[];
25
+ validateGrid(grid: GridData): RuleState;
26
+ copyWith({ color, size }: {
27
+ color?: Color;
28
+ size?: number;
29
+ }): this;
30
+ withColor(color: Color): this;
31
+ withSize(size: number): this;
32
+ }
33
+ export declare const instance: RegionAreaRule;