@logic-pad/core 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/assets/logic-core.global.d.ts +83 -22
  2. package/dist/data/grid.d.ts +44 -14
  3. package/dist/data/grid.js +43 -36
  4. package/dist/data/rules/banPatternRule.js +1 -1
  5. package/dist/data/rules/customRule.js +1 -1
  6. package/dist/data/rules/lyingSymbolRule.d.ts +1 -1
  7. package/dist/data/rules/lyingSymbolRule.js +38 -13
  8. package/dist/data/rules/musicGridRule.js +1 -1
  9. package/dist/data/rules/mysteryRule.js +1 -1
  10. package/dist/data/rules/regionAreaRule.js +3 -3
  11. package/dist/data/serializer/serializer_v0.js +1 -1
  12. package/dist/data/solver/allSolvers.js +2 -2
  13. package/dist/data/solver/backtrack/backtrackSolver.d.ts +3 -4
  14. package/dist/data/solver/backtrack/backtrackSolver.js +4 -30
  15. package/dist/data/solver/backtrack/backtrackWorker.d.ts +1 -2
  16. package/dist/data/solver/backtrack/backtrackWorker.js +12 -8
  17. package/dist/data/solver/eventIteratingSolver.d.ts +6 -0
  18. package/dist/data/solver/eventIteratingSolver.js +33 -0
  19. package/dist/data/solver/solver.d.ts +6 -1
  20. package/dist/data/solver/solver.js +2 -1
  21. package/dist/data/solver/universal/universalSolver.d.ts +7 -0
  22. package/dist/data/solver/universal/universalSolver.js +30 -0
  23. package/dist/data/solver/universal/universalWorker.d.ts +1 -0
  24. package/dist/data/solver/universal/universalWorker.js +119 -0
  25. package/dist/data/symbols/customIconSymbol.js +2 -2
  26. package/dist/data/symbols/customTextSymbol.js +2 -2
  27. package/dist/index.d.ts +3 -2
  28. package/dist/index.js +3 -2
  29. package/package.json +1 -1
  30. package/dist/data/solver/underclued/undercluedSolver.d.ts +0 -8
  31. package/dist/data/solver/underclued/undercluedSolver.js +0 -55
  32. package/dist/data/solver/underclued/undercluedWorker.d.ts +0 -2
  33. package/dist/data/solver/underclued/undercluedWorker.js +0 -135
