@logic-pad/core 0.4.6 → 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 (41) hide show
  1. package/assets/logic-core.global.d.ts +134 -25
  2. package/dist/data/grid.d.ts +44 -14
  3. package/dist/data/grid.js +43 -36
  4. package/dist/data/primitives.d.ts +19 -1
  5. package/dist/data/primitives.js +20 -0
  6. package/dist/data/rules/banPatternRule.js +1 -1
  7. package/dist/data/rules/customRule.js +1 -1
  8. package/dist/data/rules/lyingSymbolRule.d.ts +30 -0
  9. package/dist/data/rules/lyingSymbolRule.js +239 -0
  10. package/dist/data/rules/musicGridRule.js +1 -1
  11. package/dist/data/rules/mysteryRule.js +2 -2
  12. package/dist/data/rules/offByXRule.d.ts +1 -1
  13. package/dist/data/rules/offByXRule.js +7 -3
  14. package/dist/data/rules/regionAreaRule.js +3 -3
  15. package/dist/data/rules/rules.gen.d.ts +1 -0
  16. package/dist/data/rules/rules.gen.js +1 -0
  17. package/dist/data/serializer/serializer_v0.js +1 -1
  18. package/dist/data/solver/allSolvers.js +2 -2
  19. package/dist/data/solver/backtrack/backtrackSolver.d.ts +3 -4
  20. package/dist/data/solver/backtrack/backtrackSolver.js +4 -30
  21. package/dist/data/solver/backtrack/backtrackWorker.d.ts +1 -2
  22. package/dist/data/solver/backtrack/backtrackWorker.js +12 -8
  23. package/dist/data/solver/eventIteratingSolver.d.ts +6 -0
  24. package/dist/data/solver/eventIteratingSolver.js +33 -0
  25. package/dist/data/solver/solver.d.ts +6 -1
  26. package/dist/data/solver/solver.js +2 -1
  27. package/dist/data/solver/universal/universalSolver.d.ts +7 -0
  28. package/dist/data/solver/universal/universalSolver.js +30 -0
  29. package/dist/data/solver/universal/universalWorker.d.ts +1 -0
  30. package/dist/data/solver/universal/universalWorker.js +119 -0
  31. package/dist/data/symbols/customIconSymbol.js +2 -2
  32. package/dist/data/symbols/customTextSymbol.js +2 -2
  33. package/dist/data/validate.d.ts +1 -1
  34. package/dist/data/validate.js +3 -3
  35. package/dist/index.d.ts +4 -2
  36. package/dist/index.js +4 -2
  37. package/package.json +1 -1
  38. package/dist/data/solver/underclued/undercluedSolver.d.ts +0 -8
  39. package/dist/data/solver/underclued/undercluedSolver.js +0 -55
  40. package/dist/data/solver/underclued/undercluedWorker.d.ts +0 -2
  41. package/dist/data/solver/underclued/undercluedWorker.js +0 -135
@@ -31,9 +31,25 @@ declare global {
31
31
  Underclued = 'underclued',
32
32
  }
33
33
  export declare enum State {
34
+ /**
35
+ * Describes the violation of a rule.
36
+ */
34
37
  Error = 'error',
38
+ /**
39
+ * Describes that a rule is satisfied and complete in the current grid.
40
+ */
35
41
  Satisfied = 'satisfied',
42
+ /**
43
+ * Describes that a rule is not violated, but is not yet complete in the current grid.
44
+ */
36
45
  Incomplete = 'incomplete',
46
+ /**
47
+ * Describes that a rule is violated but ignored due to the effect of another rule.
48
+ */
49
+ Ignored = 'ignored',
50
+ }
51
+ export declare namespace State {
52
+ function isSatisfied(state: State): boolean;
37
53
  }
38
54
  export type RuleState =
