@logic-pad/core 0.7.0 → 0.10.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 (40) hide show
  1. package/assets/logic-core.global.d.ts +72 -13
  2. package/dist/data/grid.js +1 -0
  3. package/dist/data/primitives.d.ts +2 -1
  4. package/dist/data/primitives.js +2 -0
  5. package/dist/data/rules/banPatternRule.js +8 -0
  6. package/dist/data/rules/musicGridRule.d.ts +1 -1
  7. package/dist/data/rules/musicGridRule.js +2 -7
  8. package/dist/data/rules/wrapAroundRule.d.ts +0 -2
  9. package/dist/data/rules/wrapAroundRule.js +124 -58
  10. package/dist/data/solver/allSolvers.js +2 -0
  11. package/dist/data/solver/backtrack/backtrackSolver.d.ts +2 -1
  12. package/dist/data/solver/backtrack/backtrackSolver.js +10 -2
  13. package/dist/data/solver/backtrack/backtrackWorker.js +11 -0
  14. package/dist/data/solver/backtrack/symbols/focus.d.ts +9 -0
  15. package/dist/data/solver/backtrack/symbols/focus.js +59 -0
  16. package/dist/data/solver/cspuz/cspuzSolver.d.ts +12 -0
  17. package/dist/data/solver/cspuz/cspuzSolver.js +113 -0
  18. package/dist/data/solver/cspuz/cspuzWorker.d.ts +1 -0
  19. package/dist/data/solver/cspuz/cspuzWorker.js +44 -0
  20. package/dist/data/solver/cspuz/jsonify.d.ts +3 -0
  21. package/dist/data/solver/cspuz/jsonify.js +211 -0
  22. package/dist/data/solver/eventIteratingSolver.d.ts +3 -2
  23. package/dist/data/solver/eventIteratingSolver.js +17 -3
  24. package/dist/data/solver/solver.d.ts +11 -6
  25. package/dist/data/solver/universal/universalSolver.d.ts +1 -0
  26. package/dist/data/solver/universal/universalSolver.js +6 -0
  27. package/dist/data/solver/universal/universalWorker.js +5 -0
  28. package/dist/data/solver/z3/z3Solver.d.ts +3 -1
  29. package/dist/data/solver/z3/z3Solver.js +13 -1
  30. package/dist/data/symbols/directionLinkerSymbol.js +22 -13
  31. package/dist/data/symbols/focusSymbol.d.ts +30 -0
  32. package/dist/data/symbols/focusSymbol.js +110 -0
  33. package/dist/data/symbols/minesweeperSymbol.d.ts +1 -1
  34. package/dist/data/symbols/minesweeperSymbol.js +9 -2
  35. package/dist/data/symbols/symbols.gen.d.ts +1 -0
  36. package/dist/data/symbols/symbols.gen.js +1 -0
  37. package/dist/data/symbols/viewpointSymbol.js +9 -11
  38. package/dist/index.d.ts +5 -1
  39. package/dist/index.js +5 -1
  40. package/package.json +1 -1