@@ -646,6 +646,7 @@ declare global {
646
646
  readonly underclued: CachedAccess<UndercluedRule | undefined>;
647
647
  /**
648
648
  * Create a new grid with tiles, connections, symbols and rules.
649
+ *
649
650
  * @param width The width of the grid.
650
651
  * @param height The height of the grid.
651
652
  * @param tiles The tiles of the grid.
@@ -663,6 +664,38 @@ declare global {
663
664
  symbols?: ReadonlyMap<string, readonly Symbol$1[]>,
664
665
  rules?: readonly Rule[]
665
666
  );
667
+ /**
668
+ * Create a new GridData object from a string array.
669
+ *
670
+ * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells.
671
+ * - Capitalize the letter to make the tile fixed.
672
+ * - Use `.` to represent empty space.
673
+ *
674
+ * @param array - The string array to create the grid from.
675
+ * @returns The created grid.
676
+ */
677
+ static create(array: string[]): GridData;
678
+ /**
679
+ * Create a new grid with tiles, connections, symbols and rules. Sanitize the provided list of symbols and rules,
680
+ * and trigger grid change events.
681
+ *
682
+ * @param width The width of the grid.
683
+ * @param height The height of the grid.
684
+ * @param tiles The tiles of the grid.
685
+ * @param connections The connections of the grid, which determines which tiles are merged.
686
+ * @param zones The zones of the grid.
687
+ * @param symbols The symbols in the grid.
688
+ * @param rules The rules of the grid.
689
+ */
690
+ static create(
691
+ width: number,
692
+ height: number,
693
+ tiles?: readonly (readonly TileData[])[],
694
+ connections?: GridConnections,
695
+ zones?: GridZones,
696
+ symbols?: ReadonlyMap<string, readonly Symbol$1[]>,
697
+ rules?: readonly Rule[]
698
+ ): GridData;
666
699
  /**
667
700
  * Copy the current grid while modifying the provided properties.
668
701
  * @param param0 The properties to modify.
@@ -685,6 +718,30 @@ declare global {
685
718
  symbols?: ReadonlyMap<string, readonly Symbol$1[]>;
686
719
  rules?: readonly Rule[];
687
720
  }): GridData;
721
+ /**
722
+ * Copy the current grid while modifying the provided properties.
723
+ * Skip sanitization and event triggering for performance.
724
+ *
725
+ * @param param0 The properties to modify.
726
+ * @returns The new grid with the modified properties.
727
+ */
728
+ fastCopyWith({
729
+ width,
730
+ height,
731
+ tiles,
732
+ connections,
733
+ zones,
734
+ symbols,
735
+ rules,
736
+ }: {
737
+ width?: number;
738
+ height?: number;
739
+ tiles?: readonly (readonly TileData[])[];
740
+ connections?: GridConnections;
741
+ zones?: GridZones;
742
+ symbols?: ReadonlyMap<string, readonly Symbol$1[]>;
743
+ rules?: readonly Rule[];
744
+ }): GridData;
688
745
  isPositionValid(x: number, y: number): boolean;
689
746
  /**
690
747
  * Safely get the tile at the given position.
@@ -695,19 +752,19 @@ declare global {
695
752
  getTile(x: number, y: number): TileData;
696
753
  /**
697
754
  * Safely set the tile at the given position.
698
- * If the position is invalid, the grid is returned unchanged.
755
+ * If the position is invalid, the tile array is returned unchanged.
699
756
  * If the tile is merged with other tiles, the colors of all connected tiles are changed.
700
757
  *
701
758
  * @param x The x-coordinate of the tile.
702
759
  * @param y The y-coordinate of the tile.
703
760
  * @param tile The new tile to set.
704
- * @returns The new grid with the tile set at the given position.
761
+ * @returns The new tile array with updated tiles.
705
762
  */
706
763
  setTile(
707
764
  x: number,
708
765
  y: number,
709
766
  tile: TileData | ((tile: TileData) => TileData)
710
- ): GridData;
767
+ ): readonly (readonly TileData[])[];
711
768
  /**
712
769
  * Replace or modify all tiles in the grid.
713
770
  *
@@ -860,17 +917,6 @@ declare global {
860
917
  * @returns The created tile array.
861
918
  */
862
919
  static createTiles(array: string[]): TileData[][];
863
- /**
864
- * Create a new GridData object from a string array.
865
- *
866
- * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells.
867
- * - Capitalize the letter to make the tile fixed.
868
- * - Use `.` to represent empty space.
869
- *
870
- * @param array - The string array to create the grid from.
871
- * @returns The created grid.
872
- */
873
- static create(array: string[]): GridData;
874
920
  /**
875
921
  * Find a tile in the grid that satisfies the predicate.
876
922
  *
@@ -1539,7 +1585,7 @@ declare global {
1539
1585
  private static readonly CONFIGS;
1540
1586
  private static readonly SEARCH_VARIANTS;
1541
1587
  /**
1542
- * **&lt;count&gt; symbols are lying and can be ignored**
1588
+ * **&lt;count&gt; symbols are lying and are incorrect**
1543
1589
  *
1544
1590
  * @param count Number of lying symbols
1545
1591
  */
@@ -1911,6 +1957,9 @@ declare global {
1911
1957
  stringifyPuzzle(puzzle: Puzzle): string;
1912
1958
  parsePuzzle(input: string): Puzzle;
1913
1959
  }
1960
+ export interface CancelRef {
1961
+ cancel?: () => void;
1962
+ }
1914
1963
  /**
1915
1964
  * Base class that all solvers must extend.
1916
1965
  */
