@logic-pad/core 0.10.1 → 0.11.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.
- package/assets/logic-core.global.d.ts +78 -20
- package/dist/data/grid.js +3 -1
- package/dist/data/gridConnections.d.ts +1 -0
- package/dist/data/gridConnections.js +19 -0
- package/dist/data/gridZones.d.ts +1 -0
- package/dist/data/gridZones.js +25 -0
- package/dist/data/rules/banPatternRule.js +2 -9
- package/dist/data/rules/containsShapeRule.d.ts +33 -0
- package/dist/data/rules/containsShapeRule.js +151 -0
- package/dist/data/rules/rules.gen.d.ts +1 -0
- package/dist/data/rules/rules.gen.js +1 -0
- package/dist/data/shapes.d.ts +2 -0
- package/dist/data/shapes.js +10 -0
- package/dist/data/solver/allSolvers.js +2 -0
- package/dist/data/solver/auto/autoSolver.d.ts +17 -0
- package/dist/data/solver/auto/autoSolver.js +181 -0
- package/dist/data/solver/cspuz/cspuzSolver.d.ts +1 -1
- package/dist/data/solver/cspuz/cspuzSolver.js +1 -1
- package/dist/data/solver/cspuz/cspuzWorker.js +43 -4
- package/dist/data/solver/eventIteratingSolver.d.ts +1 -0
- package/dist/data/solver/eventIteratingSolver.js +10 -0
- package/dist/data/solver/solver.d.ts +3 -1
- package/dist/data/solver/solver.js +9 -0
- package/dist/data/solver/z3/z3Solver.d.ts +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/package.json +1 -1
|
@@ -160,6 +160,11 @@ declare global {
|
|
|
160
160
|
* @returns The deduplicated array of edges.
|
|
161
161
|
*/
|
|
162
162
|
static deduplicateEdges(edges: readonly Edge[]): readonly Edge[];
|
|
163
|
+
static validateEdges(
|
|
164
|
+
connections: GridZones,
|
|
165
|
+
width: number,
|
|
166
|
+
height: number
|
|
167
|
+
): GridZones;
|
|
163
168
|
insertColumn(index: number): GridZones;
|
|
164
169
|
insertRow(index: number): GridZones;
|
|
165
170
|
removeColumn(index: number): GridZones;
|
|
@@ -206,6 +211,11 @@ declare global {
|
|
|
206
211
|
* @returns The created connections. You can apply this to a GridData object using GridData.withConnections.
|
|
207
212
|
*/
|
|
208
213
|
static create(array: string[]): GridConnections;
|
|
214
|
+
static validateEdges(
|
|
215
|
+
connections: GridConnections,
|
|
216
|
+
width: number,
|
|
217
|
+
height: number
|
|
218
|
+
): GridConnections;
|
|
209
219
|
insertColumn(index: number): GridConnections;
|
|
210
220
|
insertRow(index: number): GridConnections;
|
|
211
221
|
removeColumn(index: number): GridConnections;
|
|
@@ -1495,6 +1505,10 @@ declare global {
|
|
|
1495
1505
|
): Shape;
|
|
1496
1506
|
export declare function getShapeVariants(shape: Shape): Shape[];
|
|
1497
1507
|
export declare function normalizeShape(shape: Shape): Shape;
|
|
1508
|
+
export declare function sanitizePatternGrid(
|
|
1509
|
+
pattern: GridData,
|
|
1510
|
+
tileMapper?: (tile: TileData) => TileData
|
|
1511
|
+
): GridData;
|
|
1498
1512
|
export declare class BanPatternRule extends Rule {
|
|
1499
1513
|
private static readonly EXAMPLE_GRID;
|
|
1500
1514
|
private static readonly CONFIGS;
|
|
@@ -1583,6 +1597,46 @@ declare global {
|
|
|
1583
1597
|
copyWith({ color }: { color?: Color }): this;
|
|
1584
1598
|
withColor(color: Color): this;
|
|
1585
1599
|
}
|
|
1600
|
+
export type ShapeRegions = {
|
|
1601
|
+
regions: {
|
|
1602
|
+
positions: Position$1[];
|
|
1603
|
+
shape: Shape;
|
|
1604
|
+
count: number;
|
|
1605
|
+
}[];
|
|
1606
|
+
complete: boolean;
|
|
1607
|
+
};
|
|
1608
|
+
export declare abstract class RegionShapeRule extends Rule {
|
|
1609
|
+
readonly color: Color;
|
|
1610
|
+
/**
|
|
1611
|
+
* @param color - The color of the regions to compare.
|
|
1612
|
+
*/
|
|
1613
|
+
constructor(color: Color);
|
|
1614
|
+
protected getShapeRegions(grid: GridData): ShapeRegions;
|
|
1615
|
+
withColor(color: Color): this;
|
|
1616
|
+
}
|
|
1617
|
+
export declare class ContainsShapeRule extends RegionShapeRule {
|
|
1618
|
+
private static readonly EXAMPLE_GRID_LIGHT;
|
|
1619
|
+
private static readonly EXAMPLE_GRID_DARK;
|
|
1620
|
+
private static readonly CONFIGS;
|
|
1621
|
+
private static readonly SEARCH_VARIANTS;
|
|
1622
|
+
readonly pattern: GridData;
|
|
1623
|
+
readonly cache: Shape[];
|
|
1624
|
+
/**
|
|
1625
|
+
* **All <color> areas must contain this pattern**
|
|
1626
|
+
*
|
|
1627
|
+
* @param color - The color of the regions to compare.
|
|
1628
|
+
* @param pattern - GridData representing the required pattern. Only non-gray tiles are considered.
|
|
1629
|
+
*/
|
|
1630
|
+
constructor(color: Color, pattern: GridData);
|
|
1631
|
+
get id(): string;
|
|
1632
|
+
get explanation(): string;
|
|
1633
|
+
get configs(): readonly AnyConfig[] | null;
|
|
1634
|
+
createExampleGrid(): GridData;
|
|
1635
|
+
get searchVariants(): SearchVariant[];
|
|
1636
|
+
validateGrid(grid: GridData): RuleState;
|
|
1637
|
+
copyWith({ color, pattern }: { color?: Color; pattern?: GridData }): this;
|
|
1638
|
+
withPattern(pattern: GridData): this;
|
|
1639
|
+
}
|
|
1586
1640
|
export declare class CustomRule extends Rule {
|
|
1587
1641
|
readonly description: string;
|
|
1588
1642
|
readonly grid: GridData;
|
|
@@ -1825,23 +1879,6 @@ declare global {
|
|
|
1825
1879
|
withColor(color: Color): this;
|
|
1826
1880
|
withSize(size: number): this;
|
|
1827
1881
|
}
|
|
1828
|
-
export type ShapeRegions = {
|
|
1829
|
-
regions: {
|
|
1830
|
-
positions: Position$1[];
|
|
1831
|
-
shape: Shape;
|
|
1832
|
-
count: number;
|
|
1833
|
-
}[];
|
|
1834
|
-
complete: boolean;
|
|
1835
|
-
};
|
|
1836
|
-
export declare abstract class RegionShapeRule extends Rule {
|
|
1837
|
-
readonly color: Color;
|
|
1838
|
-
/**
|
|
1839
|
-
* @param color - The color of the regions to compare.
|
|
1840
|
-
*/
|
|
1841
|
-
constructor(color: Color);
|
|
1842
|
-
protected getShapeRegions(grid: GridData): ShapeRegions;
|
|
1843
|
-
withColor(color: Color): this;
|
|
1844
|
-
}
|
|
1845
1882
|
export declare class SameShapeRule extends RegionShapeRule {
|
|
1846
1883
|
private static readonly CONFIGS;
|
|
1847
1884
|
private static readonly EXAMPLE_GRID_LIGHT;
|
|
@@ -2087,7 +2124,8 @@ declare global {
|
|
|
2087
2124
|
*
|
|
2088
2125
|
* @returns A promise that resolves to `true` if the environment is supported, or `false` otherwise.
|
|
2089
2126
|
*/
|
|
2090
|
-
isEnvironmentSupported(): Promise<boolean>;
|
|
2127
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
2128
|
+
readonly environmentCheck: CachedAccess<Promise<boolean>>;
|
|
2091
2129
|
/**
|
|
2092
2130
|
* Check if the solver supports the given instruction. This is used to render a small indication in the UI for each
|
|
2093
2131
|
* instruction in the editor.
|
|
@@ -2108,9 +2146,29 @@ declare global {
|
|
|
2108
2146
|
isGridSupported(grid: GridData): boolean;
|
|
2109
2147
|
}
|
|
2110
2148
|
export declare const allSolvers: Map<string, Solver>;
|
|
2149
|
+
export declare class AutoSolver extends Solver {
|
|
2150
|
+
readonly id = 'auto';
|
|
2151
|
+
readonly author = 'various contributors';
|
|
2152
|
+
readonly description =
|
|
2153
|
+
'Automatically select the fastest solver based on supported instructions and environment.';
|
|
2154
|
+
readonly supportsCancellation = true;
|
|
2155
|
+
private static readonly nonAdditiveInstructions;
|
|
2156
|
+
isGridSupported(grid: GridData): boolean;
|
|
2157
|
+
isInstructionSupported(instructionId: string): boolean;
|
|
2158
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
2159
|
+
private fillSolution;
|
|
2160
|
+
private fixGrid;
|
|
2161
|
+
private solveWithProgress;
|
|
2162
|
+
private solveOne;
|
|
2163
|
+
solve(
|
|
2164
|
+
grid: GridData,
|
|
2165
|
+
abortSignal?: AbortSignal | undefined
|
|
2166
|
+
): AsyncGenerator<GridData | null>;
|
|
2167
|
+
}
|
|
2111
2168
|
export declare abstract class EventIteratingSolver extends Solver {
|
|
2112
2169
|
readonly supportsCancellation = true;
|
|
2113
2170
|
protected abstract createWorker(): Worker;
|
|
2171
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
2114
2172
|
solve(
|
|
2115
2173
|
grid: GridData,
|
|
2116
2174
|
abortSignal?: AbortSignal
|
|
@@ -2635,7 +2693,7 @@ declare global {
|
|
|
2635
2693
|
readonly id = 'cspuz';
|
|
2636
2694
|
readonly author = 'semiexp';
|
|
2637
2695
|
readonly description =
|
|
2638
|
-
'A blazingly fast WebAssembly solver that supports most rules and symbols (including underclued).
|
|
2696
|
+
'A blazingly fast WebAssembly solver that supports most rules and symbols (including underclued).';
|
|
2639
2697
|
protected createWorker(): Worker;
|
|
2640
2698
|
isGridSupported(grid: GridData): boolean;
|
|
2641
2699
|
isInstructionSupported(instructionId: string): boolean;
|
|
@@ -2739,7 +2797,7 @@ declare global {
|
|
|
2739
2797
|
readonly description =
|
|
2740
2798
|
'(Obsolete) A WebAssembly solver that supports a limited set of rules and symbols.';
|
|
2741
2799
|
readonly supportsCancellation = false;
|
|
2742
|
-
isEnvironmentSupported(): Promise<boolean>;
|
|
2800
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
2743
2801
|
solve(grid: GridData): AsyncGenerator<GridData | null>;
|
|
2744
2802
|
isInstructionSupported(instructionId: string): boolean;
|
|
2745
2803
|
isGridSupported(grid: GridData): boolean;
|
package/dist/data/grid.js
CHANGED
|
@@ -109,7 +109,9 @@ export default class GridData {
|
|
|
109
109
|
: new Map();
|
|
110
110
|
// do not deduplicate all rules because it makes for bad editor experience
|
|
111
111
|
const newRules = rules ? GridData.deduplicateSingletonRules(rules) : [];
|
|
112
|
-
const newGrid = new GridData(arrayOrWidth, height, tiles, connections
|
|
112
|
+
const newGrid = new GridData(arrayOrWidth, height, tiles, connections
|
|
113
|
+
? GridConnections.validateEdges(connections, arrayOrWidth, height)
|
|
114
|
+
: connections, zones ? GridZones.validateEdges(zones, arrayOrWidth, height) : zones, newSymbols, newRules);
|
|
113
115
|
newSymbols.forEach(list => {
|
|
114
116
|
list.forEach((sym, i) => {
|
|
115
117
|
if (handlesGridChange(sym)) {
|
|
@@ -17,6 +17,7 @@ export default class GridConnections extends GridZones {
|
|
|
17
17
|
* @returns The created connections. You can apply this to a GridData object using GridData.withConnections.
|
|
18
18
|
*/
|
|
19
19
|
static create(array: string[]): GridConnections;
|
|
20
|
+
static validateEdges(connections: GridConnections, width: number, height: number): GridConnections;
|
|
20
21
|
insertColumn(index: number): GridConnections;
|
|
21
22
|
insertRow(index: number): GridConnections;
|
|
22
23
|
removeColumn(index: number): GridConnections;
|
|
@@ -111,6 +111,25 @@ export default class GridConnections extends GridZones {
|
|
|
111
111
|
}
|
|
112
112
|
return new GridConnections(edges);
|
|
113
113
|
}
|
|
114
|
+
static validateEdges(connections, width, height) {
|
|
115
|
+
const newEdges = [];
|
|
116
|
+
for (const edge of connections.edges) {
|
|
117
|
+
if (edge.x1 < 0 || edge.x1 >= width || edge.y1 < 0 || edge.y1 >= height) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (edge.x2 < 0 || edge.x2 >= width || edge.y2 < 0 || edge.y2 >= height) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (Math.abs(edge.x1 - edge.x2) + Math.abs(edge.y1 - edge.y2) !== 1) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
newEdges.push(edge);
|
|
127
|
+
}
|
|
128
|
+
if (newEdges.length === connections.edges.length) {
|
|
129
|
+
return connections;
|
|
130
|
+
}
|
|
131
|
+
return new GridConnections(newEdges);
|
|
132
|
+
}
|
|
114
133
|
insertColumn(index) {
|
|
115
134
|
return new GridConnections(this.edges.flatMap(edge => {
|
|
116
135
|
if ((edge.x1 < index && edge.x2 < index) ||
|
package/dist/data/gridZones.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export default class GridZones {
|
|
|
18
18
|
* @returns The deduplicated array of edges.
|
|
19
19
|
*/
|
|
20
20
|
static deduplicateEdges(edges: readonly Edge[]): readonly Edge[];
|
|
21
|
+
static validateEdges(connections: GridZones, width: number, height: number): GridZones;
|
|
21
22
|
insertColumn(index: number): GridZones;
|
|
22
23
|
insertRow(index: number): GridZones;
|
|
23
24
|
removeColumn(index: number): GridZones;
|
package/dist/data/gridZones.js
CHANGED
|
@@ -48,6 +48,31 @@ export default class GridZones {
|
|
|
48
48
|
static deduplicateEdges(edges) {
|
|
49
49
|
return edges.filter((edge, index) => edges.findIndex(e => isSameEdge(e, edge)) === index);
|
|
50
50
|
}
|
|
51
|
+
static validateEdges(connections, width, height) {
|
|
52
|
+
const newEdges = [];
|
|
53
|
+
for (const edge of connections.edges) {
|
|
54
|
+
if (edge.x1 < -1 ||
|
|
55
|
+
edge.x1 >= width + 1 ||
|
|
56
|
+
edge.y1 < -1 ||
|
|
57
|
+
edge.y1 >= height + 1) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (edge.x2 < -1 ||
|
|
61
|
+
edge.x2 >= width + 1 ||
|
|
62
|
+
edge.y2 < -1 ||
|
|
63
|
+
edge.y2 >= height + 1) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (Math.abs(edge.x1 - edge.x2) + Math.abs(edge.y1 - edge.y2) !== 1) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
newEdges.push(edge);
|
|
70
|
+
}
|
|
71
|
+
if (newEdges.length === connections.edges.length) {
|
|
72
|
+
return connections;
|
|
73
|
+
}
|
|
74
|
+
return new GridZones(newEdges);
|
|
75
|
+
}
|
|
51
76
|
insertColumn(index) {
|
|
52
77
|
return new GridZones(this.edges.map(edge => {
|
|
53
78
|
if (edge.x1 < index || edge.x2 < index) {
|
|
@@ -2,7 +2,7 @@ import { ConfigType } from '../config.js';
|
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
3
|
import { array } from '../dataHelper.js';
|
|
4
4
|
import { Color, State } from '../primitives.js';
|
|
5
|
-
import { getShapeVariants, tilesToShape } from '../shapes.js';
|
|
5
|
+
import { getShapeVariants, sanitizePatternGrid, tilesToShape, } from '../shapes.js';
|
|
6
6
|
import Rule from './rule.js';
|
|
7
7
|
class BanPatternRule extends Rule {
|
|
8
8
|
/**
|
|
@@ -24,14 +24,7 @@ class BanPatternRule extends Rule {
|
|
|
24
24
|
writable: true,
|
|
25
25
|
value: void 0
|
|
26
26
|
});
|
|
27
|
-
this.pattern = pattern
|
|
28
|
-
// unlock all tiles
|
|
29
|
-
.withTiles(tiles => tiles.map(row => row.map(t => t.exists
|
|
30
|
-
? t.withFixed(false)
|
|
31
|
-
: t.copyWith({ exists: true, color: Color.Gray, fixed: false }))))
|
|
32
|
-
// strip all symbols and rules
|
|
33
|
-
.withRules([])
|
|
34
|
-
.withSymbols(new Map());
|
|
27
|
+
this.pattern = sanitizePatternGrid(pattern);
|
|
35
28
|
this.cache = getShapeVariants(tilesToShape(this.pattern.tiles));
|
|
36
29
|
}
|
|
37
30
|
get id() {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AnyConfig } from '../config.js';
|
|
2
|
+
import GridData from '../grid.js';
|
|
3
|
+
import { Color, RuleState } from '../primitives.js';
|
|
4
|
+
import { Shape } from '../shapes.js';
|
|
5
|
+
import RegionShapeRule from './regionShapeRule.js';
|
|
6
|
+
import { SearchVariant } from './rule.js';
|
|
7
|
+
export default class ContainsShapeRule extends RegionShapeRule {
|
|
8
|
+
private static readonly EXAMPLE_GRID_LIGHT;
|
|
9
|
+
private static readonly EXAMPLE_GRID_DARK;
|
|
10
|
+
private static readonly CONFIGS;
|
|
11
|
+
private static readonly SEARCH_VARIANTS;
|
|
12
|
+
readonly pattern: GridData;
|
|
13
|
+
readonly cache: Shape[];
|
|
14
|
+
/**
|
|
15
|
+
* **All <color> areas must contain this pattern**
|
|
16
|
+
*
|
|
17
|
+
* @param color - The color of the regions to compare.
|
|
18
|
+
* @param pattern - GridData representing the required pattern. Only non-gray tiles are considered.
|
|
19
|
+
*/
|
|
20
|
+
constructor(color: Color, pattern: GridData);
|
|
21
|
+
get id(): string;
|
|
22
|
+
get explanation(): string;
|
|
23
|
+
get configs(): readonly AnyConfig[] | null;
|
|
24
|
+
createExampleGrid(): GridData;
|
|
25
|
+
get searchVariants(): SearchVariant[];
|
|
26
|
+
validateGrid(grid: GridData): RuleState;
|
|
27
|
+
copyWith({ color, pattern, }: {
|
|
28
|
+
color?: Color;
|
|
29
|
+
pattern?: GridData;
|
|
30
|
+
}): this;
|
|
31
|
+
withPattern(pattern: GridData): this;
|
|
32
|
+
}
|
|
33
|
+
export declare const instance: ContainsShapeRule;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { ConfigType } from '../config.js';
|
|
2
|
+
import { array } from '../dataHelper.js';
|
|
3
|
+
import GridData from '../grid.js';
|
|
4
|
+
import { Color, State } from '../primitives.js';
|
|
5
|
+
import { getShapeVariants, sanitizePatternGrid, tilesToShape, } from '../shapes.js';
|
|
6
|
+
import RegionShapeRule from './regionShapeRule.js';
|
|
7
|
+
class ContainsShapeRule extends RegionShapeRule {
|
|
8
|
+
/**
|
|
9
|
+
* **All <color> areas must contain this pattern**
|
|
10
|
+
*
|
|
11
|
+
* @param color - The color of the regions to compare.
|
|
12
|
+
* @param pattern - GridData representing the required pattern. Only non-gray tiles are considered.
|
|
13
|
+
*/
|
|
14
|
+
constructor(color, pattern) {
|
|
15
|
+
super(color);
|
|
16
|
+
Object.defineProperty(this, "pattern", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: void 0
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(this, "cache", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: void 0
|
|
27
|
+
});
|
|
28
|
+
this.pattern = sanitizePatternGrid(pattern, t => t.color === color ? t : t.withColor(Color.Gray));
|
|
29
|
+
this.cache = getShapeVariants(tilesToShape(this.pattern.tiles));
|
|
30
|
+
}
|
|
31
|
+
get id() {
|
|
32
|
+
return `contains_shape`;
|
|
33
|
+
}
|
|
34
|
+
get explanation() {
|
|
35
|
+
return `All ${this.color} areas must contain this pattern`;
|
|
36
|
+
}
|
|
37
|
+
get configs() {
|
|
38
|
+
return ContainsShapeRule.CONFIGS;
|
|
39
|
+
}
|
|
40
|
+
createExampleGrid() {
|
|
41
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
42
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
43
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
44
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
45
|
+
this.pattern.forEach((tile, x, y) => {
|
|
46
|
+
if (tile.color !== Color.Gray && tile.exists) {
|
|
47
|
+
minX = Math.min(minX, x);
|
|
48
|
+
minY = Math.min(minY, y);
|
|
49
|
+
maxX = Math.max(maxX, x);
|
|
50
|
+
maxY = Math.max(maxY, y);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const width = maxX - minX + 1;
|
|
54
|
+
const height = maxY - minY + 1;
|
|
55
|
+
const tiles = array(width, height, (x, y) => {
|
|
56
|
+
const tile = this.pattern.getTile(x + minX, y + minY);
|
|
57
|
+
if (!tile.exists || tile.color !== Color.Gray)
|
|
58
|
+
return tile;
|
|
59
|
+
return tile.withExists(false);
|
|
60
|
+
});
|
|
61
|
+
return GridData.create(width, height, tiles);
|
|
62
|
+
}
|
|
63
|
+
get searchVariants() {
|
|
64
|
+
return ContainsShapeRule.SEARCH_VARIANTS;
|
|
65
|
+
}
|
|
66
|
+
validateGrid(grid) {
|
|
67
|
+
const { regions, complete } = this.getShapeRegions(grid);
|
|
68
|
+
const errorRegion = regions.find(r => {
|
|
69
|
+
for (const pattern of this.cache) {
|
|
70
|
+
if (r.shape.elements.length < pattern.elements.length)
|
|
71
|
+
continue;
|
|
72
|
+
for (let y = 0; y <= r.shape.height - pattern.height; y++) {
|
|
73
|
+
for (let x = 0; x <= r.shape.width - pattern.width; x++) {
|
|
74
|
+
let match = true;
|
|
75
|
+
for (const element of pattern.elements) {
|
|
76
|
+
const tile = r.shape.elements.find(e => e.x === x + element.x && e.y === y + element.y);
|
|
77
|
+
if (!tile || tile.color !== element.color) {
|
|
78
|
+
match = false;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (match)
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
});
|
|
89
|
+
if (errorRegion) {
|
|
90
|
+
return {
|
|
91
|
+
state: State.Error,
|
|
92
|
+
positions: errorRegion.positions,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return { state: complete ? State.Satisfied : State.Incomplete };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
copyWith({ color, pattern, }) {
|
|
100
|
+
return new ContainsShapeRule(color ?? this.color, pattern ?? this.pattern);
|
|
101
|
+
}
|
|
102
|
+
withPattern(pattern) {
|
|
103
|
+
return this.copyWith({ pattern });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
Object.defineProperty(ContainsShapeRule, "EXAMPLE_GRID_LIGHT", {
|
|
107
|
+
enumerable: true,
|
|
108
|
+
configurable: true,
|
|
109
|
+
writable: true,
|
|
110
|
+
value: Object.freeze(GridData.create(['nnnnn', 'nnnnn', 'wwwwn', 'nnnnn', 'nnnnn']))
|
|
111
|
+
});
|
|
112
|
+
Object.defineProperty(ContainsShapeRule, "EXAMPLE_GRID_DARK", {
|
|
113
|
+
enumerable: true,
|
|
114
|
+
configurable: true,
|
|
115
|
+
writable: true,
|
|
116
|
+
value: Object.freeze(GridData.create(['nnnnn', 'nnnnn', 'bbbbn', 'nnnnn', 'nnnnn']))
|
|
117
|
+
});
|
|
118
|
+
Object.defineProperty(ContainsShapeRule, "CONFIGS", {
|
|
119
|
+
enumerable: true,
|
|
120
|
+
configurable: true,
|
|
121
|
+
writable: true,
|
|
122
|
+
value: Object.freeze([
|
|
123
|
+
{
|
|
124
|
+
type: ConfigType.Color,
|
|
125
|
+
default: Color.Light,
|
|
126
|
+
allowGray: false,
|
|
127
|
+
field: 'color',
|
|
128
|
+
description: 'Color',
|
|
129
|
+
configurable: true,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
type: ConfigType.Tile,
|
|
133
|
+
default: ContainsShapeRule.EXAMPLE_GRID_LIGHT,
|
|
134
|
+
resizable: true,
|
|
135
|
+
field: 'pattern',
|
|
136
|
+
description: 'Pattern',
|
|
137
|
+
configurable: true,
|
|
138
|
+
},
|
|
139
|
+
])
|
|
140
|
+
});
|
|
141
|
+
Object.defineProperty(ContainsShapeRule, "SEARCH_VARIANTS", {
|
|
142
|
+
enumerable: true,
|
|
143
|
+
configurable: true,
|
|
144
|
+
writable: true,
|
|
145
|
+
value: [
|
|
146
|
+
new ContainsShapeRule(Color.Light, ContainsShapeRule.EXAMPLE_GRID_LIGHT).searchVariant(),
|
|
147
|
+
new ContainsShapeRule(Color.Dark, ContainsShapeRule.EXAMPLE_GRID_DARK).searchVariant(),
|
|
148
|
+
]
|
|
149
|
+
});
|
|
150
|
+
export default ContainsShapeRule;
|
|
151
|
+
export const instance = new ContainsShapeRule(Color.Dark, GridData.create([]));
|
|
@@ -3,6 +3,7 @@ export { instance as CellCountPerZoneRule } from './cellCountPerZoneRule.js';
|
|
|
3
3
|
export { instance as CellCountRule } from './cellCountRule.js';
|
|
4
4
|
export { instance as CompletePatternRule } from './completePatternRule.js';
|
|
5
5
|
export { instance as ConnectAllRule } from './connectAllRule.js';
|
|
6
|
+
export { instance as ContainsShapeRule } from './containsShapeRule.js';
|
|
6
7
|
export { instance as CustomRule } from './customRule.js';
|
|
7
8
|
export { instance as ForesightRule } from './foresightRule.js';
|
|
8
9
|
export { instance as LyingSymbolRule } from './lyingSymbolRule.js';
|
|
@@ -7,6 +7,7 @@ export { instance as CellCountPerZoneRule } from './cellCountPerZoneRule.js';
|
|
|
7
7
|
export { instance as CellCountRule } from './cellCountRule.js';
|
|
8
8
|
export { instance as CompletePatternRule } from './completePatternRule.js';
|
|
9
9
|
export { instance as ConnectAllRule } from './connectAllRule.js';
|
|
10
|
+
export { instance as ContainsShapeRule } from './containsShapeRule.js';
|
|
10
11
|
export { instance as CustomRule } from './customRule.js';
|
|
11
12
|
export { instance as ForesightRule } from './foresightRule.js';
|
|
12
13
|
export { instance as LyingSymbolRule } from './lyingSymbolRule.js';
|
package/dist/data/shapes.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import GridData from './grid.js';
|
|
1
2
|
import { Color, Position } from './primitives.js';
|
|
2
3
|
import TileData from './tile.js';
|
|
3
4
|
export interface ShapeElement {
|
|
@@ -15,3 +16,4 @@ export declare function tilesToShape(tiles: readonly (readonly TileData[])[]): S
|
|
|
15
16
|
export declare function positionsToShape(positions: Position[], color: Color): Shape;
|
|
16
17
|
export declare function getShapeVariants(shape: Shape): Shape[];
|
|
17
18
|
export declare function normalizeShape(shape: Shape): Shape;
|
|
19
|
+
export declare function sanitizePatternGrid(pattern: GridData, tileMapper?: (tile: TileData) => TileData): GridData;
|
package/dist/data/shapes.js
CHANGED
|
@@ -115,3 +115,13 @@ export function normalizeShape(shape) {
|
|
|
115
115
|
const variants = getShapeVariants(shape);
|
|
116
116
|
return variants.reduce((min, variant) => (compareShape(variant, min) < 0 ? variant : min), variants[0]);
|
|
117
117
|
}
|
|
118
|
+
export function sanitizePatternGrid(pattern, tileMapper = t => t) {
|
|
119
|
+
return (pattern
|
|
120
|
+
// unlock all tiles
|
|
121
|
+
.withTiles(tiles => tiles.map(row => row.map(t => tileMapper(t.exists
|
|
122
|
+
? t.withFixed(false)
|
|
123
|
+
: t.copyWith({ exists: true, color: Color.Gray, fixed: false })))))
|
|
124
|
+
// strip all symbols and rules
|
|
125
|
+
.withRules([])
|
|
126
|
+
.withSymbols(new Map()));
|
|
127
|
+
}
|
|
@@ -2,10 +2,12 @@ import UniversalSolver from './universal/universalSolver.js';
|
|
|
2
2
|
import BacktrackSolver from './backtrack/backtrackSolver.js';
|
|
3
3
|
import Z3Solver from './z3/z3Solver.js';
|
|
4
4
|
import CspuzSolver from './cspuz/cspuzSolver.js';
|
|
5
|
+
import AutoSolver from './auto/autoSolver.js';
|
|
5
6
|
const allSolvers = new Map();
|
|
6
7
|
function register(prototype) {
|
|
7
8
|
allSolvers.set(prototype.id, prototype);
|
|
8
9
|
}
|
|
10
|
+
register(new AutoSolver());
|
|
9
11
|
register(new CspuzSolver());
|
|
10
12
|
register(new BacktrackSolver());
|
|
11
13
|
register(new UniversalSolver());
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import GridData from '../../grid.js';
|
|
2
|
+
import Solver from '../solver.js';
|
|
3
|
+
export default class AutoSolver extends Solver {
|
|
4
|
+
readonly id = "auto";
|
|
5
|
+
readonly author = "various contributors";
|
|
6
|
+
readonly description = "Automatically select the fastest solver based on supported instructions and environment.";
|
|
7
|
+
readonly supportsCancellation = true;
|
|
8
|
+
private static readonly nonAdditiveInstructions;
|
|
9
|
+
isGridSupported(grid: GridData): boolean;
|
|
10
|
+
isInstructionSupported(instructionId: string): boolean;
|
|
11
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
12
|
+
private fillSolution;
|
|
13
|
+
private fixGrid;
|
|
14
|
+
private solveWithProgress;
|
|
15
|
+
private solveOne;
|
|
16
|
+
solve(grid: GridData, abortSignal?: AbortSignal | undefined): AsyncGenerator<GridData | null>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Color, State } from '../../primitives.js';
|
|
2
|
+
import { instance as lyingSymbolInstance } from '../../rules/lyingSymbolRule.js';
|
|
3
|
+
import { instance as offByXInstance } from '../../rules/offByXRule.js';
|
|
4
|
+
import { instance as lotusInstance } from '../../symbols/lotusSymbol.js';
|
|
5
|
+
import { instance as galaxyInstance } from '../../symbols/galaxySymbol.js';
|
|
6
|
+
import { allSolvers } from '../allSolvers.js';
|
|
7
|
+
import Solver from '../solver.js';
|
|
8
|
+
import UndercluedRule from '../../rules/undercluedRule.js';
|
|
9
|
+
import validateGrid from '../../validate.js';
|
|
10
|
+
class AutoSolver extends Solver {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
Object.defineProperty(this, "id", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
value: 'auto'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(this, "author", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: 'various contributors'
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(this, "description", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
value: 'Automatically select the fastest solver based on supported instructions and environment.'
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(this, "supportsCancellation", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: true
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
isGridSupported(grid) {
|
|
39
|
+
for (const solver of allSolvers.values()) {
|
|
40
|
+
if (solver.id === this.id)
|
|
41
|
+
continue;
|
|
42
|
+
if (solver.isGridSupported(grid)) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
isInstructionSupported(instructionId) {
|
|
49
|
+
for (const solver of allSolvers.values()) {
|
|
50
|
+
if (solver.id === this.id)
|
|
51
|
+
continue;
|
|
52
|
+
if (solver.isInstructionSupported(instructionId)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
async isEnvironmentSupported() {
|
|
59
|
+
for (const solver of allSolvers.values()) {
|
|
60
|
+
if (solver.id === this.id)
|
|
61
|
+
continue;
|
|
62
|
+
if (await solver.environmentCheck.value) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
fillSolution(grid, solution) {
|
|
69
|
+
return grid.withTiles(tiles => {
|
|
70
|
+
return tiles.map((row, y) => row.map((tile, x) => {
|
|
71
|
+
if (!tile.exists || tile.fixed)
|
|
72
|
+
return tile;
|
|
73
|
+
const solutionTile = solution.tiles[y][x];
|
|
74
|
+
return tile.withColor(solutionTile.color);
|
|
75
|
+
}));
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
fixGrid(grid) {
|
|
79
|
+
return grid.withTiles(tiles => {
|
|
80
|
+
return tiles.map(row => row.map(tile => {
|
|
81
|
+
if (tile.fixed)
|
|
82
|
+
return tile;
|
|
83
|
+
return tile.withFixed(tile.color !== Color.Gray);
|
|
84
|
+
}));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async *solveWithProgress(solver, grid, progress, abortSignal) {
|
|
88
|
+
for await (const updatedGrid of solver.solve(progress, abortSignal)) {
|
|
89
|
+
if (abortSignal?.aborted)
|
|
90
|
+
return;
|
|
91
|
+
if (!updatedGrid)
|
|
92
|
+
return updatedGrid;
|
|
93
|
+
yield this.fillSolution(grid, updatedGrid);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async solveOne(generator) {
|
|
97
|
+
// eslint-disable-next-line no-unreachable-loop
|
|
98
|
+
for await (const grid of generator) {
|
|
99
|
+
return grid;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
async *solve(grid, abortSignal) {
|
|
104
|
+
if (!!grid.findRule(r => AutoSolver.nonAdditiveInstructions.has(r.id)) ||
|
|
105
|
+
!!grid.findSymbol(s => AutoSolver.nonAdditiveInstructions.has(s.id))) {
|
|
106
|
+
for (const solver of allSolvers.values()) {
|
|
107
|
+
if (solver.id === this.id)
|
|
108
|
+
continue;
|
|
109
|
+
if (solver.isGridSupported(grid)) {
|
|
110
|
+
yield* solver.solve(grid, abortSignal);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
throw new Error('No solver supports the given grid');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
let progressGrid = grid;
|
|
118
|
+
for (const solver of allSolvers.values()) {
|
|
119
|
+
if (solver.id === this.id)
|
|
120
|
+
continue;
|
|
121
|
+
if (solver.isGridSupported(progressGrid)) {
|
|
122
|
+
yield* this.solveWithProgress(solver, grid, progressGrid, abortSignal);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
else if (solver.isGridSupported(grid)) {
|
|
126
|
+
yield* solver.solve(grid, abortSignal);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
let undercluedGrid = progressGrid
|
|
131
|
+
.withRules(rules => rules.filter(r => solver.isInstructionSupported(r.id)))
|
|
132
|
+
.withSymbols(symbols => {
|
|
133
|
+
for (const id of symbols.keys()) {
|
|
134
|
+
if (!solver.isInstructionSupported(id))
|
|
135
|
+
symbols.delete(id);
|
|
136
|
+
}
|
|
137
|
+
return symbols;
|
|
138
|
+
})
|
|
139
|
+
.addRule(new UndercluedRule());
|
|
140
|
+
if (!solver.isGridSupported(undercluedGrid)) {
|
|
141
|
+
// special case for solvers that support lotus and galaxy symbols but not dual-color placement
|
|
142
|
+
undercluedGrid = undercluedGrid.withSymbols(symbols => {
|
|
143
|
+
symbols.delete(lotusInstance.id);
|
|
144
|
+
symbols.delete(galaxyInstance.id);
|
|
145
|
+
return symbols;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (!solver.isGridSupported(undercluedGrid))
|
|
149
|
+
continue;
|
|
150
|
+
const undercluedSolution = await this.solveOne(this.solveWithProgress(solver, progressGrid, undercluedGrid, abortSignal));
|
|
151
|
+
if (undercluedSolution === null)
|
|
152
|
+
continue;
|
|
153
|
+
if (undercluedSolution.getTileCount(true, false, Color.Gray) === 0) {
|
|
154
|
+
const result = this.fillSolution(grid, undercluedSolution);
|
|
155
|
+
if (validateGrid(result, null).final !== State.Error) {
|
|
156
|
+
yield result;
|
|
157
|
+
yield null;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
yield null;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
progressGrid = this.fixGrid(undercluedSolution);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
yield this.fillSolution(grid, progressGrid);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
Object.defineProperty(AutoSolver, "nonAdditiveInstructions", {
|
|
173
|
+
enumerable: true,
|
|
174
|
+
configurable: true,
|
|
175
|
+
writable: true,
|
|
176
|
+
value: new Set([
|
|
177
|
+
offByXInstance.id,
|
|
178
|
+
lyingSymbolInstance.id,
|
|
179
|
+
])
|
|
180
|
+
});
|
|
181
|
+
export default AutoSolver;
|
|
@@ -4,7 +4,7 @@ export default class CspuzSolver extends EventIteratingSolver {
|
|
|
4
4
|
private static readonly supportedInstrs;
|
|
5
5
|
readonly id = "cspuz";
|
|
6
6
|
readonly author = "semiexp";
|
|
7
|
-
readonly description = "A blazingly fast WebAssembly solver that supports most rules and symbols (including underclued).
|
|
7
|
+
readonly description = "A blazingly fast WebAssembly solver that supports most rules and symbols (including underclued).";
|
|
8
8
|
protected createWorker(): Worker;
|
|
9
9
|
isGridSupported(grid: GridData): boolean;
|
|
10
10
|
isInstructionSupported(instructionId: string): boolean;
|
|
@@ -36,7 +36,7 @@ class CspuzSolver extends EventIteratingSolver {
|
|
|
36
36
|
enumerable: true,
|
|
37
37
|
configurable: true,
|
|
38
38
|
writable: true,
|
|
39
|
-
value: 'A blazingly fast WebAssembly solver that supports most rules and symbols (including underclued).
|
|
39
|
+
value: 'A blazingly fast WebAssembly solver that supports most rules and symbols (including underclued).'
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
createWorker() {
|
|
@@ -14,10 +14,7 @@ function stringToColor(str) {
|
|
|
14
14
|
return Color.Gray;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
const grid = Serializer.parseGrid(e.data);
|
|
19
|
-
const puzzleData = gridToJson(grid);
|
|
20
|
-
const solverResult = solveLogicPad(puzzleData, !!grid.findRule(r => r.id === undercluedInstance.id));
|
|
17
|
+
function postSolution(grid, solverResult) {
|
|
21
18
|
if (solverResult === null) {
|
|
22
19
|
postMessage(null);
|
|
23
20
|
}
|
|
@@ -40,5 +37,47 @@ onmessage = e => {
|
|
|
40
37
|
postMessage(Serializer.stringifyGrid(solution));
|
|
41
38
|
}
|
|
42
39
|
}
|
|
40
|
+
}
|
|
41
|
+
onmessage = e => {
|
|
42
|
+
const grid = Serializer.parseGrid(e.data);
|
|
43
|
+
const isUnderclued = !!grid.findRule(r => r.id === undercluedInstance.id);
|
|
44
|
+
const puzzleData = gridToJson(grid);
|
|
45
|
+
const solverResult = solveLogicPad(puzzleData, isUnderclued);
|
|
46
|
+
postSolution(grid, solverResult);
|
|
47
|
+
// Make use of the underclued mode to determine solution uniqueness
|
|
48
|
+
if (solverResult !== null && !('error' in solverResult) && !isUnderclued) {
|
|
49
|
+
const undercluedResult = solveLogicPad(puzzleData, true);
|
|
50
|
+
if (undercluedResult === null) {
|
|
51
|
+
postMessage(undefined); // Shouldn't happen because underclued grids should always be solvable
|
|
52
|
+
}
|
|
53
|
+
else if ('error' in undercluedResult) {
|
|
54
|
+
throw new Error(undercluedResult.error);
|
|
55
|
+
}
|
|
56
|
+
else if (undercluedResult.every((row, y) => row.every((cell, x) => cell !== null || !grid.getTile(x, y).exists))) {
|
|
57
|
+
postMessage(null);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
let tweaked = false;
|
|
61
|
+
for (const [y, row] of undercluedResult.entries()) {
|
|
62
|
+
for (const [x, color] of row.entries()) {
|
|
63
|
+
if (color !== null) {
|
|
64
|
+
puzzleData.tiles[y][x].fixed = true;
|
|
65
|
+
puzzleData.tiles[y][x].color = color;
|
|
66
|
+
}
|
|
67
|
+
else if (!tweaked) {
|
|
68
|
+
const positions = grid.connections.getConnectedTiles({ x, y });
|
|
69
|
+
const newColor = solverResult[y][x] === 'dark' ? 'light' : 'dark';
|
|
70
|
+
positions.forEach(({ x: px, y: py }) => {
|
|
71
|
+
puzzleData.tiles[py][px].fixed = true;
|
|
72
|
+
puzzleData.tiles[py][px].color = newColor;
|
|
73
|
+
});
|
|
74
|
+
tweaked = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const secondResult = solveLogicPad(puzzleData, false);
|
|
79
|
+
postSolution(grid, secondResult);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
43
82
|
postMessage(undefined);
|
|
44
83
|
};
|
|
@@ -3,5 +3,6 @@ import Solver from './solver.js';
|
|
|
3
3
|
export default abstract class EventIteratingSolver extends Solver {
|
|
4
4
|
readonly supportsCancellation = true;
|
|
5
5
|
protected abstract createWorker(): Worker;
|
|
6
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
6
7
|
solve(grid: GridData, abortSignal?: AbortSignal): AsyncGenerator<GridData | null>;
|
|
7
8
|
}
|
|
@@ -11,6 +11,16 @@ export default class EventIteratingSolver extends Solver {
|
|
|
11
11
|
value: true
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
|
+
isEnvironmentSupported() {
|
|
15
|
+
try {
|
|
16
|
+
const worker = this.createWorker();
|
|
17
|
+
worker.terminate();
|
|
18
|
+
return Promise.resolve(true);
|
|
19
|
+
}
|
|
20
|
+
catch (ex) {
|
|
21
|
+
return Promise.resolve(false);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
14
24
|
async *solve(grid, abortSignal) {
|
|
15
25
|
const worker = this.createWorker();
|
|
16
26
|
const terminateHandler = () => worker.terminate();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CachedAccess } from '../dataHelper.js';
|
|
1
2
|
import GridData from '../grid.js';
|
|
2
3
|
/**
|
|
3
4
|
* Base class that all solvers must extend.
|
|
@@ -49,7 +50,8 @@ export default abstract class Solver {
|
|
|
49
50
|
*
|
|
50
51
|
* @returns A promise that resolves to `true` if the environment is supported, or `false` otherwise.
|
|
51
52
|
*/
|
|
52
|
-
isEnvironmentSupported(): Promise<boolean>;
|
|
53
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
54
|
+
readonly environmentCheck: CachedAccess<Promise<boolean>>;
|
|
53
55
|
/**
|
|
54
56
|
* Check if the solver supports the given instruction. This is used to render a small indication in the UI for each
|
|
55
57
|
* instruction in the editor.
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import { CachedAccess } from '../dataHelper.js';
|
|
1
2
|
import { allRules } from '../rules/index.js';
|
|
2
3
|
import { allSymbols } from '../symbols/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* Base class that all solvers must extend.
|
|
5
6
|
*/
|
|
6
7
|
export default class Solver {
|
|
8
|
+
constructor() {
|
|
9
|
+
Object.defineProperty(this, "environmentCheck", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
writable: true,
|
|
13
|
+
value: CachedAccess.of(() => this.isEnvironmentSupported())
|
|
14
|
+
});
|
|
15
|
+
}
|
|
7
16
|
/**
|
|
8
17
|
* Check if the solver supports the current browser environment. This method is called once when the user first clicks
|
|
9
18
|
* the "Solve" button, and the result is cached for the duration of the editor session.
|
|
@@ -5,7 +5,7 @@ export default class Z3Solver extends Solver {
|
|
|
5
5
|
readonly author = "Lysine";
|
|
6
6
|
readonly description = "(Obsolete) A WebAssembly solver that supports a limited set of rules and symbols.";
|
|
7
7
|
readonly supportsCancellation = false;
|
|
8
|
-
isEnvironmentSupported(): Promise<boolean>;
|
|
8
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
9
9
|
solve(grid: GridData): AsyncGenerator<GridData | null>;
|
|
10
10
|
isInstructionSupported(instructionId: string): boolean;
|
|
11
11
|
isGridSupported(grid: GridData): boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ import CellCountPerZoneRule from './data/rules/cellCountPerZoneRule.js';
|
|
|
20
20
|
import CellCountRule from './data/rules/cellCountRule.js';
|
|
21
21
|
import CompletePatternRule from './data/rules/completePatternRule.js';
|
|
22
22
|
import ConnectAllRule from './data/rules/connectAllRule.js';
|
|
23
|
+
import ContainsShapeRule from './data/rules/containsShapeRule.js';
|
|
23
24
|
import CustomRule from './data/rules/customRule.js';
|
|
24
25
|
import ForesightRule from './data/rules/foresightRule.js';
|
|
25
26
|
import { allRules } from './data/rules/index.js';
|
|
@@ -45,8 +46,9 @@ import GzipCompressor from './data/serializer/compressor/gzipCompressor.js';
|
|
|
45
46
|
import StreamCompressor from './data/serializer/compressor/streamCompressor.js';
|
|
46
47
|
import SerializerBase from './data/serializer/serializerBase.js';
|
|
47
48
|
import SerializerV0 from './data/serializer/serializer_v0.js';
|
|
48
|
-
import { getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape } from './data/shapes.js';
|
|
49
|
+
import { getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape } from './data/shapes.js';
|
|
49
50
|
import { allSolvers } from './data/solver/allSolvers.js';
|
|
51
|
+
import AutoSolver from './data/solver/auto/autoSolver.js';
|
|
50
52
|
import BacktrackSolver from './data/solver/backtrack/backtrackSolver.js';
|
|
51
53
|
import BTModule, { BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor } from './data/solver/backtrack/data.js';
|
|
52
54
|
import BanPatternBTModule from './data/solver/backtrack/rules/banPattern.js';
|
|
@@ -106,4 +108,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
106
108
|
import TileData from './data/tile.js';
|
|
107
109
|
import TileConnections from './data/tileConnections.js';
|
|
108
110
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
109
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
|
111
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, ContainsShapeRule, CustomRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape, allSolvers, AutoSolver, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ import CellCountPerZoneRule from './data/rules/cellCountPerZoneRule.js';
|
|
|
23
23
|
import CellCountRule from './data/rules/cellCountRule.js';
|
|
24
24
|
import CompletePatternRule from './data/rules/completePatternRule.js';
|
|
25
25
|
import ConnectAllRule from './data/rules/connectAllRule.js';
|
|
26
|
+
import ContainsShapeRule from './data/rules/containsShapeRule.js';
|
|
26
27
|
import CustomRule from './data/rules/customRule.js';
|
|
27
28
|
import ForesightRule from './data/rules/foresightRule.js';
|
|
28
29
|
import { allRules } from './data/rules/index.js';
|
|
@@ -48,8 +49,9 @@ import GzipCompressor from './data/serializer/compressor/gzipCompressor.js';
|
|
|
48
49
|
import StreamCompressor from './data/serializer/compressor/streamCompressor.js';
|
|
49
50
|
import SerializerBase from './data/serializer/serializerBase.js';
|
|
50
51
|
import SerializerV0 from './data/serializer/serializer_v0.js';
|
|
51
|
-
import { getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape } from './data/shapes.js';
|
|
52
|
+
import { getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape } from './data/shapes.js';
|
|
52
53
|
import { allSolvers } from './data/solver/allSolvers.js';
|
|
54
|
+
import AutoSolver from './data/solver/auto/autoSolver.js';
|
|
53
55
|
import BacktrackSolver from './data/solver/backtrack/backtrackSolver.js';
|
|
54
56
|
import BTModule, { BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor } from './data/solver/backtrack/data.js';
|
|
55
57
|
import BanPatternBTModule from './data/solver/backtrack/rules/banPattern.js';
|
|
@@ -109,4 +111,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
109
111
|
import TileData from './data/tile.js';
|
|
110
112
|
import TileConnections from './data/tileConnections.js';
|
|
111
113
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
112
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
|
114
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGetTile, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, WRAPPINGS, Wrapping, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, ContainsShapeRule, CustomRule, ForesightRule, allRules, LyingSymbolRule, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, WrapAroundRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, sanitizePatternGrid, shapeEquals, tilesToShape, allSolvers, AutoSolver, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, FocusBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, CspuzSolver, gridToJson, EventIteratingSolver, Solver, UniversalSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, FocusSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|