@@ -9,6 +9,7 @@ declare global {
9
9
  // Generated by dts-bundle-generator v9.5.1
10
10
 
11
11
  import { RegionConstrainer, SymbolGrid } from 'grilops';
12
+ import { PuzzleData } from 'logic-pad-solver-core';
12
13
  import { Optimize, Solver as Solver$1, Z3LowLevel } from 'z3-solver';
13
14
  import { z } from 'zod';
14
15
 
@@ -86,6 +87,7 @@ declare global {
86
87
  None = 'none',
87
88
  Wrap = 'wrap',
88
89
  WrapReverse = 'wrap-reverse',
90
+ ReflectReverse = 'reflect-reverse',
89
91
  }
90
92
  export declare const WRAPPINGS: readonly Wrapping[];
91
93
  export declare enum Direction {
@@ -567,7 +569,7 @@ declare global {
567
569
  get configs(): readonly AnyConfig[] | null;
568
570
  createExampleGrid(): GridData;
569
571
  get searchVariants(): SearchVariant[];
570
- validateGrid(grid: GridData): RuleState;
572
+ validateGrid(_grid: GridData): RuleState;
571
573
  onSetGrid(
572
574
  _oldGrid: GridData,
573
575
  newGrid: GridData,
@@ -650,9 +652,7 @@ declare global {
650
652
  readonly vertical: Wrapping;
651
653
  private static readonly EXAMPLE_GRID_NONE;
652
654
  private static readonly EXAMPLE_GRID_HORIZONTAL;
653
- private static readonly EXAMPLE_GRID_HORIZONTAL_REVERSE;
654
655
  private static readonly EXAMPLE_GRID_VERTICAL;
655
- private static readonly EXAMPLE_GRID_VERTICAL_REVERSE;
656
656
  private static readonly SEARCH_VARIANTS;
657
657
  private static readonly CONFIGS;
658
658
  /**
@@ -2034,9 +2034,6 @@ declare global {
2034
2034
  stringifyPuzzle(puzzle: Puzzle): string;
2035
2035
  parsePuzzle(input: string): Puzzle;
2036
2036
  }
2037
- export interface CancelRef {
2038
- cancel?: () => void;
2039
- }
2040
2037
  /**
2041
2038
  * Base class that all solvers must extend.
2042
2039
  */
@@ -2047,10 +2044,18 @@ declare global {
2047
2044
  * This is also displayed to the user when selecting a solver.
2048
2045
  */
2049
2046
  abstract get id(): string;
2047
+ /**
2048
+ * The author(s) of the solver.
2049
+ */
2050
+ abstract get author(): string;
2050
2051
  /**
2051
2052
  * A short paragraph describing when the user should use this solver.
2052
2053
  */
2053
2054
  abstract get description(): string;
2055
+ /**
2056
+ * Whether the solver supports cancellation. If `true`, the solver must respond to the abort signal if it is provided.
2057
+ */
2058
+ abstract get supportsCancellation(): boolean;
2054
2059
  /**
2055
2060
  * Solve the given grid. The implementation should delegate long-running tasks to a worker thread and yield solutions
2056
2061
  * asynchronously.
@@ -2066,12 +2071,12 @@ declare global {
2066
2071
  *
2067
2072
  * @param grid The grid to solve. The provided grid is guaranteed to be supported by the solver. Some tiles in the
2068
2073
  * grid may already be filled by the user. It is up to the solver to decide whether to respect these tiles or not.
2069
- * @param cancelRef A reference to a function that can be called to cancel the solver. If cancellation is supported,
2070
- * the solver can assign a function to `cancelRef.cancel` that will stop the solver when called.
2074
+ * @param abortSignal An optional signal that the solver should subscribe to in order to cancel the operation. If the
2075
+ * solver does not support cancellation, it should ignore this parameter.
2071
2076
  */
2072
2077
  abstract solve(
2073
2078
  grid: GridData,
2074
- cancelRef: CancelRef
2079
+ abortSignal?: AbortSignal
2075
2080
  ): AsyncGenerator<GridData | null>;
2076
2081
  /**
2077
2082
  * Check if the solver supports the current browser environment. This method is called once when the user first clicks
@@ -2104,17 +2109,19 @@ declare global {
2104
2109
  }
2105
2110
  export declare const allSolvers: Map<string, Solver>;
2106
2111
  export declare abstract class EventIteratingSolver extends Solver {
2112
+ readonly supportsCancellation = true;
2107
2113
  protected abstract createWorker(): Worker;
2108
2114
  solve(
2109
2115
  grid: GridData,
2110
- cancelRef: CancelRef
2116
+ abortSignal?: AbortSignal
2111
2117
  ): AsyncGenerator<GridData | null>;
2112
2118
  }
2113
2119
  export declare class BacktrackSolver extends EventIteratingSolver {
2114
2120
  private static readonly supportedInstrs;
2115
2121
  readonly id = 'backtrack';
2122
+ readonly author = 'ALaggyDev';
2116
2123
  readonly description =
2117
- 'Solves puzzles using backtracking with optimizations (blazingly fast). Support most rules and symbols (including underclued).';
2124
+ 'Solves puzzles pretty fast using backtracking with optimizations. Support most rules and symbols (including underclued).';
2118
2125
  protected createWorker(): Worker;
2119
2126
  isInstructionSupported(instructionId: string): boolean;
2120
2127
  }
@@ -2357,6 +2364,43 @@ declare global {
2357
2364
  y: number
2358
2365
  ): Position$1 | null;
2359
2366
  }
2367
+ export declare class FocusSymbol extends NumberSymbol {
2368
+ private static readonly CONFIGS;
2369
+ private static readonly EXAMPLE_GRID;
2370
+ /**
2371
+ * **Focus Numbers count directly adjacent cells of the same color**
2372
+ * @param x - The x-coordinate of the symbol.
2373
+ * @param y - The y-coordinate of the symbol.
2374
+ * @param number - The focus number.
2375
+ */
2376
+ constructor(x: number, y: number, number: number);
2377
+ get id(): string;
2378
+ get placementStep(): number;
2379
+ get explanation(): string;
2380
+ get configs(): readonly AnyConfig[] | null;
2381
+ createExampleGrid(): GridData;
2382
+ countTiles(grid: GridData): {
2383
+ completed: number;
2384
+ possible: number;
2385
+ };
2386
+ copyWith({
2387
+ x,
2388
+ y,
2389
+ number,
2390
+ }: {
2391
+ x?: number;
2392
+ y?: number;
2393
+ number?: number;
2394
+ }): this;
2395
+ withNumber(number: number): this;
2396
+ }
2397
+ export declare class FocusBTModule extends BTModule {
2398
+ instr: FocusSymbol;
2399
+ private cachedCheckResult?;
2400
+ constructor(instr: FocusSymbol);
2401
+ checkGlobal(grid: BTGridData): CheckResult | false;
2402
+ private buildCheckAndRating;
2403
+ }
2360
2404
  export declare class GalaxySymbol extends DirectionLinkerSymbol {
2361
2405
  readonly x: number;
2362
2406
  readonly y: number;
@@ -2464,7 +2508,7 @@ declare global {
2464
2508
  private static readonly CONFIGS;
2465
2509
  private static readonly EXAMPLE_GRID;
2466
2510
  /**
2467
- * **Minesweeper numbers count opposite cells in 8 adjacent spaces**
2511
+ * **Minesweeper Numbers count opposite cells in 8 adjacent spaces**
2468
2512
  *
2469
2513
  * @param x - The x-coordinate of the symbol.
2470
2514
  * @param y - The y-coordinate of the symbol.
@@ -2586,8 +2630,21 @@ declare global {
2586
2630
  constructor(instr: ViewpointSymbol);
2587
2631
  checkGlobal(grid: BTGridData): CheckResult | false;
2588
2632
  }
2633
+ export declare class CspuzSolver extends EventIteratingSolver {
2634
+ private static readonly supportedInstrs;
2635
+ readonly id = 'cspuz';
2636
+ readonly author = 'semiexp';
2637
+ readonly description =
2638
+ 'A blazingly fast WebAssembly solver that supports most rules and symbols (including underclued). No uniqueness check yet.';
2639
+ protected createWorker(): Worker;
2640
+ isGridSupported(grid: GridData): boolean;
2641
+ isInstructionSupported(instructionId: string): boolean;
2642
+ isEnvironmentSupported(): Promise<boolean>;
2643
+ }
2644
+ export declare function gridToJson(grid: GridData): PuzzleData;
2589
2645
  export declare class UniversalSolver extends EventIteratingSolver {
2590
2646
  readonly id = 'universal';
2647
+ readonly author = 'romain22222, Lysine';
2591
2648
  readonly description =
2592
2649
  'A backtracking solver that supports all rules and symbols (including underclued) but is less optimized.';
2593
2650
  protected createWorker(): Worker;
@@ -2678,8 +2735,10 @@ declare global {
2678
2735
  ): import('grilops').Direction;
2679
2736
  export declare class Z3Solver extends Solver {
2680
2737
  readonly id = 'z3';
2738
+ readonly author = 'Lysine';
2681
2739
  readonly description =
2682
- 'Good for confirming that a solution is unique, especially for larger puzzles. It is otherwise slower than most solvers in small to medium-sized puzzles.';
2740
+ '(Obsolete) A WebAssembly solver that supports a limited set of rules and symbols.';
2741
+ readonly supportsCancellation = false;
2683
2742
  isEnvironmentSupported(): Promise<boolean>;
2684
2743
  solve(grid: GridData): AsyncGenerator<GridData | null>;
2685
2744
  isInstructionSupported(instructionId: string): boolean;
package/dist/data/grid.js CHANGED
@@ -204,6 +204,7 @@ export default class GridData {
204
204
  const tiles = this.tiles.map(row => [...row]);
205
205
  const newTile = typeof tile === 'function' ? tile(tiles[y][x]) : tile;
206
206
  changing.forEach(({ x, y }) => {
207
+ ({ x, y } = this.toArrayCoordinates(x, y));
207
208
  tiles[y][x] = tiles[y][x].withColor(newTile.color);
208
209
  });
209
210
  tiles[y][x] = newTile;
@@ -67,7 +67,8 @@ export declare const COMPARISONS: readonly Comparison[];
67
67
  export declare enum Wrapping {
68
68
  None = "none",
69
69
  Wrap = "wrap",
70
- WrapReverse = "wrap-reverse"
70
+ WrapReverse = "wrap-reverse",
71
+ ReflectReverse = "reflect-reverse"
71
72
  }
72
73
  export declare const WRAPPINGS: readonly Wrapping[];
73
74
  export declare enum Direction {
@@ -56,11 +56,13 @@ export var Wrapping;
56
56
  Wrapping["None"] = "none";
57
57
  Wrapping["Wrap"] = "wrap";
58
58
  Wrapping["WrapReverse"] = "wrap-reverse";
59
+ Wrapping["ReflectReverse"] = "reflect-reverse";
59
60
  })(Wrapping || (Wrapping = {}));
60
61
  export const WRAPPINGS = [
61
62
  Wrapping.None,
62
63
  Wrapping.Wrap,
63
64
  Wrapping.WrapReverse,
65
+ Wrapping.ReflectReverse,
64
66
  ];
65
67
  export var Direction;
66
68
  (function (Direction) {
@@ -74,7 +74,15 @@ class BanPatternRule extends Rule {
74
74
  for (let y = 0; y <= grid.height - 1; y++) {
75
75
  for (let x = 0; x <= grid.width - 1; x++) {
76
76
  let match = true;
77
+ const visited = [];
77
78
  for (const tile of pattern.elements) {
79
+ const pos = grid.toArrayCoordinates(x + tile.x, y + tile.y);
80
+ if (grid.wrapAround.value && // optimization: not need to check visited if wrapAround is disabled
81
+ visited.some(p => p.x === pos.x && p.y === pos.y)) {
82
+ match = false;
83
+ break;
84
+ }
85
+ visited.push(pos);
78
86
  const t = grid.getTile(x + tile.x, y + tile.y);
79
87
  if (!t.exists || t.color !== tile.color) {
80
88
  match = false;
@@ -25,7 +25,7 @@ export default class MusicGridRule extends Rule implements GridChangeHandler, Se
25
25
  get configs(): readonly AnyConfig[] | null;
26
26
  createExampleGrid(): GridData;
27
27
  get searchVariants(): SearchVariant[];
28
- validateGrid(grid: GridData): RuleState;
28
+ validateGrid(_grid: GridData): RuleState;
29
29
  onSetGrid(_oldGrid: GridData, newGrid: GridData, _solution: GridData | null): GridData;
30
30
  onGridChange(newGrid: GridData): this;
31
31
  onGridResize(_grid: GridData, mode: 'insert' | 'remove', direction: 'row' | 'column', index: number): this | null;
@@ -61,13 +61,8 @@ class MusicGridRule extends Rule {
61
61
  get searchVariants() {
62
62
  return MusicGridRule.SEARCH_VARIANTS;
63
63
  }
64
- validateGrid(grid) {
65
- if (grid.getTileCount(true, false, Color.Gray) > 0) {
66
- return { state: State.Incomplete };
67
- }
68
- else {
69
- return { state: State.Satisfied };
70
- }
64
+ validateGrid(_grid) {
65
+ return { state: State.Incomplete };
71
66
  }
72
67
  onSetGrid(_oldGrid, newGrid, _solution) {
73
68
  if (newGrid.getTileCount(true, undefined, Color.Gray) === 0)
@@ -8,9 +8,7 @@ export default class WrapAroundRule extends Rule implements GetTileHandler {
8
8
  readonly vertical: Wrapping;
9
9
  private static readonly EXAMPLE_GRID_NONE;
10
10
  private static readonly EXAMPLE_GRID_HORIZONTAL;
11
- private static readonly EXAMPLE_GRID_HORIZONTAL_REVERSE;
12
11
  private static readonly EXAMPLE_GRID_VERTICAL;
13
- private static readonly EXAMPLE_GRID_VERTICAL_REVERSE;
14
12
  private static readonly SEARCH_VARIANTS;
15
13
  private static readonly CONFIGS;
16
14
  /**
@@ -1,8 +1,9 @@
1
1
  import { ConfigType } from '../config.js';
2
2
  import { array } from '../dataHelper.js';
3
3
  import GridData from '../grid.js';
4
- import { Color, MajorRule, State, Wrapping, } from '../primitives.js';
4
+ import { Color, MajorRule, Orientation, State, Wrapping, orientationToggle, } from '../primitives.js';
5
5
  import LetterSymbol from '../symbols/letterSymbol.js';
6
+ import MyopiaSymbol from '../symbols/myopiaSymbol.js';
6
7
  import Rule from './rule.js';
7
8
  class WrapAroundRule extends Rule {
8
9
  /**
@@ -29,19 +30,32 @@ class WrapAroundRule extends Rule {
29
30
  this.vertical = vertical;
30
31
  }
31
32
  onGetTile(x, y, grid) {
33
+ if (grid.width === 0 || grid.height === 0) {
34
+ return { x, y };
35
+ }
32
36
  if (this.horizontal !== Wrapping.None) {
33
37
  const idx = Math.abs(Math.floor(x / grid.width));
34
38
  x = ((x % grid.width) + grid.width) % grid.width;
35
- if (this.horizontal === Wrapping.WrapReverse && idx % 2 === 1) {
39
+ if ((this.horizontal === Wrapping.WrapReverse ||
40
+ this.horizontal === Wrapping.ReflectReverse) &&
41
+ idx % 2 === 1) {
36
42
  y = grid.height - 1 - y;
37
43
  }
44
+ if (this.horizontal === Wrapping.ReflectReverse && idx % 2 === 1) {
45
+ x = grid.width - 1 - x;
46
+ }
38
47
  }
39
48
  if (this.vertical !== Wrapping.None) {
40
49
  const idx = Math.abs(Math.floor(y / grid.height));
41
50
  y = ((y % grid.height) + grid.height) % grid.height;
42
- if (this.vertical === Wrapping.WrapReverse && idx % 2 === 1) {
51
+ if ((this.vertical === Wrapping.WrapReverse ||
52
+ this.vertical === Wrapping.ReflectReverse) &&
53
+ idx % 2 === 1) {
43
54
  x = grid.width - 1 - x;
44
55
  }
56
+ if (this.vertical === Wrapping.ReflectReverse && idx % 2 === 1) {
57
+ y = grid.height - 1 - y;
58
+ }
45
59
  }
46
60
  return { x, y };
47
61
  }
@@ -52,37 +66,48 @@ class WrapAroundRule extends Rule {
52
66
  if (this.horizontal === Wrapping.None && this.vertical === Wrapping.None) {
53
67
  return `No edges are connected.`;
54
68
  }
55
- else if (this.horizontal === Wrapping.None) {
56
- return `The top and bottom edges are connected${this.vertical === Wrapping.WrapReverse ? ' in reverse' : ''}.`;
69
+ const horizontal = this.horizontal === Wrapping.None
70
+ ? null
71
+ : this.horizontal === Wrapping.Wrap ||
72
+ this.horizontal === Wrapping.WrapReverse
73
+ ? 'connected'
74
+ : 'reflective';
75
+ const vertical = this.vertical === Wrapping.None
76
+ ? null
77
+ : this.vertical === Wrapping.Wrap ||
78
+ this.vertical === Wrapping.WrapReverse
79
+ ? 'connected'
80
+ : 'reflective';
81
+ const horizontalReverse = this.horizontal === Wrapping.WrapReverse ||
82
+ this.horizontal === Wrapping.ReflectReverse
83
+ ? ' in reverse'
84
+ : '';
85
+ const verticalReverse = this.vertical === Wrapping.WrapReverse ||
86
+ this.vertical === Wrapping.ReflectReverse
87
+ ? ' in reverse'
88
+ : '';
89
+ if (this.horizontal === this.vertical) {
90
+ return `All four edges are ${horizontal}${horizontalReverse}.`;
57
91
  }
58
- else if (this.vertical === Wrapping.None) {
59
- return `The left and right edges are connected${this.horizontal === Wrapping.WrapReverse ? ' in reverse' : ''}.`;
92
+ if (this.horizontal === Wrapping.None) {
93
+ return `The top and bottom edges are ${vertical}${verticalReverse}.`;
60
94
  }
61
- else if (this.horizontal === Wrapping.Wrap &&
62
- this.vertical === Wrapping.Wrap) {
63
- return `All four edges are connected.`;
95
+ if (this.vertical === Wrapping.None) {
96
+ return `The left and right edges are ${horizontal}${horizontalReverse}.`;
64
97
  }
65
- else if (this.horizontal === Wrapping.Wrap) {
66
- return `All four edges are connected, with the top and bottom edges in reverse.`;
67
- }
68
- else if (this.vertical === Wrapping.Wrap) {
69
- return `All four edges are connected, with the left and right edges in reverse.`;
70
- }
71
- else {
72
- return `All four edges are connected in reverse.`;
98
+ if (horizontal === vertical) {
99
+ if (horizontalReverse !== '') {
100
+ return `All four edges are ${horizontal}, with the left and right edges${horizontalReverse}.`;
101
+ }
102
+ else {
103
+ return `All four edges are ${horizontal}, with the top and bottom edges${verticalReverse}.`;
104
+ }
73
105
  }
106
+ return `The left and right edges are ${horizontal}${horizontalReverse}. The top and bottom edges are ${vertical}${verticalReverse}.`;
74
107
  }
75
108
  createExampleGrid() {
76
- const horizontal = this.horizontal === Wrapping.Wrap
77
- ? WrapAroundRule.EXAMPLE_GRID_HORIZONTAL
78
- : this.horizontal === Wrapping.WrapReverse
79
- ? WrapAroundRule.EXAMPLE_GRID_HORIZONTAL_REVERSE
80
- : WrapAroundRule.EXAMPLE_GRID_NONE;
81
- const vertical = this.vertical === Wrapping.Wrap
82
- ? WrapAroundRule.EXAMPLE_GRID_VERTICAL
83
- : this.vertical === Wrapping.WrapReverse
84
- ? WrapAroundRule.EXAMPLE_GRID_VERTICAL_REVERSE
85
- : WrapAroundRule.EXAMPLE_GRID_NONE;
109
+ const horizontal = WrapAroundRule.EXAMPLE_GRID_HORIZONTAL[this.horizontal];
110
+ const vertical = WrapAroundRule.EXAMPLE_GRID_VERTICAL[this.vertical];
86
111
  if (horizontal === WrapAroundRule.EXAMPLE_GRID_NONE) {
87
112
  return vertical;
88
113
  }
@@ -134,41 +159,79 @@ Object.defineProperty(WrapAroundRule, "EXAMPLE_GRID_HORIZONTAL", {
134
159
  enumerable: true,
135
160
  configurable: true,
136
161
  writable: true,
137
- value: Object.freeze(GridData.create(['wwwww', 'bwwwb', 'wwwww', 'bwwwb', 'wwwww'])
138
- .addSymbol(new LetterSymbol(0, 1, 'A'))
139
- .addSymbol(new LetterSymbol(4, 1, 'A'))
140
- .addSymbol(new LetterSymbol(0, 3, 'B'))
141
- .addSymbol(new LetterSymbol(4, 3, 'B')))
142
- });
143
- Object.defineProperty(WrapAroundRule, "EXAMPLE_GRID_HORIZONTAL_REVERSE", {
144
- enumerable: true,
145
- configurable: true,
146
- writable: true,
147
- value: Object.freeze(GridData.create(['wwwww', 'bwwwb', 'wwwww', 'bwwwb', 'wwwww'])
148
- .addSymbol(new LetterSymbol(0, 1, 'A'))
149
- .addSymbol(new LetterSymbol(4, 1, 'B'))
150
- .addSymbol(new LetterSymbol(0, 3, 'B'))
151
- .addSymbol(new LetterSymbol(4, 3, 'A')))
162
+ value: Object.freeze({
163
+ [Wrapping.None]: WrapAroundRule.EXAMPLE_GRID_NONE,
164
+ [Wrapping.Wrap]: GridData.create([
165
+ 'wwwww',
166
+ 'bwwwb',
167
+ 'wwwww',
168
+ 'bwwwb',
169
+ 'wwwww',
170
+ ])
171
+ .addSymbol(new LetterSymbol(0, 1, 'A'))
172
+ .addSymbol(new LetterSymbol(4, 1, 'A'))
173
+ .addSymbol(new LetterSymbol(0, 3, 'B'))
174
+ .addSymbol(new LetterSymbol(4, 3, 'B')),
175
+ [Wrapping.WrapReverse]: GridData.create([
176
+ 'wwwww',
177
+ 'bwwwb',
178
+ 'wwwww',
179
+ 'bwwwb',
180
+ 'wwwww',
181
+ ])
182
+ .addSymbol(new LetterSymbol(0, 1, 'A'))
183
+ .addSymbol(new LetterSymbol(4, 1, 'B'))
184
+ .addSymbol(new LetterSymbol(0, 3, 'B'))
185
+ .addSymbol(new LetterSymbol(4, 3, 'A')),
186
+ [Wrapping.ReflectReverse]: GridData.create([
187
+ 'wwwww',
188
+ 'bwwww',
189
+ 'wwwww',
190
+ 'wwwwb',
191
+ 'wwwww',
192
+ ])
193
+ .addSymbol(new MyopiaSymbol(0, 3, false, orientationToggle(Orientation.Left)))
194
+ .addSymbol(new MyopiaSymbol(4, 1, false, orientationToggle(Orientation.Right))),
195
+ })
152
196
  });
153
197
  Object.defineProperty(WrapAroundRule, "EXAMPLE_GRID_VERTICAL", {
154
198
  enumerable: true,
155
199
  configurable: true,
156
200
  writable: true,
157
- value: Object.freeze(GridData.create(['wbwbw', 'wwwww', 'wwwww', 'wwwww', 'wbwbw'])
158
- .addSymbol(new LetterSymbol(1, 0, 'C'))
159
- .addSymbol(new LetterSymbol(3, 0, 'D'))
160
- .addSymbol(new LetterSymbol(1, 4, 'C'))
161
- .addSymbol(new LetterSymbol(3, 4, 'D')))
162
- });
163
- Object.defineProperty(WrapAroundRule, "EXAMPLE_GRID_VERTICAL_REVERSE", {
164
- enumerable: true,
165
- configurable: true,
166
- writable: true,
167
- value: Object.freeze(GridData.create(['wbwbw', 'wwwww', 'wwwww', 'wwwww', 'wbwbw'])
168
- .addSymbol(new LetterSymbol(1, 0, 'C'))
169
- .addSymbol(new LetterSymbol(3, 0, 'D'))
170
- .addSymbol(new LetterSymbol(1, 4, 'D'))
171
- .addSymbol(new LetterSymbol(3, 4, 'C')))
201
+ value: Object.freeze({
202
+ [Wrapping.None]: WrapAroundRule.EXAMPLE_GRID_NONE,
203
+ [Wrapping.Wrap]: GridData.create([
204
+ 'wbwbw',
205
+ 'wwwww',
206
+ 'wwwww',
207
+ 'wwwww',
208
+ 'wbwbw',
209
+ ])
210
+ .addSymbol(new LetterSymbol(1, 0, 'C'))
211
+ .addSymbol(new LetterSymbol(3, 0, 'D'))
212
+ .addSymbol(new LetterSymbol(1, 4, 'C'))
213
+ .addSymbol(new LetterSymbol(3, 4, 'D')),
214
+ [Wrapping.WrapReverse]: GridData.create([
215
+ 'wbwbw',
216
+ 'wwwww',
217
+ 'wwwww',
218
+ 'wwwww',
219
+ 'wbwbw',
220
+ ])
221
+ .addSymbol(new LetterSymbol(1, 0, 'C'))
222
+ .addSymbol(new LetterSymbol(3, 0, 'D'))
223
+ .addSymbol(new LetterSymbol(1, 4, 'D'))
224
+ .addSymbol(new LetterSymbol(3, 4, 'C')),
225
+ [Wrapping.ReflectReverse]: GridData.create([
226
+ 'wbwww',
227
+ 'wwwww',
228
+ 'wwwww',
229
+ 'wwwww',
230
+ 'wwwbw',
231
+ ])
232
+ .addSymbol(new MyopiaSymbol(3, 0, false, orientationToggle(Orientation.Up)))
233
+ .addSymbol(new MyopiaSymbol(1, 4, false, orientationToggle(Orientation.Down))),
234
+ })
172
235
  });
173
236
  Object.defineProperty(WrapAroundRule, "SEARCH_VARIANTS", {
174
237
  enumerable: true,
@@ -178,6 +241,9 @@ Object.defineProperty(WrapAroundRule, "SEARCH_VARIANTS", {
178
241
  new WrapAroundRule(Wrapping.Wrap, Wrapping.None).searchVariant(),
179
242
  new WrapAroundRule(Wrapping.None, Wrapping.Wrap).searchVariant(),
180
243
  new WrapAroundRule(Wrapping.Wrap, Wrapping.Wrap).searchVariant(),
244
+ new WrapAroundRule(Wrapping.ReflectReverse, Wrapping.None).searchVariant(),
245
+ new WrapAroundRule(Wrapping.None, Wrapping.ReflectReverse).searchVariant(),
246
+ new WrapAroundRule(Wrapping.ReflectReverse, Wrapping.ReflectReverse).searchVariant(),
181
247
  ]
182
248
  });
183
249
  Object.defineProperty(WrapAroundRule, "CONFIGS", {
@@ -1,10 +1,12 @@
1
1
  import UniversalSolver from './universal/universalSolver.js';
2
2
  import BacktrackSolver from './backtrack/backtrackSolver.js';
3
3
  import Z3Solver from './z3/z3Solver.js';
4
+ import CspuzSolver from './cspuz/cspuzSolver.js';
4
5
  const allSolvers = new Map();
5
6
  function register(prototype) {
6
7
  allSolvers.set(prototype.id, prototype);
7
8
  }
9
+ register(new CspuzSolver());
8
10
  register(new BacktrackSolver());
9
11
  register(new UniversalSolver());
10
12
  register(new Z3Solver());
@@ -2,7 +2,8 @@ import EventIteratingSolver from '../eventIteratingSolver.js';
2
2
  export default class BacktrackSolver extends EventIteratingSolver {
3
3
  private static readonly supportedInstrs;
4
4
  readonly id = "backtrack";
5
- readonly description = "Solves puzzles using backtracking with optimizations (blazingly fast). Support most rules and symbols (including underclued).";
5
+ readonly author = "ALaggyDev";
6
+ readonly description = "Solves puzzles pretty fast using backtracking with optimizations. Support most rules and symbols (including underclued).";
6
7
  protected createWorker(): Worker;
7
8
  isInstructionSupported(instructionId: string): boolean;
8
9
  }
@@ -11,9 +11,10 @@ import { instance as galaxyInstance } from '../../symbols/galaxySymbol.js';
11
11
  import { instance as letterInstance } from '../../symbols/letterSymbol.js';
12
12
  import { instance as lotusInstance } from '../../symbols/lotusSymbol.js';
13
13
  import { instance as minesweeperInstance } from '../../symbols/minesweeperSymbol.js';
14
+ import { instance as focusInstance } from '../../symbols/focusSymbol.js';
14
15
  import { instance as myopiaInstance } from '../../symbols/myopiaSymbol.js';
15
16
  import { instance as viewpointInstance } from '../../symbols/viewpointSymbol.js';
16
- import { instance as connectAllInstance } from '../z3/modules/connectAllModule.js';
17
+ import { instance as connectAllInstance } from '../../rules/connectAllRule.js';
17
18
  import EventIteratingSolver from '../eventIteratingSolver.js';
18
19
  class BacktrackSolver extends EventIteratingSolver {
19
20
  constructor() {
@@ -24,11 +25,17 @@ class BacktrackSolver extends EventIteratingSolver {
24
25
  writable: true,
25
26
  value: 'backtrack'
26
27
  });
28
+ Object.defineProperty(this, "author", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: 'ALaggyDev'
33
+ });
27
34
  Object.defineProperty(this, "description", {
28
35
  enumerable: true,
29
36
  configurable: true,
30
37
  writable: true,
31
- value: 'Solves puzzles using backtracking with optimizations (blazingly fast). Support most rules and symbols (including underclued).'
38
+ value: 'Solves puzzles pretty fast using backtracking with optimizations. Support most rules and symbols (including underclued).'
32
39
  });
33
40
  }
34
41
  createWorker() {
@@ -52,6 +59,7 @@ Object.defineProperty(BacktrackSolver, "supportedInstrs", {
52
59
  lotusInstance.id,
53
60
  myopiaInstance.id,
54
61
  minesweeperInstance.id,
62
+ focusInstance.id,
55
63
  letterInstance.id,
56
64
  undercluedInstance.id,
57
65
  connectAllInstance.id,
@@ -14,6 +14,7 @@ import { instance as galaxyInstance, } from '../../symbols/galaxySymbol.js';
14
14
  import { instance as letterInstance, } from '../../symbols/letterSymbol.js';
15
15
  import { instance as lotusInstance, } from '../../symbols/lotusSymbol.js';
16
16
  import { instance as minesweeperInstance, } from '../../symbols/minesweeperSymbol.js';
17
+ import { instance as focusInstance, } from '../../symbols/focusSymbol.js';
17
18
  import { instance as myopiaInstance, } from '../../symbols/myopiaSymbol.js';
18
19
  import { instance as viewpointInstance, } from '../../symbols/viewpointSymbol.js';
19
20
  import { instance as connectAllInstance } from '../z3/modules/connectAllModule.js';
@@ -33,6 +34,7 @@ import LotusBTModule from './symbols/lotus.js';
33
34
  import MinesweeperBTModule from './symbols/minesweeper.js';
34
35
  import MyopiaBTModule from './symbols/myopia.js';
35
36
  import ViewpointBTModule from './symbols/viewpoint.js';
37
+ import FocusBTModule from './symbols/focus.js';
36
38
  function translateToBTGridData(grid) {
37
39
  const tiles = array(grid.width, grid.height, (x, y) => {
38
40
  const tile = grid.getTile(x, y);
@@ -71,6 +73,9 @@ function translateToBTGridData(grid) {
71
73
  else if (id === minesweeperInstance.id) {
72
74
  module = new MinesweeperBTModule(symbol);
73
75
  }
76
+ else if (id === focusInstance.id) {
77
+ module = new FocusBTModule(symbol);
78
+ }
74
79
  else if (id === letterInstance.id) {
75
80
  continue;
76
81
  }
@@ -289,6 +294,12 @@ onmessage = e => {
289
294
  let count = 0;
290
295
  solve(grid, solution => {
291
296
  // if (count === 0) console.timeLog('Solve time', 'First solution');
297
+ if (solution) {
298
+ if (solution.resetTiles().colorEquals(solution)) {
299
+ postMessage(null);
300
+ return false;
301
+ }
302
+ }
292
303
  postMessage(Serializer.stringifyGrid(solution));
293
304
  count += 1;
294
305
  return count < 2;
@@ -0,0 +1,9 @@
1
+ import FocusSymbol from '../../../symbols/focusSymbol.js';
2
+ import BTModule, { BTGridData, CheckResult } from '../data.js';
3
+ export default class FocusBTModule extends BTModule {
4
+ instr: FocusSymbol;
5
+ private cachedCheckResult?;
6
+ constructor(instr: FocusSymbol);
7
+ checkGlobal(grid: BTGridData): CheckResult | false;
8
+ private buildCheckAndRating;
9
+ }