@@ -1940,8 +1989,13 @@ declare global {
1940
1989
  *
1941
1990
  * @param grid The grid to solve. The provided grid is guaranteed to be supported by the solver. Some tiles in the
1942
1991
  * grid may already be filled by the user. It is up to the solver to decide whether to respect these tiles or not.
1992
+ * @param cancelRef A reference to a function that can be called to cancel the solver. If cancellation is supported,
1993
+ * the solver can assign a function to `cancelRef.cancel` that will stop the solver when called.
1943
1994
  */
1944
- abstract solve(grid: GridData): AsyncGenerator<GridData | null>;
1995
+ abstract solve(
1996
+ grid: GridData,
1997
+ cancelRef: CancelRef
1998
+ ): AsyncGenerator<GridData | null>;
1945
1999
  /**
1946
2000
  * Check if the solver supports the current browser environment. This method is called once when the user first clicks
1947
2001
  * the "Solve" button, and the result is cached for the duration of the editor session.
@@ -1972,12 +2026,19 @@ declare global {
1972
2026
  isGridSupported(grid: GridData): boolean;
1973
2027
  }
1974
2028
  export declare const allSolvers: Map<string, Solver>;
1975
- export declare class BacktrackSolver extends Solver {
2029
+ export declare abstract class EventIteratingSolver extends Solver {
2030
+ protected abstract createWorker(): Worker;
2031
+ solve(
2032
+ grid: GridData,
2033
+ cancelRef: CancelRef
2034
+ ): AsyncGenerator<GridData | null>;
2035
+ }
2036
+ export declare class BacktrackSolver extends EventIteratingSolver {
1976
2037
  private static readonly supportedInstrs;
1977
2038
  readonly id = 'backtrack';
1978
2039
  readonly description =
1979
2040
  'Solves puzzles using backtracking with optimizations (blazingly fast). Support most rules and symbols (including underclued).';
1980
- solve(grid: GridData): AsyncGenerator<GridData | null>;
2041
+ protected createWorker(): Worker;
1981
2042
  isInstructionSupported(instructionId: string): boolean;
1982
2043
  }
1983
2044
  export declare enum BTTile {
@@ -2448,11 +2509,11 @@ declare global {
2448
2509
  constructor(instr: ViewpointSymbol);
2449
2510
  checkGlobal(grid: BTGridData): CheckResult | false;
2450
2511
  }
2451
- export declare class UndercluedSolver extends Solver {
2452
- readonly id = 'underclued';
2512
+ export declare class UniversalSolver extends EventIteratingSolver {
2513
+ readonly id = 'universal';
2453
2514
  readonly description =
2454
- 'Solves every puzzle as if it were underclued. Supports all rules and symbols and is decently fast for small puzzles. Very slow for large puzzles.';
2455
- solve(grid: GridData): AsyncGenerator<GridData | null>;
2515
+ 'A backtracking solver that supports all rules and symbols (including underclued) but is less optimized.';
2516
+ protected createWorker(): Worker;
2456
2517
  isInstructionSupported(instructionId: string): boolean;
2457
2518
  }
2458
2519
  export declare class Z3SolverContext<
@@ -22,6 +22,7 @@ export default class GridData {
22
22
  readonly underclued: CachedAccess<UndercluedRule | undefined>;
23
23
  /**
24
24
  * Create a new grid with tiles, connections, symbols and rules.
25
+ *
25
26
  * @param width The width of the grid.
26
27
  * @param height The height of the grid.
27
28
  * @param tiles The tiles of the grid.
@@ -31,6 +32,30 @@ export default class GridData {
31
32
  * @param rules The rules of the grid.
32
33
  */
33
34
  constructor(width: number, height: number, tiles?: readonly (readonly TileData[])[], connections?: GridConnections, zones?: GridZones, symbols?: ReadonlyMap<string, readonly Symbol[]>, rules?: readonly Rule[]);
35
+ /**
36
+ * Create a new GridData object from a string array.
37
+ *
38
+ * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells.
39
+ * - Capitalize the letter to make the tile fixed.
40
+ * - Use `.` to represent empty space.
41
+ *
42
+ * @param array - The string array to create the grid from.
43
+ * @returns The created grid.
44
+ */
45
+ static create(array: string[]): GridData;
46
+ /**
47
+ * Create a new grid with tiles, connections, symbols and rules. Sanitize the provided list of symbols and rules,
48
+ * and trigger grid change events.
49
+ *
50
+ * @param width The width of the grid.
51
+ * @param height The height of the grid.
52
+ * @param tiles The tiles of the grid.
53
+ * @param connections The connections of the grid, which determines which tiles are merged.
54
+ * @param zones The zones of the grid.
55
+ * @param symbols The symbols in the grid.
56
+ * @param rules The rules of the grid.
57
+ */
58
+ static create(width: number, height: number, tiles?: readonly (readonly TileData[])[], connections?: GridConnections, zones?: GridZones, symbols?: ReadonlyMap<string, readonly Symbol[]>, rules?: readonly Rule[]): GridData;
34
59
  /**
35
60
  * Copy the current grid while modifying the provided properties.
36
61
  * @param param0 The properties to modify.
@@ -45,6 +70,22 @@ export default class GridData {
45
70
  symbols?: ReadonlyMap<string, readonly Symbol[]>;
46
71
  rules?: readonly Rule[];
47
72
  }): GridData;
73
+ /**
74
+ * Copy the current grid while modifying the provided properties.
75
+ * Skip sanitization and event triggering for performance.
76
+ *
77
+ * @param param0 The properties to modify.
78
+ * @returns The new grid with the modified properties.
79
+ */
80
+ fastCopyWith({ width, height, tiles, connections, zones, symbols, rules, }: {
81
+ width?: number;
82
+ height?: number;
83
+ tiles?: readonly (readonly TileData[])[];
84
+ connections?: GridConnections;
85
+ zones?: GridZones;
86
+ symbols?: ReadonlyMap<string, readonly Symbol[]>;
87
+ rules?: readonly Rule[];
88
+ }): GridData;
48
89
  isPositionValid(x: number, y: number): boolean;
49
90
  /**
50
91
  * Safely get the tile at the given position.
@@ -55,15 +96,15 @@ export default class GridData {
55
96
  getTile(x: number, y: number): TileData;
56
97
  /**
57
98
  * Safely set the tile at the given position.
58
- * If the position is invalid, the grid is returned unchanged.
99
+ * If the position is invalid, the tile array is returned unchanged.
59
100
  * If the tile is merged with other tiles, the colors of all connected tiles are changed.
60
101
  *
61
102
  * @param x The x-coordinate of the tile.
62
103
  * @param y The y-coordinate of the tile.
63
104
  * @param tile The new tile to set.
64
- * @returns The new grid with the tile set at the given position.
105
+ * @returns The new tile array with updated tiles.
65
106
  */
66
- setTile(x: number, y: number, tile: TileData | ((tile: TileData) => TileData)): GridData;
107
+ setTile(x: number, y: number, tile: TileData | ((tile: TileData) => TileData)): readonly (readonly TileData[])[];
67
108
  /**
68
109
  * Replace or modify all tiles in the grid.
69
110
  *
@@ -199,17 +240,6 @@ export default class GridData {
199
240
  * @returns The created tile array.
200
241
  */
201
242
  static createTiles(array: string[]): TileData[][];
202
- /**
203
- * Create a new GridData object from a string array.
204
- *
205
- * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells.
206
- * - Capitalize the letter to make the tile fixed.
207
- * - Use `.` to represent empty space.
208
- *
209
- * @param array - The string array to create the grid from.
210
- * @returns The created grid.
211
- */
212
- static create(array: string[]): GridData;
213
243
  /**
214
244
  * Find a tile in the grid that satisfies the predicate.
215
245
  *
package/dist/data/grid.js CHANGED
@@ -16,6 +16,7 @@ export default class GridData {
16
16
  /* eslint-enable @typescript-eslint/no-unsafe-enum-comparison */
17
17
  /**
18
18
  * Create a new grid with tiles, connections, symbols and rules.
19
+ *
19
20
  * @param width The width of the grid.
20
21
  * @param height The height of the grid.
21
22
  * @param tiles The tiles of the grid.
@@ -92,25 +93,35 @@ export default class GridData {
92
93
  this.tiles = tiles ?? array(width, height, () => TileData.empty());
93
94
  this.connections = connections ?? new GridConnections();
94
95
  this.zones = zones ?? new GridZones();
95
- const newSymbols = symbols
96
- ? GridData.deduplicateSymbols(symbols)
97
- : new Map();
98
- // do not deduplicate all rules because it makes for bad editor experience
99
- const newRules = rules ? GridData.deduplicateSingletonRules(rules) : [];
100
- this.symbols = newSymbols;
101
- this.rules = newRules;
102
- newSymbols.forEach(list => {
103
- list.forEach((sym, i) => {
104
- if (handlesGridChange(sym)) {
105
- list[i] = sym.onGridChange(this);
96
+ this.symbols = symbols ?? new Map();
97
+ this.rules = rules ?? [];
98
+ }
99
+ static create(arrayOrWidth, height, tiles, connections, zones, symbols, rules) {
100
+ if (typeof arrayOrWidth === 'number') {
101
+ const newSymbols = symbols
102
+ ? GridData.deduplicateSymbols(symbols)
103
+ : new Map();
104
+ // do not deduplicate all rules because it makes for bad editor experience
105
+ const newRules = rules ? GridData.deduplicateSingletonRules(rules) : [];
106
+ const newGrid = new GridData(arrayOrWidth, height, tiles, connections, zones, newSymbols, newRules);
107
+ newSymbols.forEach(list => {
108
+ list.forEach((sym, i) => {
109
+ if (handlesGridChange(sym)) {
110
+ list[i] = sym.onGridChange(newGrid);
111
+ }
112
+ });
113
+ });
114
+ newRules.forEach((rule, i) => {
115
+ if (handlesGridChange(rule)) {
116
+ newRules[i] = rule.onGridChange(newGrid);
106
117
  }
107
118
  });
108
- });
109
- newRules.forEach((rule, i) => {
110
- if (handlesGridChange(rule)) {
111
- newRules[i] = rule.onGridChange(this);
112
- }
113
- });
119
+ return newGrid;
120
+ }
121
+ else {
122
+ const tiles = GridData.createTiles(arrayOrWidth);
123
+ return GridData.create(tiles[0]?.length ?? 0, tiles.length, tiles);
124
+ }
114
125
  }
115
126
  /**
116
127
  * Copy the current grid while modifying the provided properties.
@@ -118,6 +129,16 @@ export default class GridData {
118
129
  * @returns The new grid with the modified properties.
119
130
  */
120
131
  copyWith({ width, height, tiles, connections, zones, symbols, rules, }) {
132
+ return GridData.create(width ?? this.width, height ?? this.height, tiles ?? this.tiles, connections ?? this.connections, zones ?? this.zones, symbols ?? this.symbols, rules ?? this.rules);
133
+ }
134
+ /**
135
+ * Copy the current grid while modifying the provided properties.
136
+ * Skip sanitization and event triggering for performance.
137
+ *
138
+ * @param param0 The properties to modify.
139
+ * @returns The new grid with the modified properties.
140
+ */
141
+ fastCopyWith({ width, height, tiles, connections, zones, symbols, rules, }) {
121
142
  return new GridData(width ?? this.width, height ?? this.height, tiles ?? this.tiles, connections ?? this.connections, zones ?? this.zones, symbols ?? this.symbols, rules ?? this.rules);
122
143
  }
123
144
  isPositionValid(x, y) {
@@ -136,17 +157,17 @@ export default class GridData {
136
157
  }
137
158
  /**
138
159
  * Safely set the tile at the given position.
139
- * If the position is invalid, the grid is returned unchanged.
160
+ * If the position is invalid, the tile array is returned unchanged.
140
161
  * If the tile is merged with other tiles, the colors of all connected tiles are changed.
141
162
  *
142
163
  * @param x The x-coordinate of the tile.
143
164
  * @param y The y-coordinate of the tile.
144
165
  * @param tile The new tile to set.
145
- * @returns The new grid with the tile set at the given position.
166
+ * @returns The new tile array with updated tiles.
146
167
  */
147
168
  setTile(x, y, tile) {
148
169
  if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
149
- return this;
170
+ return this.tiles;
150
171
  }
151
172
  const changing = this.connections.getConnectedTiles({ x, y });
152
173
  const tiles = this.tiles.map(row => [...row]);
@@ -155,7 +176,7 @@ export default class GridData {
155
176
  tiles[y][x] = tiles[y][x].withColor(newTile.color);
156
177
  });
157
178
  tiles[y][x] = newTile;
158
- return this.copyWith({ tiles });
179
+ return tiles;
159
180
  }