39
55
  | {
@@ -45,6 +61,9 @@ declare global {
45
61
  }
46
62
  | {
47
63
  readonly state: State.Incomplete;
64
+ }
65
+ | {
66
+ readonly state: State.Ignored;
48
67
  };
49
68
  export interface GridState {
50
69
  final: State;
@@ -627,6 +646,7 @@ declare global {
627
646
  readonly underclued: CachedAccess<UndercluedRule | undefined>;
628
647
  /**
629
648
  * Create a new grid with tiles, connections, symbols and rules.
649
+ *
630
650
  * @param width The width of the grid.
631
651
  * @param height The height of the grid.
632
652
  * @param tiles The tiles of the grid.
@@ -644,6 +664,38 @@ declare global {
644
664
  symbols?: ReadonlyMap<string, readonly Symbol$1[]>,
645
665
  rules?: readonly Rule[]
646
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;
647
699
  /**
648
700
  * Copy the current grid while modifying the provided properties.
649
701
  * @param param0 The properties to modify.
@@ -666,6 +718,30 @@ declare global {
666
718
  symbols?: ReadonlyMap<string, readonly Symbol$1[]>;
667
719
  rules?: readonly Rule[];
668
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;
669
745
  isPositionValid(x: number, y: number): boolean;
670
746
  /**
671
747
  * Safely get the tile at the given position.
@@ -676,19 +752,19 @@ declare global {
676
752
  getTile(x: number, y: number): TileData;
677
753
  /**
678
754
  * Safely set the tile at the given position.
679
- * If the position is invalid, the grid is returned unchanged.
755
+ * If the position is invalid, the tile array is returned unchanged.
680
756
  * If the tile is merged with other tiles, the colors of all connected tiles are changed.
681
757
  *
682
758
  * @param x The x-coordinate of the tile.
683
759
  * @param y The y-coordinate of the tile.
684
760
  * @param tile The new tile to set.
685
- * @returns The new grid with the tile set at the given position.
761
+ * @returns The new tile array with updated tiles.
686
762
  */
687
763
  setTile(
688
764
  x: number,
689
765
  y: number,
690
766
  tile: TileData | ((tile: TileData) => TileData)
691
- ): GridData;
767
+ ): readonly (readonly TileData[])[];
692
768
  /**
693
769
  * Replace or modify all tiles in the grid.
694
770
  *
@@ -841,17 +917,6 @@ declare global {
841
917
  * @returns The created tile array.
842
918
  */
843
919
  static createTiles(array: string[]): TileData[][];
844
- /**
845
- * Create a new GridData object from a string array.
846
- *
847
- * - Use `b` for dark cells, `w` for light cells, and `n` for gray cells.
848
- * - Capitalize the letter to make the tile fixed.
849
- * - Use `.` to represent empty space.
850
- *
851
- * @param array - The string array to create the grid from.
852
- * @returns The created grid.
853
- */
854
- static create(array: string[]): GridData;
855
920
  /**
856
921
  * Find a tile in the grid that satisfies the predicate.
857
922
  *
@@ -1511,6 +1576,35 @@ declare global {
1511
1576
  }): this;
1512
1577
  }
1513
1578
  export declare const allRules: Map<string, Rule>;
1579
+ export declare class LyingSymbolRule
1580
+ extends Rule
1581
+ implements FinalValidationHandler
1582
+ {
1583
+ readonly count: number;
1584
+ private static readonly EXAMPLE_GRID;
1585
+ private static readonly CONFIGS;
1586
+ private static readonly SEARCH_VARIANTS;
1587
+ /**
1588
+ * **&lt;count&gt; symbols are lying and are incorrect**
1589
+ *
1590
+ * @param count Number of lying symbols
1591
+ */
1592
+ constructor(count: number);
1593
+ get id(): string;
1594
+ get explanation(): string;
1595
+ get configs(): readonly AnyConfig[] | null;
1596
+ createExampleGrid(): GridData;
1597
+ get searchVariants(): SearchVariant[];
1598
+ validateGrid(_: GridData): RuleState;
1599
+ get isSingleton(): boolean;
1600
+ onFinalValidation(
1601
+ grid: GridData,
1602
+ solution: GridData | null,
1603
+ state: GridState
1604
+ ): GridState;
1605
+ copyWith({ count }: { count?: number }): this;
1606
+ withCount(count: number): this;
1607
+ }
1514
1608
  export declare class MysteryRule
1515
1609
  extends Rule
1516
1610
  implements FinalValidationHandler, GridChangeHandler, GridResizeHandler
@@ -1574,7 +1668,7 @@ declare global {
1574
1668
  get configs(): readonly AnyConfig[] | null;
1575
1669
  createExampleGrid(): GridData;
1576
1670
  get searchVariants(): SearchVariant[];
1577
- validateGrid(_grid: GridData): RuleState;
1671
+ validateGrid(grid: GridData): RuleState;
1578
1672
  onSymbolValidation(
1579
1673
  grid: GridData,
1580
1674
  symbol: Symbol$1,
@@ -1863,6 +1957,9 @@ declare global {
1863
1957
  stringifyPuzzle(puzzle: Puzzle): string;
1864
1958
  parsePuzzle(input: string): Puzzle;
1865
1959
  }
1960
+ export interface CancelRef {
1961
+ cancel?: () => void;
1962
+ }
1866
1963
  /**
1867
1964
  * Base class that all solvers must extend.
1868
1965
  */
@@ -1892,8 +1989,13 @@ declare global {
1892
1989
  *
1893
1990
  * @param grid The grid to solve. The provided grid is guaranteed to be supported by the solver. Some tiles in the
1894
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.
1895
1994
  */
1896
- abstract solve(grid: GridData): AsyncGenerator<GridData | null>;
1995
+ abstract solve(
1996
+ grid: GridData,
1997
+ cancelRef: CancelRef
1998
+ ): AsyncGenerator<GridData | null>;
1897
1999
  /**
1898
2000
  * Check if the solver supports the current browser environment. This method is called once when the user first clicks
1899
2001
  * the "Solve" button, and the result is cached for the duration of the editor session.
@@ -1924,12 +2026,19 @@ declare global {
1924
2026
  isGridSupported(grid: GridData): boolean;
1925
2027
  }
1926
2028
  export declare const allSolvers: Map<string, Solver>;
1927
- 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 {
1928
2037
  private static readonly supportedInstrs;
1929
2038
  readonly id = 'backtrack';
1930
2039
  readonly description =
1931
2040
  'Solves puzzles using backtracking with optimizations (blazingly fast). Support most rules and symbols (including underclued).';
1932
- solve(grid: GridData): AsyncGenerator<GridData | null>;
2041
+ protected createWorker(): Worker;
1933
2042
  isInstructionSupported(instructionId: string): boolean;
1934
2043
  }
1935
2044
  export declare enum BTTile {
@@ -2400,11 +2509,11 @@ declare global {
2400
2509
  constructor(instr: ViewpointSymbol);
2401
2510
  checkGlobal(grid: BTGridData): CheckResult | false;
2402
2511
  }
2403
- export declare class UndercluedSolver extends Solver {
2404
- readonly id = 'underclued';
2512
+ export declare class UniversalSolver extends EventIteratingSolver {
2513
+ readonly id = 'universal';
2405
2514
  readonly description =
2406
- '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.';
2407
- 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;
2408
2517
  isInstructionSupported(instructionId: string): boolean;
2409
2518
  }
2410
2519
  export declare class Z3SolverContext<
@@ -2648,10 +2757,10 @@ declare global {
2648
2757
  }
2649
2758
  export declare const allSymbols: Map<string, Symbol$1>;
2650
2759
  export declare function aggregateState(
2651
- rules: RuleState[],
2760
+ rules: readonly RuleState[],
2652
2761
  grid: GridData,
2653
- symbols: Map<string, State[]>
2654
- ): State;
2762
+ symbols: ReadonlyMap<string, State[]>
2763
+ ): State.Error | State.Satisfied | State.Incomplete;
2655
2764
  export declare function applyFinalOverrides(
2656
2765
  grid: GridData,
2657
2766
  solution: GridData | null,
@@ -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))
@@ -17,9 +17,25 @@ export declare enum MajorRule {
17
17
  Underclued = "underclued"
18
18
  }
19
19
  export declare enum State {
20
+ /**
21
+ * Describes the violation of a rule.
22
+ */
20
23
  Error = "error",
24
+ /**
25
+ * Describes that a rule is satisfied and complete in the current grid.
26
+ */
21
27
  Satisfied = "satisfied",
22
- Incomplete = "incomplete"
28
+ /**
29
+ * Describes that a rule is not violated, but is not yet complete in the current grid.
30
+ */
31
+ Incomplete = "incomplete",
32
+ /**
33
+ * Describes that a rule is violated but ignored due to the effect of another rule.
34
+ */
35
+ Ignored = "ignored"
36
+ }
37
+ export declare namespace State {
38
+ function isSatisfied(state: State): boolean;
23
39
  }
24
40
  export type RuleState = {
25
41
  readonly state: State.Error;
@@ -28,6 +44,8 @@ export type RuleState = {
28
44
  readonly state: State.Satisfied;
29
45
  } | {
30
46
  readonly state: State.Incomplete;
47
+ } | {
48
+ readonly state: State.Ignored;
31
49
  };
32
50
  export interface GridState {
33
51
  final: State;
@@ -9,9 +9,29 @@ export var MajorRule;
9
9
  })(MajorRule || (MajorRule = {}));
10
10
  export var State;
11
11
  (function (State) {
12
+ /**
13
+ * Describes the violation of a rule.
14
+ */
12
15
  State["Error"] = "error";
16
+ /**
17
+ * Describes that a rule is satisfied and complete in the current grid.
18
+ */
13
19
  State["Satisfied"] = "satisfied";
20
+ /**
21
+ * Describes that a rule is not violated, but is not yet complete in the current grid.
22
+ */
14
23
  State["Incomplete"] = "incomplete";
24
+ /**
25
+ * Describes that a rule is violated but ignored due to the effect of another rule.
26
+ */
27
+ State["Ignored"] = "ignored";
28
+ })(State || (State = {}));
29
+ // eslint-disable-next-line @typescript-eslint/no-namespace
30
+ (function (State) {
31
+ function isSatisfied(state) {
32
+ return state === State.Satisfied || state === State.Ignored;
33
+ }
34
+ State.isSatisfied = isSatisfied;
15
35
  })(State || (State = {}));
16
36
  export var Color;
17
37
  (function (Color) {
@@ -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,
@@ -0,0 +1,30 @@
1
+ import { AnyConfig } from '../config.js';
2
+ import { FinalValidationHandler } from '../events/onFinalValidation.js';
3
+ import GridData from '../grid.js';
4
+ import { GridState, RuleState } from '../primitives.js';
5
+ import Rule, { SearchVariant } from './rule.js';
6
+ export default class LyingSymbolRule extends Rule implements FinalValidationHandler {
7
+ readonly count: number;
8
+ private static readonly EXAMPLE_GRID;
9
+ private static readonly CONFIGS;
10
+ private static readonly SEARCH_VARIANTS;
11
+ /**
12
+ * **&lt;count&gt; symbols are lying and are incorrect**
13
+ *
14
+ * @param count Number of lying symbols
15
+ */
16
+ constructor(count: number);
17
+ get id(): string;
18
+ get explanation(): string;
19
+ get configs(): readonly AnyConfig[] | null;
20
+ createExampleGrid(): GridData;
21
+ get searchVariants(): SearchVariant[];
22
+ validateGrid(_: GridData): RuleState;
23
+ get isSingleton(): boolean;
24
+ onFinalValidation(grid: GridData, solution: GridData | null, state: GridState): GridState;
25
+ copyWith({ count }: {
26
+ count?: number;
27
+ }): this;
28
+ withCount(count: number): this;
29
+ }
30
+ export declare const instance: LyingSymbolRule;