@logic-pad/core 0.4.2 → 0.4.4
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 +22 -11
- package/dist/data/events/onSetGrid.d.ts +1 -0
- package/dist/data/events/onSetGrid.js +15 -0
- package/dist/data/grid.d.ts +0 -8
- package/dist/data/grid.js +0 -23
- package/dist/data/instruction.d.ts +5 -0
- package/dist/data/primitives.d.ts +2 -1
- package/dist/data/primitives.js +1 -0
- package/dist/data/rules/cellCountPerZoneRule.d.ts +1 -1
- package/dist/data/rules/cellCountPerZoneRule.js +7 -2
- package/dist/data/rules/foresightRule.d.ts +2 -1
- package/dist/data/rules/foresightRule.js +8 -1
- package/dist/data/rules/perfectionRule.d.ts +11 -3
- package/dist/data/rules/perfectionRule.js +69 -13
- package/dist/data/rules/rule.d.ts +2 -1
- package/dist/data/rules/rule.js +3 -0
- package/dist/data/symbols/symbol.d.ts +2 -1
- package/dist/data/symbols/symbol.js +3 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/assets/z3-built.js +0 -14723
- package/assets/z3-built.wasm +0 -0
- package/assets/z3-built.worker.js +0 -206
|
@@ -111,6 +111,7 @@ declare global {
|
|
|
111
111
|
export declare enum Mode {
|
|
112
112
|
Create = 'create',
|
|
113
113
|
Solve = 'solve',
|
|
114
|
+
Perfection = 'perfection',
|
|
114
115
|
}
|
|
115
116
|
export declare class GridZones {
|
|
116
117
|
readonly edges: readonly Edge[];
|
|
@@ -320,6 +321,10 @@ declare global {
|
|
|
320
321
|
get validateWithSolution(): boolean;
|
|
321
322
|
get necessaryForCompletion(): boolean;
|
|
322
323
|
get visibleWhenSolving(): boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Return a variant of this instruction that is suitable for the given mode.
|
|
326
|
+
*/
|
|
327
|
+
abstract modeVariant(mode: Mode): Instruction | null;
|
|
323
328
|
/**
|
|
324
329
|
* Check if this instruction is equal to another instruction by comparing their IDs and configs.
|
|
325
330
|
*
|
|
@@ -336,6 +341,7 @@ declare global {
|
|
|
336
341
|
abstract validateGrid(grid: GridData): RuleState;
|
|
337
342
|
abstract get searchVariants(): SearchVariant[];
|
|
338
343
|
searchVariant(): SearchVariant;
|
|
344
|
+
modeVariant(_mode: Mode): Rule | null;
|
|
339
345
|
/**
|
|
340
346
|
* Whether only one instance of this rule is allowed in a grid.
|
|
341
347
|
*/
|
|
@@ -363,6 +369,7 @@ declare global {
|
|
|
363
369
|
readonly y: number;
|
|
364
370
|
constructor(x: number, y: number);
|
|
365
371
|
abstract validateSymbol(grid: GridData): State;
|
|
372
|
+
modeVariant(_mode: Mode): Symbol$1 | null;
|
|
366
373
|
onGridResize(
|
|
367
374
|
_grid: GridData,
|
|
368
375
|
mode: 'insert' | 'remove',
|
|
@@ -426,6 +433,11 @@ declare global {
|
|
|
426
433
|
export declare function handlesSetGrid<T extends Instruction>(
|
|
427
434
|
val: T
|
|
428
435
|
): val is T & SetGridHandler;
|
|
436
|
+
export declare function invokeSetGrid(
|
|
437
|
+
oldGrid: GridData,
|
|
438
|
+
newGrid: GridData,
|
|
439
|
+
solution: GridData | null
|
|
440
|
+
): GridData;
|
|
429
441
|
export declare class Row extends Configurable {
|
|
430
442
|
/**
|
|
431
443
|
* The note to play at this row, or null to keep the current note from the previous control line.
|
|
@@ -980,14 +992,6 @@ declare global {
|
|
|
980
992
|
* @returns True if the grids are equal in size and tile colors, false otherwise.
|
|
981
993
|
*/
|
|
982
994
|
colorEquals(grid: GridData): boolean;
|
|
983
|
-
/**
|
|
984
|
-
* Check if this grid conforms to the given solution, or an incomplete version of the solution.
|
|
985
|
-
* Symbols and rules are not validated.
|
|
986
|
-
*
|
|
987
|
-
* @param solution The solution to compare with.
|
|
988
|
-
* @returns True if the grid conforms to the solution, false otherwise.
|
|
989
|
-
*/
|
|
990
|
-
solutionMatches(solution: GridData): boolean;
|
|
991
995
|
/**
|
|
992
996
|
* Check if this grid is equal to another grid in terms of size, tile colors, connections, symbols, and rules.
|
|
993
997
|
*
|
|
@@ -1368,7 +1372,7 @@ declare global {
|
|
|
1368
1372
|
private static readonly EXAMPLE_GRID_GRAY;
|
|
1369
1373
|
private static readonly SEARCH_VARIANTS;
|
|
1370
1374
|
/**
|
|
1371
|
-
* **
|
|
1375
|
+
* **Zones of the same size have the same number of <color> cells.**
|
|
1372
1376
|
*
|
|
1373
1377
|
* @param color - The color of the cells to count.
|
|
1374
1378
|
*/
|
|
@@ -1483,6 +1487,7 @@ declare global {
|
|
|
1483
1487
|
validateGrid(_grid: GridData): RuleState;
|
|
1484
1488
|
get necessaryForCompletion(): boolean;
|
|
1485
1489
|
get isSingleton(): boolean;
|
|
1490
|
+
modeVariant(mode: Mode): Rule | null;
|
|
1486
1491
|
copyWith({
|
|
1487
1492
|
count,
|
|
1488
1493
|
regenInterval,
|
|
@@ -1573,12 +1578,15 @@ declare global {
|
|
|
1573
1578
|
extends Rule
|
|
1574
1579
|
implements SetGridHandler, FinalValidationHandler
|
|
1575
1580
|
{
|
|
1581
|
+
readonly editor: boolean;
|
|
1576
1582
|
private static readonly EXAMPLE_GRID;
|
|
1577
1583
|
private static readonly SEARCH_VARIANTS;
|
|
1578
1584
|
/**
|
|
1579
1585
|
* **Quest for Perfection: cell colors are final**
|
|
1586
|
+
*
|
|
1587
|
+
* @param editor - whether to enable editor mode. This field is automatically set by the editor.
|
|
1580
1588
|
*/
|
|
1581
|
-
constructor();
|
|
1589
|
+
constructor(editor?: boolean);
|
|
1582
1590
|
get id(): string;
|
|
1583
1591
|
get explanation(): string;
|
|
1584
1592
|
get configs(): readonly AnyConfig[] | null;
|
|
@@ -1586,6 +1594,7 @@ declare global {
|
|
|
1586
1594
|
get searchVariants(): SearchVariant[];
|
|
1587
1595
|
get necessaryForCompletion(): boolean;
|
|
1588
1596
|
get isSingleton(): boolean;
|
|
1597
|
+
modeVariant(mode: Mode): Rule | null;
|
|
1589
1598
|
validateGrid(grid: GridData): RuleState;
|
|
1590
1599
|
/**
|
|
1591
1600
|
* If the grid passes validation but is different from the solution, indicate the error in the final state.
|
|
@@ -1596,6 +1605,8 @@ declare global {
|
|
|
1596
1605
|
state: GridState
|
|
1597
1606
|
): GridState;
|
|
1598
1607
|
private fixTiles;
|
|
1608
|
+
private isValid;
|
|
1609
|
+
private findSingleError;
|
|
1599
1610
|
/**
|
|
1600
1611
|
* Force all tiles to be fixed.
|
|
1601
1612
|
*
|
|
@@ -1606,7 +1617,7 @@ declare global {
|
|
|
1606
1617
|
newGrid: GridData,
|
|
1607
1618
|
solution: GridData | null
|
|
1608
1619
|
): GridData;
|
|
1609
|
-
copyWith(
|
|
1620
|
+
copyWith({ editor }: { editor?: boolean }): this;
|
|
1610
1621
|
}
|
|
1611
1622
|
export declare class RegionAreaRule extends Rule {
|
|
1612
1623
|
readonly color: Color;
|
|
@@ -4,3 +4,4 @@ export interface SetGridHandler {
|
|
|
4
4
|
onSetGrid(oldGrid: GridData, newGrid: GridData, solution: GridData | null): GridData;
|
|
5
5
|
}
|
|
6
6
|
export declare function handlesSetGrid<T extends Instruction>(val: T): val is T & SetGridHandler;
|
|
7
|
+
export declare function invokeSetGrid(oldGrid: GridData, newGrid: GridData, solution: GridData | null): GridData;
|
|
@@ -2,3 +2,18 @@ import { isEventHandler } from './eventHelper.js';
|
|
|
2
2
|
export function handlesSetGrid(val) {
|
|
3
3
|
return isEventHandler(val, 'onSetGrid');
|
|
4
4
|
}
|
|
5
|
+
export function invokeSetGrid(oldGrid, newGrid, solution) {
|
|
6
|
+
newGrid.symbols.forEach(list => {
|
|
7
|
+
list.forEach(symbol => {
|
|
8
|
+
if (handlesSetGrid(symbol)) {
|
|
9
|
+
newGrid = symbol.onSetGrid(oldGrid, newGrid, solution);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
newGrid.rules.forEach(rule => {
|
|
14
|
+
if (handlesSetGrid(rule)) {
|
|
15
|
+
newGrid = rule.onSetGrid(oldGrid, newGrid, solution);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return newGrid;
|
|
19
|
+
}
|
package/dist/data/grid.d.ts
CHANGED
|
@@ -332,14 +332,6 @@ export default class GridData {
|
|
|
332
332
|
* @returns True if the grids are equal in size and tile colors, false otherwise.
|
|
333
333
|
*/
|
|
334
334
|
colorEquals(grid: GridData): boolean;
|
|
335
|
-
/**
|
|
336
|
-
* Check if this grid conforms to the given solution, or an incomplete version of the solution.
|
|
337
|
-
* Symbols and rules are not validated.
|
|
338
|
-
*
|
|
339
|
-
* @param solution The solution to compare with.
|
|
340
|
-
* @returns True if the grid conforms to the solution, false otherwise.
|
|
341
|
-
*/
|
|
342
|
-
solutionMatches(solution: GridData): boolean;
|
|
343
335
|
/**
|
|
344
336
|
* Check if this grid is equal to another grid in terms of size, tile colors, connections, symbols, and rules.
|
|
345
337
|
*
|
package/dist/data/grid.js
CHANGED
|
@@ -855,29 +855,6 @@ export default class GridData {
|
|
|
855
855
|
this.tiles.every((row, y) => row.every((tile, x) => (!tile.exists && !grid.getTile(x, y).exists) ||
|
|
856
856
|
tile.color === grid.getTile(x, y).color)));
|
|
857
857
|
}
|
|
858
|
-
/**
|
|
859
|
-
* Check if this grid conforms to the given solution, or an incomplete version of the solution.
|
|
860
|
-
* Symbols and rules are not validated.
|
|
861
|
-
*
|
|
862
|
-
* @param solution The solution to compare with.
|
|
863
|
-
* @returns True if the grid conforms to the solution, false otherwise.
|
|
864
|
-
*/
|
|
865
|
-
solutionMatches(solution) {
|
|
866
|
-
if (this.width !== solution.width)
|
|
867
|
-
return false;
|
|
868
|
-
if (this.height !== solution.height)
|
|
869
|
-
return false;
|
|
870
|
-
return this.tiles.every((row, y) => row.every((tile, x) => {
|
|
871
|
-
const solutionTile = solution.getTile(x, y);
|
|
872
|
-
if (!solutionTile.exists)
|
|
873
|
-
return true;
|
|
874
|
-
if (tile.color === Color.Gray)
|
|
875
|
-
return true;
|
|
876
|
-
if (solutionTile.color !== tile.color)
|
|
877
|
-
return false;
|
|
878
|
-
return true;
|
|
879
|
-
}));
|
|
880
|
-
}
|
|
881
858
|
/**
|
|
882
859
|
* Check if this grid is equal to another grid in terms of size, tile colors, connections, symbols, and rules.
|
|
883
860
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Configurable from './configurable.js';
|
|
2
2
|
import GridData from './grid.js';
|
|
3
|
+
import { Mode } from './primitives.js';
|
|
3
4
|
export default abstract class Instruction extends Configurable {
|
|
4
5
|
abstract get id(): string;
|
|
5
6
|
abstract get explanation(): string;
|
|
@@ -10,6 +11,10 @@ export default abstract class Instruction extends Configurable {
|
|
|
10
11
|
get validateWithSolution(): boolean;
|
|
11
12
|
get necessaryForCompletion(): boolean;
|
|
12
13
|
get visibleWhenSolving(): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Return a variant of this instruction that is suitable for the given mode.
|
|
16
|
+
*/
|
|
17
|
+
abstract modeVariant(mode: Mode): Instruction | null;
|
|
13
18
|
/**
|
|
14
19
|
* Check if this instruction is equal to another instruction by comparing their IDs and configs.
|
|
15
20
|
*
|
package/dist/data/primitives.js
CHANGED
|
@@ -10,7 +10,7 @@ export default class CellCountPerZoneRule extends Rule {
|
|
|
10
10
|
private static readonly EXAMPLE_GRID_GRAY;
|
|
11
11
|
private static readonly SEARCH_VARIANTS;
|
|
12
12
|
/**
|
|
13
|
-
* **
|
|
13
|
+
* **Zones of the same size have the same number of <color> cells.**
|
|
14
14
|
*
|
|
15
15
|
* @param color - The color of the cells to count.
|
|
16
16
|
*/
|
|
@@ -6,7 +6,7 @@ import { Color, State } from '../primitives.js';
|
|
|
6
6
|
import Rule from './rule.js';
|
|
7
7
|
class CellCountPerZoneRule extends Rule {
|
|
8
8
|
/**
|
|
9
|
-
* **
|
|
9
|
+
* **Zones of the same size have the same number of <color> cells.**
|
|
10
10
|
*
|
|
11
11
|
* @param color - The color of the cells to count.
|
|
12
12
|
*/
|
|
@@ -24,7 +24,7 @@ class CellCountPerZoneRule extends Rule {
|
|
|
24
24
|
return `zone_cell_count`;
|
|
25
25
|
}
|
|
26
26
|
get explanation() {
|
|
27
|
-
return `
|
|
27
|
+
return `Zones of the same size have the same number of ${this.color} cells`;
|
|
28
28
|
}
|
|
29
29
|
get configs() {
|
|
30
30
|
return CellCountPerZoneRule.CONFIGS;
|
|
@@ -91,6 +91,7 @@ class CellCountPerZoneRule extends Rule {
|
|
|
91
91
|
}
|
|
92
92
|
else {
|
|
93
93
|
const errorZone = zones.find(z => zones.some(zz => zz !== z &&
|
|
94
|
+
zz.positions.length === z.positions.length &&
|
|
94
95
|
(zz.completed > z.completed + z.possible ||
|
|
95
96
|
zz.completed + zz.possible < z.completed)));
|
|
96
97
|
if (errorZone) {
|
|
@@ -137,6 +138,10 @@ Object.defineProperty(CellCountPerZoneRule, "EXAMPLE_GRID_LIGHT", {
|
|
|
137
138
|
{ x1: 2, y1: 1, x2: 2, y2: 2 },
|
|
138
139
|
{ x1: 3, y1: 1, x2: 3, y2: 2 },
|
|
139
140
|
{ x1: 4, y1: 1, x2: 4, y2: 2 },
|
|
141
|
+
{ x1: 1, y1: 0, x2: 2, y2: 0 },
|
|
142
|
+
{ x1: 1, y1: 1, x2: 2, y2: 1 },
|
|
143
|
+
{ x1: 2, y1: 2, x2: 3, y2: 2 },
|
|
144
|
+
{ x1: 2, y1: 3, x2: 3, y2: 3 },
|
|
140
145
|
]))
|
|
141
146
|
.addRule(new CellCountPerZoneRule(Color.Light)))
|
|
142
147
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyConfig } from '../config.js';
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
|
-
import { RuleState, Position } from '../primitives.js';
|
|
3
|
+
import { RuleState, Position, Mode } from '../primitives.js';
|
|
4
4
|
import Rule, { SearchVariant } from './rule.js';
|
|
5
5
|
export default class ForesightRule extends Rule {
|
|
6
6
|
readonly count: number;
|
|
@@ -23,6 +23,7 @@ export default class ForesightRule extends Rule {
|
|
|
23
23
|
validateGrid(_grid: GridData): RuleState;
|
|
24
24
|
get necessaryForCompletion(): boolean;
|
|
25
25
|
get isSingleton(): boolean;
|
|
26
|
+
modeVariant(mode: Mode): Rule | null;
|
|
26
27
|
copyWith({ count, regenInterval, startFull, solvePath, }: {
|
|
27
28
|
count?: number;
|
|
28
29
|
regenInterval?: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConfigType } from '../config.js';
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
|
-
import { State } from '../primitives.js';
|
|
3
|
+
import { State, Mode } from '../primitives.js';
|
|
4
4
|
import CustomIconSymbol from '../symbols/customIconSymbol.js';
|
|
5
5
|
import Rule from './rule.js';
|
|
6
6
|
class ForesightRule extends Rule {
|
|
@@ -65,6 +65,13 @@ class ForesightRule extends Rule {
|
|
|
65
65
|
get isSingleton() {
|
|
66
66
|
return true;
|
|
67
67
|
}
|
|
68
|
+
modeVariant(mode) {
|
|
69
|
+
// foresight is disabled in perfection mode
|
|
70
|
+
if (mode === Mode.Perfection) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
68
75
|
copyWith({ count, regenInterval, startFull, solvePath, }) {
|
|
69
76
|
return new ForesightRule(count ?? this.count, regenInterval ?? this.regenInterval, startFull ?? this.startFull, solvePath ?? this.solvePath);
|
|
70
77
|
}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { AnyConfig } from '../config.js';
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
|
-
import { GridState, RuleState } from '../primitives.js';
|
|
3
|
+
import { GridState, RuleState, Mode } from '../primitives.js';
|
|
4
4
|
import Rule, { SearchVariant } from './rule.js';
|
|
5
5
|
import { SetGridHandler } from '../events/onSetGrid.js';
|
|
6
6
|
import { FinalValidationHandler } from '../events/onFinalValidation.js';
|
|
7
7
|
export default class PerfectionRule extends Rule implements SetGridHandler, FinalValidationHandler {
|
|
8
|
+
readonly editor: boolean;
|
|
8
9
|
private static readonly EXAMPLE_GRID;
|
|
9
10
|
private static readonly SEARCH_VARIANTS;
|
|
10
11
|
/**
|
|
11
12
|
* **Quest for Perfection: cell colors are final**
|
|
13
|
+
*
|
|
14
|
+
* @param editor - whether to enable editor mode. This field is automatically set by the editor.
|
|
12
15
|
*/
|
|
13
|
-
constructor();
|
|
16
|
+
constructor(editor?: boolean);
|
|
14
17
|
get id(): string;
|
|
15
18
|
get explanation(): string;
|
|
16
19
|
get configs(): readonly AnyConfig[] | null;
|
|
@@ -18,18 +21,23 @@ export default class PerfectionRule extends Rule implements SetGridHandler, Fina
|
|
|
18
21
|
get searchVariants(): SearchVariant[];
|
|
19
22
|
get necessaryForCompletion(): boolean;
|
|
20
23
|
get isSingleton(): boolean;
|
|
24
|
+
modeVariant(mode: Mode): Rule | null;
|
|
21
25
|
validateGrid(grid: GridData): RuleState;
|
|
22
26
|
/**
|
|
23
27
|
* If the grid passes validation but is different from the solution, indicate the error in the final state.
|
|
24
28
|
*/
|
|
25
29
|
onFinalValidation(grid: GridData, solution: GridData | null, state: GridState): GridState;
|
|
26
30
|
private fixTiles;
|
|
31
|
+
private isValid;
|
|
32
|
+
private findSingleError;
|
|
27
33
|
/**
|
|
28
34
|
* Force all tiles to be fixed.
|
|
29
35
|
*
|
|
30
36
|
* If the grid is already wrong, prevent the player from changing it further.
|
|
31
37
|
*/
|
|
32
38
|
onSetGrid(oldGrid: GridData, newGrid: GridData, solution: GridData | null): GridData;
|
|
33
|
-
copyWith(
|
|
39
|
+
copyWith({ editor }: {
|
|
40
|
+
editor?: boolean;
|
|
41
|
+
}): this;
|
|
34
42
|
}
|
|
35
43
|
export declare const instance: PerfectionRule;
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import GridData from '../grid.js';
|
|
2
|
-
import { Color, State } from '../primitives.js';
|
|
2
|
+
import { Color, State, Mode, } from '../primitives.js';
|
|
3
3
|
import Rule from './rule.js';
|
|
4
4
|
import CustomIconSymbol from '../symbols/customIconSymbol.js';
|
|
5
|
+
import validateGrid from '../validate.js';
|
|
5
6
|
class PerfectionRule extends Rule {
|
|
6
7
|
/**
|
|
7
8
|
* **Quest for Perfection: cell colors are final**
|
|
9
|
+
*
|
|
10
|
+
* @param editor - whether to enable editor mode. This field is automatically set by the editor.
|
|
8
11
|
*/
|
|
9
|
-
constructor() {
|
|
12
|
+
constructor(editor = false) {
|
|
10
13
|
super();
|
|
14
|
+
Object.defineProperty(this, "editor", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: editor
|
|
19
|
+
});
|
|
20
|
+
this.editor = editor;
|
|
11
21
|
}
|
|
12
22
|
get id() {
|
|
13
23
|
return `perfection`;
|
|
@@ -30,6 +40,18 @@ class PerfectionRule extends Rule {
|
|
|
30
40
|
get isSingleton() {
|
|
31
41
|
return true;
|
|
32
42
|
}
|
|
43
|
+
modeVariant(mode) {
|
|
44
|
+
// only allow this rule in perfection mode
|
|
45
|
+
if (this.editor === (mode === Mode.Create)) {
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
else if (mode === Mode.Create) {
|
|
49
|
+
return this.copyWith({ editor: true });
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
return this.copyWith({ editor: false });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
33
55
|
validateGrid(grid) {
|
|
34
56
|
if (grid.getTileCount(true, undefined, Color.Gray) > 0) {
|
|
35
57
|
return { state: State.Incomplete };
|
|
@@ -71,30 +93,62 @@ class PerfectionRule extends Rule {
|
|
|
71
93
|
}
|
|
72
94
|
return state;
|
|
73
95
|
}
|
|
74
|
-
fixTiles(grid) {
|
|
96
|
+
fixTiles(grid, exclusions) {
|
|
75
97
|
if (grid.getTileCount(true, false, Color.Light) > 0 ||
|
|
76
98
|
grid.getTileCount(true, false, Color.Dark) > 0) {
|
|
77
|
-
return grid.withTiles(tiles => tiles.map(row => row.map(t => t.exists &&
|
|
99
|
+
return grid.withTiles(tiles => tiles.map((row, y) => row.map((t, x) => t.exists &&
|
|
100
|
+
t.color !== Color.Gray &&
|
|
101
|
+
!exclusions?.some(e => e.x === x && e.y === y)
|
|
102
|
+
? t.withFixed(true)
|
|
103
|
+
: t)));
|
|
78
104
|
}
|
|
79
105
|
return grid;
|
|
80
106
|
}
|
|
107
|
+
isValid(grid, solution) {
|
|
108
|
+
return validateGrid(grid, solution).final !== State.Error;
|
|
109
|
+
}
|
|
110
|
+
findSingleError(grid, solution) {
|
|
111
|
+
if (solution === null)
|
|
112
|
+
return [];
|
|
113
|
+
const positions = [];
|
|
114
|
+
// If a solution is available, we can compare against the solution and allow the user to modify the one single error.
|
|
115
|
+
grid.tiles.forEach((row, y) => row.forEach((t, x) => {
|
|
116
|
+
if (t.exists &&
|
|
117
|
+
t.color !== Color.Gray &&
|
|
118
|
+
t.color !== solution.getTile(x, y).color) {
|
|
119
|
+
positions.push({ x, y });
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
if (positions.length > 1) {
|
|
123
|
+
const connected = grid.connections.getConnectedTiles(positions[0]);
|
|
124
|
+
if (!positions.every(p => connected.some(c => c.x === p.x && c.y === p.y))) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return positions;
|
|
129
|
+
}
|
|
81
130
|
/**
|
|
82
131
|
* Force all tiles to be fixed.
|
|
83
132
|
*
|
|
84
133
|
* If the grid is already wrong, prevent the player from changing it further.
|
|
85
134
|
*/
|
|
86
135
|
onSetGrid(oldGrid, newGrid, solution) {
|
|
87
|
-
if (
|
|
88
|
-
return
|
|
136
|
+
if (this.editor)
|
|
137
|
+
return newGrid;
|
|
138
|
+
const oldGridIsValid = this.isValid(oldGrid, solution);
|
|
139
|
+
const newGridIsValid = this.isValid(newGrid, solution);
|
|
140
|
+
if (!oldGridIsValid && !newGridIsValid) {
|
|
141
|
+
const oldPositions = this.findSingleError(oldGrid, solution);
|
|
142
|
+
return this.fixTiles(oldGrid, oldPositions);
|
|
89
143
|
}
|
|
90
|
-
if (!
|
|
91
|
-
|
|
92
|
-
return this.fixTiles(
|
|
144
|
+
else if (!newGridIsValid) {
|
|
145
|
+
const positions = this.findSingleError(newGrid, solution);
|
|
146
|
+
return this.fixTiles(newGrid, positions);
|
|
93
147
|
}
|
|
94
148
|
return this.fixTiles(newGrid);
|
|
95
149
|
}
|
|
96
|
-
copyWith(
|
|
97
|
-
return new PerfectionRule();
|
|
150
|
+
copyWith({ editor }) {
|
|
151
|
+
return new PerfectionRule(editor ?? this.editor);
|
|
98
152
|
}
|
|
99
153
|
}
|
|
100
154
|
Object.defineProperty(PerfectionRule, "EXAMPLE_GRID", {
|
|
@@ -107,7 +161,9 @@ Object.defineProperty(PerfectionRule, "SEARCH_VARIANTS", {
|
|
|
107
161
|
enumerable: true,
|
|
108
162
|
configurable: true,
|
|
109
163
|
writable: true,
|
|
110
|
-
value: [
|
|
111
|
-
|
|
164
|
+
value: [
|
|
165
|
+
new PerfectionRule().searchVariant(),
|
|
166
|
+
]
|
|
167
|
+
});
|
|
112
168
|
export default PerfectionRule;
|
|
113
169
|
export const instance = new PerfectionRule();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import GridData from '../grid.js';
|
|
2
|
-
import { RuleState } from '../primitives.js';
|
|
2
|
+
import { Mode, RuleState } from '../primitives.js';
|
|
3
3
|
import Instruction from '../instruction.js';
|
|
4
4
|
export interface SearchVariant {
|
|
5
5
|
description: string;
|
|
@@ -9,6 +9,7 @@ export default abstract class Rule extends Instruction {
|
|
|
9
9
|
abstract validateGrid(grid: GridData): RuleState;
|
|
10
10
|
abstract get searchVariants(): SearchVariant[];
|
|
11
11
|
searchVariant(): SearchVariant;
|
|
12
|
+
modeVariant(_mode: Mode): Rule | null;
|
|
12
13
|
/**
|
|
13
14
|
* Whether only one instance of this rule is allowed in a grid.
|
|
14
15
|
*/
|
package/dist/data/rules/rule.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { GridResizeHandler } from '../events/onGridResize.js';
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
3
|
import Instruction from '../instruction.js';
|
|
4
|
-
import { State } from '../primitives.js';
|
|
4
|
+
import { Mode, State } from '../primitives.js';
|
|
5
5
|
export default abstract class Symbol extends Instruction implements GridResizeHandler {
|
|
6
6
|
readonly x: number;
|
|
7
7
|
readonly y: number;
|
|
8
8
|
constructor(x: number, y: number);
|
|
9
9
|
abstract validateSymbol(grid: GridData): State;
|
|
10
|
+
modeVariant(_mode: Mode): Symbol | null;
|
|
10
11
|
onGridResize(_grid: GridData, mode: 'insert' | 'remove', direction: 'row' | 'column', index: number): this | null;
|
|
11
12
|
/**
|
|
12
13
|
* The step size for the x and y coordinates of the symbol.
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { isEventHandler } from './data/events/eventHelper.js';
|
|
|
5
5
|
import { handlesFinalValidation } from './data/events/onFinalValidation.js';
|
|
6
6
|
import { handlesGridChange } from './data/events/onGridChange.js';
|
|
7
7
|
import { handlesGridResize } from './data/events/onGridResize.js';
|
|
8
|
-
import { handlesSetGrid } from './data/events/onSetGrid.js';
|
|
8
|
+
import { handlesSetGrid, invokeSetGrid } from './data/events/onSetGrid.js';
|
|
9
9
|
import { handlesSymbolDisplay } from './data/events/onSymbolDisplay.js';
|
|
10
10
|
import { handlesSymbolValidation } from './data/events/onSymbolValidation.js';
|
|
11
11
|
import GridData, { NEIGHBOR_OFFSETS } from './data/grid.js';
|
|
@@ -98,4 +98,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
98
98
|
import TileData from './data/tile.js';
|
|
99
99
|
import TileConnections from './data/tileConnections.js';
|
|
100
100
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
101
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, 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, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver, UndercluedSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
|
101
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, 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, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver, UndercluedSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { isEventHandler } from './data/events/eventHelper.js';
|
|
|
8
8
|
import { handlesFinalValidation } from './data/events/onFinalValidation.js';
|
|
9
9
|
import { handlesGridChange } from './data/events/onGridChange.js';
|
|
10
10
|
import { handlesGridResize } from './data/events/onGridResize.js';
|
|
11
|
-
import { handlesSetGrid } from './data/events/onSetGrid.js';
|
|
11
|
+
import { handlesSetGrid, invokeSetGrid } from './data/events/onSetGrid.js';
|
|
12
12
|
import { handlesSymbolDisplay } from './data/events/onSymbolDisplay.js';
|
|
13
13
|
import { handlesSymbolValidation } from './data/events/onSymbolValidation.js';
|
|
14
14
|
import GridData, { NEIGHBOR_OFFSETS } from './data/grid.js';
|
|
@@ -101,4 +101,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
101
101
|
import TileData from './data/tile.js';
|
|
102
102
|
import TileConnections from './data/tileConnections.js';
|
|
103
103
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
104
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, 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, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver, UndercluedSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|
|
104
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, invokeSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, 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, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver, UndercluedSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
|