160
181
  /**
161
182
  * Replace or modify all tiles in the grid.
@@ -542,20 +563,6 @@ export default class GridData {
542
563
  return TileData.create(row.charAt(x));
543
564
  }));
544
565
  }
545
- /**
546
- * Create a new GridData object from a string array.
547
- *
548
- * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells.
549
- * - Capitalize the letter to make the tile fixed.
550
- * - Use `.` to represent empty space.
551
- *
552
- * @param array - The string array to create the grid from.
553
- * @returns The created grid.
554
- */
555
- static create(array) {
556
- const tiles = GridData.createTiles(array);
557
- return new GridData(tiles[0]?.length ?? 0, tiles.length, tiles);
558
- }
559
566
  /**
560
567
  * Find a tile in the grid that satisfies the predicate.
561
568
  *
@@ -795,7 +802,7 @@ export default class GridData {
795
802
  if (newSymbolList.length > 0)
796
803
  symbols.set(id, newSymbolList);
797
804
  }
798
- return new GridData(width, height, newTiles, connections, zones, symbols, this.rules);
805
+ return GridData.create(width, height, newTiles, connections, zones, symbols, this.rules);
799
806
  }
800
807
  pasteTiles(origin, grid) {
801
808
  if (!(grid instanceof GridData))
@@ -64,7 +64,7 @@ class BanPatternRule extends Rule {
64
64
  return tile;
65
65
  return tile.withExists(false);
66
66
  });
67
- return new GridData(width, height, tiles);
67
+ return GridData.create(width, height, tiles);
68
68
  }
69
69
  get searchVariants() {
70
70
  return BanPatternRule.SEARCH_VARIANTS;
@@ -57,7 +57,7 @@ Object.defineProperty(CustomRule, "EXAMPLE_GRID", {
57
57
  enumerable: true,
58
58
  configurable: true,
59
59
  writable: true,
60
- value: Object.freeze(new GridData(5, 4))
60
+ value: Object.freeze(GridData.create(5, 4))
61
61
  });
62
62
  Object.defineProperty(CustomRule, "configs", {
63
63
  enumerable: true,
@@ -9,7 +9,7 @@ export default class LyingSymbolRule extends Rule implements FinalValidationHand
9
9
  private static readonly CONFIGS;
10
10
  private static readonly SEARCH_VARIANTS;
11
11
  /**
12
- * **&lt;count&gt; symbols are lying and can be ignored**
12
+ * **&lt;count&gt; symbols are lying and are incorrect**
13
13
  *
14
14
  * @param count Number of lying symbols
15
15
  */
@@ -1,12 +1,15 @@
1
1
  import { ConfigType } from '../config.js';
2
2
  import GridData from '../grid.js';
3
- import { Color, State } from '../primitives.js';
3
+ import { Color, Orientation, State, } from '../primitives.js';
4
4
  import Rule from './rule.js';
5
- import CustomIconSymbol from '../symbols/customIconSymbol.js';
6
5
  import validateGrid from '../validate.js';
7
6
  import Symbol from '../symbols/symbol.js';
7
+ import LetterSymbol from '../symbols/letterSymbol.js';
8
+ import GalaxySymbol from '../symbols/galaxySymbol.js';
9
+ import LotusSymbol from '../symbols/lotusSymbol.js';
10
+ import AreaNumberSymbol from '../symbols/areaNumberSymbol.js';
8
11
  class IgnoredSymbol extends Symbol {
9
- constructor(symbol) {
12
+ constructor(symbol, state) {
10
13
  super(symbol.x, symbol.y);
11
14
  Object.defineProperty(this, "symbol", {
12
15
  enumerable: true,
@@ -14,16 +17,23 @@ class IgnoredSymbol extends Symbol {
14
17
  writable: true,
15
18
  value: symbol
16
19
  });
20
+ Object.defineProperty(this, "state", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: state
25
+ });
17
26
  this.symbol = symbol;
27
+ this.state = state;
18
28
  }
19
29
  get id() {
20
- return this.symbol.id;
30
+ return `ignored_${this.symbol.id}`;
21
31
  }
22
32
  get explanation() {
23
33
  return this.symbol.explanation;
24
34
  }
25
35
  get configs() {
26
- return this.symbol.configs;
36
+ return [];
27
37
  }
28
38
  createExampleGrid() {
29
39
  return this.symbol.createExampleGrid();
@@ -38,14 +48,17 @@ class IgnoredSymbol extends Symbol {
38
48
  return this.symbol.sortOrder;
39
49
  }
40
50
  validateSymbol(_grid, _solution) {
41
- return State.Ignored;
51
+ return this.state;
42
52
  }
43
- copyWith({ symbol }) {
44
- return new IgnoredSymbol(symbol ?? this.symbol);
53
+ copyWith({ symbol, state }) {
54
+ return new IgnoredSymbol(symbol ?? this.symbol, state ?? this.state);
45
55
  }
46
56
  withSymbol(symbol) {
47
57
  return this.copyWith({ symbol });
48
58
  }
59
+ equals(other) {
60
+ return other === this;
61
+ }
49
62
  }
50
63
  class IgnoredRule extends Rule {
51
64
  constructor(rule, state) {
@@ -69,11 +82,14 @@ class IgnoredRule extends Rule {
69
82
  return [];
70
83
  }
71
84
  get id() {
72
- return this.rule.id;
85
+ return `ignored_${this.rule.id}`;
73
86
  }
74
87
  get explanation() {
75
88
  return this.rule.explanation;
76
89
  }
90
+ get configs() {
91
+ return [];
92
+ }
77
93
  createExampleGrid() {
78
94
  return this.rule.createExampleGrid();
79
95
  }
@@ -95,10 +111,13 @@ class IgnoredRule extends Rule {
95
111
  copyWith({ rule, state }) {
96
112
  return new IgnoredRule(rule ?? this.rule, state ?? this.state);
97
113
  }
114
+ equals(other) {
115
+ return other === this;
116
+ }
98
117
  }
99
118
  class LyingSymbolRule extends Rule {
100
119
  /**
101
- * **&lt;count&gt; symbols are lying and can be ignored**
120
+ * **&lt;count&gt; symbols are lying and are incorrect**
102
121
  *
103
122
  * @param count Number of lying symbols
104
123
  */
@@ -116,7 +135,7 @@ class LyingSymbolRule extends Rule {
116
135
  return `lying_symbols`;
117
136
  }
118
137
  get explanation() {
119
- return `${this.count} symbol${this.count <= 1 ? ' is' : 's are'} *lying* and can be ignored`;
138
+ return `${this.count} symbol${this.count <= 1 ? ' is' : 's are'} *lying* and ${this.count <= 1 ? 'is' : 'are'} incorrect`;
120
139
  }
121
140
  get configs() {
122
141
  return LyingSymbolRule.CONFIGS;
@@ -156,7 +175,7 @@ class LyingSymbolRule extends Rule {
156
175
  newSymbols.set(key, []);
157
176
  }
158
177
  if (ignoredSymbols.some(([k, i]) => k === key && i === idx)) {
159
- newSymbols.get(key).push(new IgnoredSymbol(symbol));
178
+ newSymbols.get(key).push(new IgnoredSymbol(symbol, State.Ignored));
160
179
  }
161
180
  else {
162
181
  newSymbols.get(key).push(symbol);
@@ -183,7 +202,13 @@ Object.defineProperty(LyingSymbolRule, "EXAMPLE_GRID", {
183
202
  enumerable: true,
184
203
  configurable: true,
185
204
  writable: true,
186
- value: Object.freeze(GridData.create(['.']).addSymbol(new CustomIconSymbol('', GridData.create([]), 0, 0, 'MdOutlineDeblur')))
205
+ value: Object.freeze(GridData.create(['bbbbw', 'wwbbb', 'bbbbw', 'wbbww']).withSymbols([
206
+ new LetterSymbol(4, 0, 'A'),
207
+ new GalaxySymbol(1, 1),
208
+ new LotusSymbol(2, 2, Orientation.Up),
209
+ new LetterSymbol(0, 3, 'A'),
210
+ new AreaNumberSymbol(4, 3, 1),
211
+ ]))
187
212
  });
188
213
  Object.defineProperty(LyingSymbolRule, "CONFIGS", {
189
214
  enumerable: true,
@@ -200,7 +200,7 @@ Object.defineProperty(MusicGridRule, "CONFIGS", {
200
200
  {
201
201
  type: ConfigType.NullableGrid,
202
202
  default: null,
203
- nonNullDefault: new GridData(5, 4).addRule(new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null)),
203
+ nonNullDefault: GridData.create(5, 4).addRule(new MusicGridRule([new ControlLine(0, 120, false, false, DEFAULT_SCALLE)], null)),
204
204
  field: 'track',
205
205
  description: 'Track',
206
206
  configurable: true,
@@ -121,7 +121,7 @@ class MysteryRule extends Rule {
121
121
  return tile.withColor(solutionTile.color);
122
122
  })
123
123
  : solution.tiles;
124
- return new GridData(baseGrid?.width ?? solution.width, baseGrid?.height ?? solution.height, tiles);
124
+ return GridData.create(baseGrid?.width ?? solution.width, baseGrid?.height ?? solution.height, tiles);
125
125
  }
126
126
  }
127
127
  Object.defineProperty(MysteryRule, "EXAMPLE_GRID", {
@@ -62,7 +62,7 @@ class RegionAreaRule extends Rule {
62
62
  ? Color.Dark
63
63
  : Color.Light);
64
64
  });
65
- return new GridData(5, 4, tiles);
65
+ return GridData.create(5, 4, tiles);
66
66
  }
67
67
  }
68
68
  get searchVariants() {
@@ -157,13 +157,13 @@ Object.defineProperty(RegionAreaRule, "EXAMPLE_GRID_LIGHT", {
157
157
  enumerable: true,
158
158
  configurable: true,
159
159
  writable: true,
160
- value: Object.freeze(RegionAreaRule.EXAMPLE_GRID_DARK.map(grid => new GridData(grid.width, grid.height, grid.tiles.map(row => row.map(tile => tile.withColor(tile.color === Color.Dark ? Color.Light : Color.Dark))))))
160
+ value: Object.freeze(RegionAreaRule.EXAMPLE_GRID_DARK.map(grid => GridData.create(grid.width, grid.height, grid.tiles.map(row => row.map(tile => tile.withColor(tile.color === Color.Dark ? Color.Light : Color.Dark))))))
161
161
  });
162
162
  Object.defineProperty(RegionAreaRule, "EXAMPLE_GRID_GRAY", {
163
163
  enumerable: true,
164
164
  configurable: true,
165
165
  writable: true,
166
- value: Object.freeze(RegionAreaRule.EXAMPLE_GRID_DARK.map(grid => new GridData(grid.width, grid.height, grid.tiles.map((row, y) => row.map((tile, x) => tile.withColor(tile.color === Color.Dark
166
+ value: Object.freeze(RegionAreaRule.EXAMPLE_GRID_DARK.map(grid => GridData.create(grid.width, grid.height, grid.tiles.map((row, y) => row.map((tile, x) => tile.withColor(tile.color === Color.Dark
167
167
  ? Color.Gray
168
168
  : x % 2 !== y % 2
169
169
  ? Color.Dark
@@ -422,7 +422,7 @@ export default class SerializerV0 extends SerializerBase {
422
422
  throw new Error(`Invalid data: ${d}`);
423
423
  }
424
424
  }
425
- return new GridData(width ?? tiles?.[0].length ?? 0, height ?? tiles?.length ?? 0, tiles, connections, zones, symbols, rules);
425
+ return GridData.create(width ?? tiles?.[0].length ?? 0, height ?? tiles?.length ?? 0, tiles, connections, zones, symbols, rules);
426
426
  }
427
427
  stringifyPuzzle(puzzle) {
428
428
  let grid = puzzle.grid;
@@ -1,4 +1,4 @@
1
- import UndercluedSolver from './underclued/undercluedSolver.js';
1
+ import UniversalSolver from './universal/universalSolver.js';
2
2
  import BacktrackSolver from './backtrack/backtrackSolver.js';
3
3
  import Z3Solver from './z3/z3Solver.js';
4
4
  const allSolvers = new Map();
@@ -6,6 +6,6 @@ function register(prototype) {
6
6
  allSolvers.set(prototype.id, prototype);
7
7
  }
8
8
  register(new BacktrackSolver());
9
- register(new UndercluedSolver());
9
+ register(new UniversalSolver());
10
10
  register(new Z3Solver());
11
11
  export { allSolvers };
@@ -1,9 +1,8 @@
1
- import GridData from '../../grid.js';
2
- import Solver from '../solver.js';
3
- export default class BacktrackSolver extends Solver {
1
+ import EventIteratingSolver from '../eventIteratingSolver.js';
2
+ export default class BacktrackSolver extends EventIteratingSolver {
4
3
  private static readonly supportedInstrs;
5
4
  readonly id = "backtrack";
6
5
  readonly description = "Solves puzzles using backtracking with optimizations (blazingly fast). Support most rules and symbols (including underclued).";
7
- solve(grid: GridData): AsyncGenerator<GridData | null>;
6
+ protected createWorker(): Worker;
8
7
  isInstructionSupported(instructionId: string): boolean;
9
8
  }