@logic-pad/core 0.2.1 → 0.3.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 +76 -5
- package/dist/data/config.d.ts +7 -3
- package/dist/data/config.js +8 -0
- package/dist/data/events/onSetGrid.d.ts +1 -1
- package/dist/data/grid.d.ts +8 -0
- package/dist/data/grid.js +25 -2
- package/dist/data/rules/foresightRule.d.ts +5 -3
- package/dist/data/rules/foresightRule.js +17 -3
- package/dist/data/rules/musicGridRule.d.ts +1 -1
- package/dist/data/rules/musicGridRule.js +1 -1
- package/dist/data/rules/perfectionRule.d.ts +35 -0
- package/dist/data/rules/perfectionRule.js +113 -0
- package/dist/data/rules/rules.gen.d.ts +1 -0
- package/dist/data/rules/rules.gen.js +1 -0
- package/dist/data/serializer/serializer_v0.js +16 -0
- package/dist/data/solver/backtrack/backtrackSolver.js +1 -1
- package/dist/data/solver/backtrack/symbols/directionLinker.d.ts +2 -0
- package/dist/data/solver/backtrack/symbols/directionLinker.js +95 -14
- package/dist/data/solver/backtrack/symbols/lotus.d.ts +3 -1
- package/dist/data/solver/backtrack/symbols/lotus.js +24 -0
- package/dist/data/symbols/directionLinkerSymbol.d.ts +0 -1
- package/dist/data/symbols/directionLinkerSymbol.js +77 -94
- package/dist/data/symbols/lotusSymbol.js +18 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/package.json +1 -1
|
@@ -401,7 +401,11 @@ declare global {
|
|
|
401
401
|
val: T
|
|
402
402
|
): val is T & GridChangeHandler;
|
|
403
403
|
export interface SetGridHandler {
|
|
404
|
-
onSetGrid(
|
|
404
|
+
onSetGrid(
|
|
405
|
+
oldGrid: GridData,
|
|
406
|
+
newGrid: GridData,
|
|
407
|
+
solution: GridData | null
|
|
408
|
+
): GridData;
|
|
405
409
|
}
|
|
406
410
|
export declare function handlesSetGrid<T extends Instruction>(
|
|
407
411
|
val: T
|
|
@@ -504,7 +508,11 @@ declare global {
|
|
|
504
508
|
createExampleGrid(): GridData;
|
|
505
509
|
get searchVariants(): SearchVariant[];
|
|
506
510
|
validateGrid(_grid: GridData): RuleState;
|
|
507
|
-
onSetGrid(
|
|
511
|
+
onSetGrid(
|
|
512
|
+
_oldGrid: GridData,
|
|
513
|
+
newGrid: GridData,
|
|
514
|
+
_solution: GridData | null
|
|
515
|
+
): GridData;
|
|
508
516
|
onGridChange(newGrid: GridData): this;
|
|
509
517
|
onGridResize(
|
|
510
518
|
_grid: GridData,
|
|
@@ -944,6 +952,14 @@ declare global {
|
|
|
944
952
|
* @returns True if the grids are equal in size and tile colors, false otherwise.
|
|
945
953
|
*/
|
|
946
954
|
colorEquals(grid: GridData): boolean;
|
|
955
|
+
/**
|
|
956
|
+
* Check if this grid conforms to the given solution, or an incomplete version of the solution.
|
|
957
|
+
* Symbols and rules are not validated.
|
|
958
|
+
*
|
|
959
|
+
* @param solution The solution to compare with.
|
|
960
|
+
* @returns True if the grid conforms to the solution, false otherwise.
|
|
961
|
+
*/
|
|
962
|
+
solutionMatches(solution: GridData): boolean;
|
|
947
963
|
/**
|
|
948
964
|
* Check if this grid is equal to another grid in terms of size, tile colors, connections, symbols, and rules.
|
|
949
965
|
*
|
|
@@ -1014,6 +1030,7 @@ declare global {
|
|
|
1014
1030
|
Icon = 'icon',
|
|
1015
1031
|
ControlLines = 'controlLines',
|
|
1016
1032
|
NullableNote = 'nullableNote',
|
|
1033
|
+
SolvePath = 'solvePath',
|
|
1017
1034
|
}
|
|
1018
1035
|
export interface Config<T> {
|
|
1019
1036
|
readonly type: ConfigType;
|
|
@@ -1084,6 +1101,9 @@ declare global {
|
|
|
1084
1101
|
export interface NullableNoteConfig extends Config<string | null> {
|
|
1085
1102
|
readonly type: ConfigType.NullableNote;
|
|
1086
1103
|
}
|
|
1104
|
+
export interface SolvePathConfig extends Config<Position$1[]> {
|
|
1105
|
+
readonly type: ConfigType.SolvePath;
|
|
1106
|
+
}
|
|
1087
1107
|
export type AnyConfig =
|
|
1088
1108
|
| BooleanConfig
|
|
1089
1109
|
| NullableBooleanConfig
|
|
@@ -1101,7 +1121,8 @@ declare global {
|
|
|
1101
1121
|
| NullableGridConfig
|
|
1102
1122
|
| IconConfig
|
|
1103
1123
|
| ControlLinesConfig
|
|
1104
|
-
| NullableNoteConfig
|
|
1124
|
+
| NullableNoteConfig
|
|
1125
|
+
| SolvePathConfig;
|
|
1105
1126
|
/**
|
|
1106
1127
|
* Compare two config values for equality, using an appropriate method for the config type.
|
|
1107
1128
|
*
|
|
@@ -1390,13 +1411,19 @@ declare global {
|
|
|
1390
1411
|
readonly count: number;
|
|
1391
1412
|
readonly regenInterval: number;
|
|
1392
1413
|
readonly startFull: boolean;
|
|
1414
|
+
readonly solvePath: Position$1[];
|
|
1393
1415
|
private static readonly EXAMPLE_GRID;
|
|
1394
1416
|
private static readonly CONFIGS;
|
|
1395
1417
|
private static readonly SEARCH_VARIANTS;
|
|
1396
1418
|
/**
|
|
1397
1419
|
* **Foresight: Show hints**
|
|
1398
1420
|
*/
|
|
1399
|
-
constructor(
|
|
1421
|
+
constructor(
|
|
1422
|
+
count: number,
|
|
1423
|
+
regenInterval: number,
|
|
1424
|
+
startFull: boolean,
|
|
1425
|
+
solvePath?: Position$1[]
|
|
1426
|
+
);
|
|
1400
1427
|
get id(): string;
|
|
1401
1428
|
get explanation(): string;
|
|
1402
1429
|
get visibleWhenSolving(): boolean;
|
|
@@ -1410,10 +1437,12 @@ declare global {
|
|
|
1410
1437
|
count,
|
|
1411
1438
|
regenInterval,
|
|
1412
1439
|
startFull,
|
|
1440
|
+
solvePath,
|
|
1413
1441
|
}: {
|
|
1414
1442
|
count?: number;
|
|
1415
1443
|
regenInterval?: number;
|
|
1416
1444
|
startFull?: boolean;
|
|
1445
|
+
solvePath?: Position$1[];
|
|
1417
1446
|
}): this;
|
|
1418
1447
|
}
|
|
1419
1448
|
export declare const allRules: Map<string, Rule>;
|
|
@@ -1490,6 +1519,45 @@ declare global {
|
|
|
1490
1519
|
copyWith({ number }: { number?: number }): this;
|
|
1491
1520
|
withNumber(number: number): this;
|
|
1492
1521
|
}
|
|
1522
|
+
export declare class PerfectionRule
|
|
1523
|
+
extends Rule
|
|
1524
|
+
implements SetGridHandler, FinalValidationHandler
|
|
1525
|
+
{
|
|
1526
|
+
private static readonly EXAMPLE_GRID;
|
|
1527
|
+
private static readonly SEARCH_VARIANTS;
|
|
1528
|
+
/**
|
|
1529
|
+
* **Quest for Perfection: cell colors are final**
|
|
1530
|
+
*/
|
|
1531
|
+
constructor();
|
|
1532
|
+
get id(): string;
|
|
1533
|
+
get explanation(): string;
|
|
1534
|
+
get configs(): readonly AnyConfig[] | null;
|
|
1535
|
+
createExampleGrid(): GridData;
|
|
1536
|
+
get searchVariants(): SearchVariant[];
|
|
1537
|
+
get necessaryForCompletion(): boolean;
|
|
1538
|
+
get isSingleton(): boolean;
|
|
1539
|
+
validateGrid(grid: GridData): RuleState;
|
|
1540
|
+
/**
|
|
1541
|
+
* If the grid passes validation but is different from the solution, indicate the error in the final state.
|
|
1542
|
+
*/
|
|
1543
|
+
onFinalValidation(
|
|
1544
|
+
grid: GridData,
|
|
1545
|
+
solution: GridData | null,
|
|
1546
|
+
state: GridState
|
|
1547
|
+
): GridState;
|
|
1548
|
+
private fixTiles;
|
|
1549
|
+
/**
|
|
1550
|
+
* Force all tiles to be fixed.
|
|
1551
|
+
*
|
|
1552
|
+
* If the grid is already wrong, prevent the player from changing it further.
|
|
1553
|
+
*/
|
|
1554
|
+
onSetGrid(
|
|
1555
|
+
oldGrid: GridData,
|
|
1556
|
+
newGrid: GridData,
|
|
1557
|
+
solution: GridData | null
|
|
1558
|
+
): GridData;
|
|
1559
|
+
copyWith(_: object): this;
|
|
1560
|
+
}
|
|
1493
1561
|
export declare class RegionAreaRule extends Rule {
|
|
1494
1562
|
readonly color: Color;
|
|
1495
1563
|
readonly size: number;
|
|
@@ -2011,7 +2079,6 @@ declare global {
|
|
|
2011
2079
|
get explanation(): string;
|
|
2012
2080
|
get configs(): readonly AnyConfig[] | null;
|
|
2013
2081
|
createExampleGrid(): GridData;
|
|
2014
|
-
private getColor;
|
|
2015
2082
|
private deltaCoordinate;
|
|
2016
2083
|
validateSymbol(grid: GridData): State;
|
|
2017
2084
|
copyWith({ x, y }: { x?: number; y?: number }): this;
|
|
@@ -2020,6 +2087,8 @@ declare global {
|
|
|
2020
2087
|
export declare abstract class DirectionLinkerBTModule extends BTModule {
|
|
2021
2088
|
instr: DirectionLinkerSymbol;
|
|
2022
2089
|
constructor(instr: DirectionLinkerSymbol);
|
|
2090
|
+
private initialPositions;
|
|
2091
|
+
private getInitialPositions;
|
|
2023
2092
|
checkGlobal(grid: BTGridData): CheckResult | false;
|
|
2024
2093
|
protected abstract movePos(
|
|
2025
2094
|
grid: BTGridData,
|
|
@@ -2127,6 +2196,8 @@ declare global {
|
|
|
2127
2196
|
x: number,
|
|
2128
2197
|
y: number
|
|
2129
2198
|
): Position$1 | null;
|
|
2199
|
+
private getTileSafe;
|
|
2200
|
+
checkGlobal(grid: BTGridData): false | CheckResult;
|
|
2130
2201
|
}
|
|
2131
2202
|
export declare class MinesweeperSymbol extends NumberSymbol {
|
|
2132
2203
|
private static readonly CONFIGS;
|
package/dist/data/config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import GridData from './grid.js';
|
|
2
|
-
import { Color, Comparison, Direction, DirectionToggle, Orientation, OrientationToggle } from './primitives.js';
|
|
2
|
+
import { Color, Comparison, Direction, DirectionToggle, Orientation, OrientationToggle, Position } from './primitives.js';
|
|
3
3
|
import { ControlLine } from './rules/musicControlLine.js';
|
|
4
4
|
export declare enum ConfigType {
|
|
5
5
|
Boolean = "boolean",
|
|
@@ -18,7 +18,8 @@ export declare enum ConfigType {
|
|
|
18
18
|
NullableGrid = "nullableGrid",
|
|
19
19
|
Icon = "icon",
|
|
20
20
|
ControlLines = "controlLines",
|
|
21
|
-
NullableNote = "nullableNote"
|
|
21
|
+
NullableNote = "nullableNote",
|
|
22
|
+
SolvePath = "solvePath"
|
|
22
23
|
}
|
|
23
24
|
export interface Config<T> {
|
|
24
25
|
readonly type: ConfigType;
|
|
@@ -89,7 +90,10 @@ export interface ControlLinesConfig extends Config<ControlLine[]> {
|
|
|
89
90
|
export interface NullableNoteConfig extends Config<string | null> {
|
|
90
91
|
readonly type: ConfigType.NullableNote;
|
|
91
92
|
}
|
|
92
|
-
export
|
|
93
|
+
export interface SolvePathConfig extends Config<Position[]> {
|
|
94
|
+
readonly type: ConfigType.SolvePath;
|
|
95
|
+
}
|
|
96
|
+
export type AnyConfig = BooleanConfig | NullableBooleanConfig | NumberConfig | NullableNumberConfig | StringConfig | ColorConfig | ComparisonConfig | DirectionConfig | DirectionToggleConfig | OrientationConfig | OrientationToggleConfig | TileConfig | GridConfig | NullableGridConfig | IconConfig | ControlLinesConfig | NullableNoteConfig | SolvePathConfig;
|
|
93
97
|
/**
|
|
94
98
|
* Compare two config values for equality, using an appropriate method for the config type.
|
|
95
99
|
*
|
package/dist/data/config.js
CHANGED
|
@@ -18,6 +18,7 @@ export var ConfigType;
|
|
|
18
18
|
ConfigType["Icon"] = "icon";
|
|
19
19
|
ConfigType["ControlLines"] = "controlLines";
|
|
20
20
|
ConfigType["NullableNote"] = "nullableNote";
|
|
21
|
+
ConfigType["SolvePath"] = "solvePath";
|
|
21
22
|
})(ConfigType || (ConfigType = {}));
|
|
22
23
|
/**
|
|
23
24
|
* Compare two config values for equality, using an appropriate method for the config type.
|
|
@@ -51,5 +52,12 @@ export function configEquals(type, a, b) {
|
|
|
51
52
|
if (type === ConfigType.OrientationToggle) {
|
|
52
53
|
return ORIENTATIONS.every(dir => a[dir] === b[dir]);
|
|
53
54
|
}
|
|
55
|
+
if (type === ConfigType.SolvePath) {
|
|
56
|
+
const aPath = a;
|
|
57
|
+
const bPath = b;
|
|
58
|
+
if (aPath.length !== bPath.length)
|
|
59
|
+
return false;
|
|
60
|
+
return aPath.every((pos, i) => pos.x === bPath[i].x && pos.y === bPath[i].y);
|
|
61
|
+
}
|
|
54
62
|
return a === b;
|
|
55
63
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import GridData from '../grid.js';
|
|
2
2
|
import Instruction from '../instruction.js';
|
|
3
3
|
export interface SetGridHandler {
|
|
4
|
-
onSetGrid(oldGrid: GridData, newGrid: GridData): GridData;
|
|
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;
|
package/dist/data/grid.d.ts
CHANGED
|
@@ -321,6 +321,14 @@ export default class GridData {
|
|
|
321
321
|
* @returns True if the grids are equal in size and tile colors, false otherwise.
|
|
322
322
|
*/
|
|
323
323
|
colorEquals(grid: GridData): boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Check if this grid conforms to the given solution, or an incomplete version of the solution.
|
|
326
|
+
* Symbols and rules are not validated.
|
|
327
|
+
*
|
|
328
|
+
* @param solution The solution to compare with.
|
|
329
|
+
* @returns True if the grid conforms to the solution, false otherwise.
|
|
330
|
+
*/
|
|
331
|
+
solutionMatches(solution: GridData): boolean;
|
|
324
332
|
/**
|
|
325
333
|
* Check if this grid is equal to another grid in terms of size, tile colors, connections, symbols, and rules.
|
|
326
334
|
*
|
package/dist/data/grid.js
CHANGED
|
@@ -709,13 +709,13 @@ export default class GridData {
|
|
|
709
709
|
this.symbols.forEach(list => {
|
|
710
710
|
list.forEach(symbol => {
|
|
711
711
|
if (handlesSetGrid(symbol)) {
|
|
712
|
-
newGrid = symbol.onSetGrid(this, newGrid);
|
|
712
|
+
newGrid = symbol.onSetGrid(this, newGrid, null);
|
|
713
713
|
}
|
|
714
714
|
});
|
|
715
715
|
});
|
|
716
716
|
this.rules.forEach(rule => {
|
|
717
717
|
if (handlesSetGrid(rule)) {
|
|
718
|
-
newGrid = rule.onSetGrid(this, newGrid);
|
|
718
|
+
newGrid = rule.onSetGrid(this, newGrid, null);
|
|
719
719
|
}
|
|
720
720
|
});
|
|
721
721
|
return newGrid;
|
|
@@ -801,6 +801,29 @@ export default class GridData {
|
|
|
801
801
|
this.tiles.every((row, y) => row.every((tile, x) => (!tile.exists && !grid.getTile(x, y).exists) ||
|
|
802
802
|
tile.color === grid.getTile(x, y).color)));
|
|
803
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* Check if this grid conforms to the given solution, or an incomplete version of the solution.
|
|
806
|
+
* Symbols and rules are not validated.
|
|
807
|
+
*
|
|
808
|
+
* @param solution The solution to compare with.
|
|
809
|
+
* @returns True if the grid conforms to the solution, false otherwise.
|
|
810
|
+
*/
|
|
811
|
+
solutionMatches(solution) {
|
|
812
|
+
if (this.width !== solution.width)
|
|
813
|
+
return false;
|
|
814
|
+
if (this.height !== solution.height)
|
|
815
|
+
return false;
|
|
816
|
+
return this.tiles.every((row, y) => row.every((tile, x) => {
|
|
817
|
+
const solutionTile = solution.getTile(x, y);
|
|
818
|
+
if (!solutionTile.exists)
|
|
819
|
+
return true;
|
|
820
|
+
if (tile.color === Color.Gray)
|
|
821
|
+
return true;
|
|
822
|
+
if (solutionTile.color !== tile.color)
|
|
823
|
+
return false;
|
|
824
|
+
return true;
|
|
825
|
+
}));
|
|
826
|
+
}
|
|
804
827
|
/**
|
|
805
828
|
* Check if this grid is equal to another grid in terms of size, tile colors, connections, symbols, and rules.
|
|
806
829
|
*
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { AnyConfig } from '../config.js';
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
|
-
import { RuleState } from '../primitives.js';
|
|
3
|
+
import { RuleState, Position } from '../primitives.js';
|
|
4
4
|
import Rule, { SearchVariant } from './rule.js';
|
|
5
5
|
export default class ForesightRule extends Rule {
|
|
6
6
|
readonly count: number;
|
|
7
7
|
readonly regenInterval: number;
|
|
8
8
|
readonly startFull: boolean;
|
|
9
|
+
readonly solvePath: Position[];
|
|
9
10
|
private static readonly EXAMPLE_GRID;
|
|
10
11
|
private static readonly CONFIGS;
|
|
11
12
|
private static readonly SEARCH_VARIANTS;
|
|
12
13
|
/**
|
|
13
14
|
* **Foresight: Show hints**
|
|
14
15
|
*/
|
|
15
|
-
constructor(count: number, regenInterval: number, startFull: boolean);
|
|
16
|
+
constructor(count: number, regenInterval: number, startFull: boolean, solvePath?: Position[]);
|
|
16
17
|
get id(): string;
|
|
17
18
|
get explanation(): string;
|
|
18
19
|
get visibleWhenSolving(): boolean;
|
|
@@ -22,10 +23,11 @@ export default class ForesightRule extends Rule {
|
|
|
22
23
|
validateGrid(_grid: GridData): RuleState;
|
|
23
24
|
get necessaryForCompletion(): boolean;
|
|
24
25
|
get isSingleton(): boolean;
|
|
25
|
-
copyWith({ count, regenInterval, startFull, }: {
|
|
26
|
+
copyWith({ count, regenInterval, startFull, solvePath, }: {
|
|
26
27
|
count?: number;
|
|
27
28
|
regenInterval?: number;
|
|
28
29
|
startFull?: boolean;
|
|
30
|
+
solvePath?: Position[];
|
|
29
31
|
}): this;
|
|
30
32
|
}
|
|
31
33
|
export declare const instance: ForesightRule;
|
|
@@ -7,7 +7,7 @@ class ForesightRule extends Rule {
|
|
|
7
7
|
/**
|
|
8
8
|
* **Foresight: Show hints**
|
|
9
9
|
*/
|
|
10
|
-
constructor(count, regenInterval, startFull) {
|
|
10
|
+
constructor(count, regenInterval, startFull, solvePath = []) {
|
|
11
11
|
super();
|
|
12
12
|
Object.defineProperty(this, "count", {
|
|
13
13
|
enumerable: true,
|
|
@@ -27,9 +27,16 @@ class ForesightRule extends Rule {
|
|
|
27
27
|
writable: true,
|
|
28
28
|
value: startFull
|
|
29
29
|
});
|
|
30
|
+
Object.defineProperty(this, "solvePath", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
configurable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
value: solvePath
|
|
35
|
+
});
|
|
30
36
|
this.count = count;
|
|
31
37
|
this.regenInterval = regenInterval;
|
|
32
38
|
this.startFull = startFull;
|
|
39
|
+
this.solvePath = solvePath;
|
|
33
40
|
}
|
|
34
41
|
get id() {
|
|
35
42
|
return `foresight`;
|
|
@@ -58,8 +65,8 @@ class ForesightRule extends Rule {
|
|
|
58
65
|
get isSingleton() {
|
|
59
66
|
return true;
|
|
60
67
|
}
|
|
61
|
-
copyWith({ count, regenInterval, startFull, }) {
|
|
62
|
-
return new ForesightRule(count ?? this.count, regenInterval ?? this.regenInterval, startFull ?? this.startFull);
|
|
68
|
+
copyWith({ count, regenInterval, startFull, solvePath, }) {
|
|
69
|
+
return new ForesightRule(count ?? this.count, regenInterval ?? this.regenInterval, startFull ?? this.startFull, solvePath ?? this.solvePath);
|
|
63
70
|
}
|
|
64
71
|
}
|
|
65
72
|
Object.defineProperty(ForesightRule, "EXAMPLE_GRID", {
|
|
@@ -96,6 +103,13 @@ Object.defineProperty(ForesightRule, "CONFIGS", {
|
|
|
96
103
|
description: 'Start with full foresight',
|
|
97
104
|
configurable: true,
|
|
98
105
|
},
|
|
106
|
+
{
|
|
107
|
+
type: ConfigType.SolvePath,
|
|
108
|
+
default: [],
|
|
109
|
+
field: 'solvePath',
|
|
110
|
+
description: 'Intended solve path',
|
|
111
|
+
configurable: true,
|
|
112
|
+
},
|
|
99
113
|
])
|
|
100
114
|
});
|
|
101
115
|
Object.defineProperty(ForesightRule, "SEARCH_VARIANTS", {
|
|
@@ -24,7 +24,7 @@ export default class MusicGridRule extends Rule implements GridChangeHandler, Se
|
|
|
24
24
|
createExampleGrid(): GridData;
|
|
25
25
|
get searchVariants(): SearchVariant[];
|
|
26
26
|
validateGrid(_grid: GridData): RuleState;
|
|
27
|
-
onSetGrid(_oldGrid: GridData, newGrid: GridData): GridData;
|
|
27
|
+
onSetGrid(_oldGrid: GridData, newGrid: GridData, _solution: GridData | null): GridData;
|
|
28
28
|
onGridChange(newGrid: GridData): this;
|
|
29
29
|
onGridResize(_grid: GridData, mode: 'insert' | 'remove', direction: 'row' | 'column', index: number): this | null;
|
|
30
30
|
/**
|
|
@@ -56,7 +56,7 @@ class MusicGridRule extends Rule {
|
|
|
56
56
|
validateGrid(_grid) {
|
|
57
57
|
return { state: State.Incomplete };
|
|
58
58
|
}
|
|
59
|
-
onSetGrid(_oldGrid, newGrid) {
|
|
59
|
+
onSetGrid(_oldGrid, newGrid, _solution) {
|
|
60
60
|
if (newGrid.getTileCount(true, undefined, Color.Gray) === 0)
|
|
61
61
|
return newGrid;
|
|
62
62
|
const tiles = newGrid.tiles.map(row => row.map(tile => tile.color === Color.Gray ? tile.withColor(Color.Light) : tile));
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AnyConfig } from '../config.js';
|
|
2
|
+
import GridData from '../grid.js';
|
|
3
|
+
import { GridState, RuleState } from '../primitives.js';
|
|
4
|
+
import Rule, { SearchVariant } from './rule.js';
|
|
5
|
+
import { SetGridHandler } from '../events/onSetGrid.js';
|
|
6
|
+
import { FinalValidationHandler } from '../events/onFinalValidation.js';
|
|
7
|
+
export default class PerfectionRule extends Rule implements SetGridHandler, FinalValidationHandler {
|
|
8
|
+
private static readonly EXAMPLE_GRID;
|
|
9
|
+
private static readonly SEARCH_VARIANTS;
|
|
10
|
+
/**
|
|
11
|
+
* **Quest for Perfection: cell colors are final**
|
|
12
|
+
*/
|
|
13
|
+
constructor();
|
|
14
|
+
get id(): string;
|
|
15
|
+
get explanation(): string;
|
|
16
|
+
get configs(): readonly AnyConfig[] | null;
|
|
17
|
+
createExampleGrid(): GridData;
|
|
18
|
+
get searchVariants(): SearchVariant[];
|
|
19
|
+
get necessaryForCompletion(): boolean;
|
|
20
|
+
get isSingleton(): boolean;
|
|
21
|
+
validateGrid(grid: GridData): RuleState;
|
|
22
|
+
/**
|
|
23
|
+
* If the grid passes validation but is different from the solution, indicate the error in the final state.
|
|
24
|
+
*/
|
|
25
|
+
onFinalValidation(grid: GridData, solution: GridData | null, state: GridState): GridState;
|
|
26
|
+
private fixTiles;
|
|
27
|
+
/**
|
|
28
|
+
* Force all tiles to be fixed.
|
|
29
|
+
*
|
|
30
|
+
* If the grid is already wrong, prevent the player from changing it further.
|
|
31
|
+
*/
|
|
32
|
+
onSetGrid(oldGrid: GridData, newGrid: GridData, solution: GridData | null): GridData;
|
|
33
|
+
copyWith(_: object): this;
|
|
34
|
+
}
|
|
35
|
+
export declare const instance: PerfectionRule;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import GridData from '../grid.js';
|
|
2
|
+
import { Color, State } from '../primitives.js';
|
|
3
|
+
import Rule from './rule.js';
|
|
4
|
+
import CustomIconSymbol from '../symbols/customIconSymbol.js';
|
|
5
|
+
class PerfectionRule extends Rule {
|
|
6
|
+
/**
|
|
7
|
+
* **Quest for Perfection: cell colors are final**
|
|
8
|
+
*/
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
}
|
|
12
|
+
get id() {
|
|
13
|
+
return `perfection`;
|
|
14
|
+
}
|
|
15
|
+
get explanation() {
|
|
16
|
+
return `*Quest for Perfection*: cell colors are final`;
|
|
17
|
+
}
|
|
18
|
+
get configs() {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
createExampleGrid() {
|
|
22
|
+
return PerfectionRule.EXAMPLE_GRID;
|
|
23
|
+
}
|
|
24
|
+
get searchVariants() {
|
|
25
|
+
return PerfectionRule.SEARCH_VARIANTS;
|
|
26
|
+
}
|
|
27
|
+
get necessaryForCompletion() {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
get isSingleton() {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
validateGrid(grid) {
|
|
34
|
+
if (grid.getTileCount(true, undefined, Color.Gray) > 0) {
|
|
35
|
+
return { state: State.Incomplete };
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
return { state: State.Satisfied };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* If the grid passes validation but is different from the solution, indicate the error in the final state.
|
|
43
|
+
*/
|
|
44
|
+
onFinalValidation(grid, solution, state) {
|
|
45
|
+
if (state.final === State.Error)
|
|
46
|
+
return state;
|
|
47
|
+
if (solution === null)
|
|
48
|
+
return state;
|
|
49
|
+
const positions = [];
|
|
50
|
+
grid.tiles.forEach((row, y) => row.forEach((t, x) => {
|
|
51
|
+
if (t.exists &&
|
|
52
|
+
t.color !== Color.Gray &&
|
|
53
|
+
t.color !== solution.getTile(x, y).color) {
|
|
54
|
+
positions.push({ x, y });
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
if (positions.length > 0) {
|
|
58
|
+
const ruleId = grid.rules.indexOf(this);
|
|
59
|
+
return {
|
|
60
|
+
final: State.Error,
|
|
61
|
+
rules: state.rules.map((r, idx) => {
|
|
62
|
+
if (idx === ruleId) {
|
|
63
|
+
return { state: State.Error, positions };
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
return r;
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
symbols: state.symbols,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return state;
|
|
73
|
+
}
|
|
74
|
+
fixTiles(grid) {
|
|
75
|
+
if (grid.getTileCount(true, false, Color.Light) > 0 ||
|
|
76
|
+
grid.getTileCount(true, false, Color.Dark) > 0) {
|
|
77
|
+
return grid.withTiles(tiles => tiles.map(row => row.map(t => t.exists && t.color !== Color.Gray ? t.withFixed(true) : t)));
|
|
78
|
+
}
|
|
79
|
+
return grid;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Force all tiles to be fixed.
|
|
83
|
+
*
|
|
84
|
+
* If the grid is already wrong, prevent the player from changing it further.
|
|
85
|
+
*/
|
|
86
|
+
onSetGrid(oldGrid, newGrid, solution) {
|
|
87
|
+
if (!solution) {
|
|
88
|
+
return this.fixTiles(newGrid);
|
|
89
|
+
}
|
|
90
|
+
if (!oldGrid.solutionMatches(solution) &&
|
|
91
|
+
!newGrid.solutionMatches(solution)) {
|
|
92
|
+
return this.fixTiles(oldGrid);
|
|
93
|
+
}
|
|
94
|
+
return this.fixTiles(newGrid);
|
|
95
|
+
}
|
|
96
|
+
copyWith(_) {
|
|
97
|
+
return new PerfectionRule();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
Object.defineProperty(PerfectionRule, "EXAMPLE_GRID", {
|
|
101
|
+
enumerable: true,
|
|
102
|
+
configurable: true,
|
|
103
|
+
writable: true,
|
|
104
|
+
value: Object.freeze(GridData.create(['w']).addSymbol(new CustomIconSymbol('', GridData.create(['w']), 0, 0, 'MdStars')))
|
|
105
|
+
});
|
|
106
|
+
Object.defineProperty(PerfectionRule, "SEARCH_VARIANTS", {
|
|
107
|
+
enumerable: true,
|
|
108
|
+
configurable: true,
|
|
109
|
+
writable: true,
|
|
110
|
+
value: []
|
|
111
|
+
}); // this rule is not searchable
|
|
112
|
+
export default PerfectionRule;
|
|
113
|
+
export const instance = new PerfectionRule();
|
|
@@ -7,6 +7,7 @@ export { instance as ForesightRule } from './foresightRule.js';
|
|
|
7
7
|
export { instance as MusicGridRule } from './musicGridRule.js';
|
|
8
8
|
export { instance as MysteryRule } from './mysteryRule.js';
|
|
9
9
|
export { instance as OffByXRule } from './offByXRule.js';
|
|
10
|
+
export { instance as PerfectionRule } from './perfectionRule.js';
|
|
10
11
|
export { instance as RegionAreaRule } from './regionAreaRule.js';
|
|
11
12
|
export { instance as SameShapeRule } from './sameShapeRule.js';
|
|
12
13
|
export { instance as SymbolsPerRegionRule } from './symbolsPerRegionRule.js';
|
|
@@ -11,6 +11,7 @@ export { instance as ForesightRule } from './foresightRule.js';
|
|
|
11
11
|
export { instance as MusicGridRule } from './musicGridRule.js';
|
|
12
12
|
export { instance as MysteryRule } from './mysteryRule.js';
|
|
13
13
|
export { instance as OffByXRule } from './offByXRule.js';
|
|
14
|
+
export { instance as PerfectionRule } from './perfectionRule.js';
|
|
14
15
|
export { instance as RegionAreaRule } from './regionAreaRule.js';
|
|
15
16
|
export { instance as SameShapeRule } from './sameShapeRule.js';
|
|
16
17
|
export { instance as SymbolsPerRegionRule } from './symbolsPerRegionRule.js';
|
|
@@ -161,6 +161,12 @@ export default class SerializerV0 extends SerializerBase {
|
|
|
161
161
|
escape(instruction[config.field]
|
|
162
162
|
.map(line => this.stringifyControlLine(line))
|
|
163
163
|
.join(':')));
|
|
164
|
+
case ConfigType.SolvePath:
|
|
165
|
+
return (config.field +
|
|
166
|
+
'=' +
|
|
167
|
+
escape(instruction[config.field]
|
|
168
|
+
?.map(pos => `${pos.x}_${pos.y}`)
|
|
169
|
+
.join('/') ?? ''));
|
|
164
170
|
}
|
|
165
171
|
}
|
|
166
172
|
parseConfig(configs, entry) {
|
|
@@ -219,6 +225,16 @@ export default class SerializerV0 extends SerializerBase {
|
|
|
219
225
|
];
|
|
220
226
|
case ConfigType.NullableNote:
|
|
221
227
|
return [config.field, value === '' ? null : unescape(value)];
|
|
228
|
+
case ConfigType.SolvePath:
|
|
229
|
+
return [
|
|
230
|
+
config.field,
|
|
231
|
+
value === ''
|
|
232
|
+
? []
|
|
233
|
+
: value.split('/').map(pos => {
|
|
234
|
+
const [x, y] = pos.split('_');
|
|
235
|
+
return { x: Number(x), y: Number(y) };
|
|
236
|
+
}),
|
|
237
|
+
];
|
|
222
238
|
}
|
|
223
239
|
}
|
|
224
240
|
stringifyInstruction(instruction) {
|
|
@@ -4,6 +4,8 @@ import BTModule, { BTGridData, CheckResult } from '../data.js';
|
|
|
4
4
|
export default abstract class DirectionLinkerBTModule extends BTModule {
|
|
5
5
|
instr: DirectionLinkerSymbol;
|
|
6
6
|
constructor(instr: DirectionLinkerSymbol);
|
|
7
|
+
private initialPositions;
|
|
8
|
+
private getInitialPositions;
|
|
7
9
|
checkGlobal(grid: BTGridData): CheckResult | false;
|
|
8
10
|
protected abstract movePos(grid: BTGridData, x: number, y: number): Position | null;
|
|
9
11
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import BTModule, { BTTile, IntArray2D,
|
|
1
|
+
import BTModule, { BTTile, IntArray2D, } from '../data.js';
|
|
2
2
|
export default class DirectionLinkerBTModule extends BTModule {
|
|
3
3
|
constructor(instr) {
|
|
4
4
|
super();
|
|
@@ -8,31 +8,108 @@ export default class DirectionLinkerBTModule extends BTModule {
|
|
|
8
8
|
writable: true,
|
|
9
9
|
value: void 0
|
|
10
10
|
});
|
|
11
|
+
Object.defineProperty(this, "initialPositions", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: null
|
|
16
|
+
});
|
|
11
17
|
this.instr = instr;
|
|
12
18
|
}
|
|
19
|
+
getInitialPositions() {
|
|
20
|
+
if (this.instr.x % 1 !== 0 && this.instr.y % 1 !== 0)
|
|
21
|
+
return [
|
|
22
|
+
{ x: Math.floor(this.instr.x), y: Math.floor(this.instr.y) },
|
|
23
|
+
{ x: Math.ceil(this.instr.x), y: Math.ceil(this.instr.y) },
|
|
24
|
+
{ x: Math.floor(this.instr.x), y: Math.ceil(this.instr.y) },
|
|
25
|
+
{ x: Math.ceil(this.instr.x), y: Math.floor(this.instr.y) },
|
|
26
|
+
];
|
|
27
|
+
else if (this.instr.x % 1 !== 0)
|
|
28
|
+
return [
|
|
29
|
+
{ x: Math.floor(this.instr.x), y: this.instr.y },
|
|
30
|
+
{ x: Math.ceil(this.instr.x), y: this.instr.y },
|
|
31
|
+
];
|
|
32
|
+
else if (this.instr.y % 1 !== 0)
|
|
33
|
+
return [
|
|
34
|
+
{ x: this.instr.x, y: Math.floor(this.instr.y) },
|
|
35
|
+
{ x: this.instr.x, y: Math.ceil(this.instr.y) },
|
|
36
|
+
];
|
|
37
|
+
else
|
|
38
|
+
return [{ x: this.instr.x, y: this.instr.y }];
|
|
39
|
+
}
|
|
13
40
|
checkGlobal(grid) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const tile = grid.getTile(thisX, thisY);
|
|
17
|
-
if (tile === BTTile.Empty)
|
|
18
|
-
return createOneTileResult(grid, { x: thisX, y: thisY });
|
|
41
|
+
if (this.initialPositions === null)
|
|
42
|
+
this.initialPositions = this.getInitialPositions();
|
|
19
43
|
const tilesNeedCheck = IntArray2D.create(grid.width, grid.height);
|
|
20
44
|
const ratings = [];
|
|
21
|
-
|
|
45
|
+
let checkable = false;
|
|
46
|
+
for (const pos of this.initialPositions) {
|
|
47
|
+
const tile = grid.isInBound(pos.x, pos.y)
|
|
48
|
+
? grid.getTile(pos.x, pos.y)
|
|
49
|
+
: BTTile.NonExist;
|
|
50
|
+
if (tile === BTTile.Empty) {
|
|
51
|
+
const oppoPos = this.movePos(grid, pos.x, pos.y);
|
|
52
|
+
if (oppoPos === null ||
|
|
53
|
+
grid.getTile(oppoPos.x, oppoPos.y) === BTTile.NonExist)
|
|
54
|
+
return false;
|
|
55
|
+
else {
|
|
56
|
+
tilesNeedCheck.set(pos.x, pos.y, 1);
|
|
57
|
+
ratings.push({ pos, score: 1 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (tile === BTTile.NonExist) {
|
|
61
|
+
const oppoPos = this.movePos(grid, pos.x, pos.y);
|
|
62
|
+
if (oppoPos !== null &&
|
|
63
|
+
grid.getTile(oppoPos.x, oppoPos.y) !== BTTile.NonExist) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const oppoPos = this.movePos(grid, pos.x, pos.y);
|
|
69
|
+
if (oppoPos !== null) {
|
|
70
|
+
const oppoTile = grid.getTile(oppoPos.x, oppoPos.y);
|
|
71
|
+
if (oppoTile === BTTile.Empty) {
|
|
72
|
+
tilesNeedCheck.set(pos.x, pos.y, 1);
|
|
73
|
+
ratings.push({ pos, score: 1 });
|
|
74
|
+
}
|
|
75
|
+
else if (oppoTile === BTTile.NonExist)
|
|
76
|
+
return false;
|
|
77
|
+
else
|
|
78
|
+
checkable = true;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!checkable) {
|
|
86
|
+
return { tilesNeedCheck, ratings };
|
|
87
|
+
}
|
|
88
|
+
const queue = this.initialPositions
|
|
89
|
+
.filter(pos => grid.isInBound(pos.x, pos.y) &&
|
|
90
|
+
grid.getTile(pos.x, pos.y) !== BTTile.NonExist)
|
|
91
|
+
.map(pos => {
|
|
92
|
+
const oppoPos = this.movePos(grid, pos.x, pos.y);
|
|
93
|
+
return {
|
|
94
|
+
pos,
|
|
95
|
+
color: grid.getTile(pos.x, pos.y),
|
|
96
|
+
oppoColor: grid.getTile(oppoPos.x, oppoPos.y),
|
|
97
|
+
};
|
|
98
|
+
});
|
|
22
99
|
const visited = IntArray2D.create(grid.width, grid.height);
|
|
23
100
|
// Visit all connected tiles
|
|
24
101
|
while (queue.length > 0) {
|
|
25
102
|
const curPos = queue.pop();
|
|
26
|
-
if (visited.get(curPos.x, curPos.y))
|
|
103
|
+
if (visited.get(curPos.pos.x, curPos.pos.y))
|
|
27
104
|
continue;
|
|
28
|
-
visited.set(curPos.x, curPos.y, 1);
|
|
29
|
-
const oppoPos = this.movePos(grid, curPos.x, curPos.y);
|
|
105
|
+
visited.set(curPos.pos.x, curPos.pos.y, 1);
|
|
106
|
+
const oppoPos = this.movePos(grid, curPos.pos.x, curPos.pos.y);
|
|
30
107
|
if (oppoPos === null)
|
|
31
108
|
return false;
|
|
32
109
|
const oppoTile = grid.getTile(oppoPos.x, oppoPos.y);
|
|
33
|
-
if (!(oppoTile === BTTile.Empty || oppoTile ===
|
|
110
|
+
if (!(oppoTile === BTTile.Empty || oppoTile === curPos.oppoColor))
|
|
34
111
|
return false;
|
|
35
|
-
for (const edge of grid.getEdges(curPos)) {
|
|
112
|
+
for (const edge of grid.getEdges(curPos.pos)) {
|
|
36
113
|
if (visited.get(edge.x, edge.y))
|
|
37
114
|
continue;
|
|
38
115
|
const edgeTile = grid.getTile(edge.x, edge.y);
|
|
@@ -40,8 +117,12 @@ export default class DirectionLinkerBTModule extends BTModule {
|
|
|
40
117
|
tilesNeedCheck.set(edge.x, edge.y, 1);
|
|
41
118
|
ratings.push({ pos: edge, score: 1 });
|
|
42
119
|
}
|
|
43
|
-
else if (edgeTile ===
|
|
44
|
-
queue.push(
|
|
120
|
+
else if (edgeTile === curPos.color) {
|
|
121
|
+
queue.push({
|
|
122
|
+
pos: edge,
|
|
123
|
+
color: curPos.color,
|
|
124
|
+
oppoColor: curPos.oppoColor,
|
|
125
|
+
});
|
|
45
126
|
}
|
|
46
127
|
}
|
|
47
128
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Position } from '../../../primitives.js';
|
|
2
2
|
import LotusSymbol from '../../../symbols/lotusSymbol.js';
|
|
3
|
-
import { BTGridData } from '../data.js';
|
|
3
|
+
import { BTGridData, CheckResult } from '../data.js';
|
|
4
4
|
import DirectionLinkerBTModule from './directionLinker.js';
|
|
5
5
|
export default class LotusBTModule extends DirectionLinkerBTModule {
|
|
6
6
|
instr: LotusSymbol;
|
|
7
7
|
constructor(instr: LotusSymbol);
|
|
8
8
|
protected movePos(grid: BTGridData, x: number, y: number): Position | null;
|
|
9
|
+
private getTileSafe;
|
|
10
|
+
checkGlobal(grid: BTGridData): false | CheckResult;
|
|
9
11
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Orientation } from '../../../primitives.js';
|
|
2
|
+
import { BTTile } from '../data.js';
|
|
2
3
|
import DirectionLinkerBTModule from './directionLinker.js';
|
|
3
4
|
export default class LotusBTModule extends DirectionLinkerBTModule {
|
|
4
5
|
constructor(instr) {
|
|
@@ -33,4 +34,27 @@ export default class LotusBTModule extends DirectionLinkerBTModule {
|
|
|
33
34
|
}
|
|
34
35
|
return grid.isInBound(pos.x, pos.y) ? pos : null;
|
|
35
36
|
}
|
|
37
|
+
getTileSafe(grid, x, y) {
|
|
38
|
+
return grid.isInBound(x, y) ? grid.getTile(x, y) : BTTile.NonExist;
|
|
39
|
+
}
|
|
40
|
+
checkGlobal(grid) {
|
|
41
|
+
if (this.instr.orientation === Orientation.DownLeft ||
|
|
42
|
+
this.instr.orientation === Orientation.DownRight ||
|
|
43
|
+
this.instr.orientation === Orientation.UpLeft ||
|
|
44
|
+
this.instr.orientation === Orientation.UpRight) {
|
|
45
|
+
if (this.instr.x % 1 === 0 || this.instr.y % 1 === 0)
|
|
46
|
+
if (this.instr.x % 1 !== 0 || this.instr.y % 1 !== 0) {
|
|
47
|
+
if (this.getTileSafe(grid, Math.floor(this.instr.x), Math.floor(this.instr.y)) === BTTile.NonExist &&
|
|
48
|
+
this.getTileSafe(grid, Math.ceil(this.instr.x), Math.ceil(this.instr.y)) === BTTile.NonExist &&
|
|
49
|
+
this.getTileSafe(grid, Math.floor(this.instr.x), Math.ceil(this.instr.y)) === BTTile.NonExist &&
|
|
50
|
+
this.getTileSafe(grid, Math.ceil(this.instr.x), Math.floor(this.instr.y)) === BTTile.NonExist) {
|
|
51
|
+
return { tilesNeedCheck: null, ratings: null };
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return super.checkGlobal(grid);
|
|
59
|
+
}
|
|
36
60
|
}
|
|
@@ -24,7 +24,6 @@ export default class DirectionLinkerSymbol extends Symbol {
|
|
|
24
24
|
get explanation(): string;
|
|
25
25
|
get configs(): readonly AnyConfig[] | null;
|
|
26
26
|
createExampleGrid(): GridData;
|
|
27
|
-
private getColor;
|
|
28
27
|
private deltaCoordinate;
|
|
29
28
|
validateSymbol(grid: GridData): State;
|
|
30
29
|
copyWith({ x, y }: {
|
|
@@ -2,6 +2,20 @@ import { ConfigType } from '../config.js';
|
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
3
|
import { Color, Direction, State } from '../primitives.js';
|
|
4
4
|
import Symbol from './symbol.js';
|
|
5
|
+
function getColor(c, grid) {
|
|
6
|
+
if (!grid.isPositionValid(c.x, c.y) || !grid.getTile(c.x, c.y).exists) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
return grid.getTile(c.x, c.y).color;
|
|
10
|
+
}
|
|
11
|
+
function makeTurtle(pos1, pos2, grid) {
|
|
12
|
+
return {
|
|
13
|
+
pos1,
|
|
14
|
+
color1: getColor(pos1, grid),
|
|
15
|
+
pos2,
|
|
16
|
+
color2: getColor(pos2, grid),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
5
19
|
class DirectionLinkerSymbol extends Symbol {
|
|
6
20
|
/**
|
|
7
21
|
* **Darts count opposite color cells in that direction**
|
|
@@ -51,12 +65,6 @@ class DirectionLinkerSymbol extends Symbol {
|
|
|
51
65
|
createExampleGrid() {
|
|
52
66
|
return DirectionLinkerSymbol.EXAMPLE_GRID;
|
|
53
67
|
}
|
|
54
|
-
getColor(c, grid) {
|
|
55
|
-
if (!grid.isPositionValid(c.x, c.y) || !grid.getTile(c.x, c.y).exists) {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
return grid.getTile(c.x, c.y).color;
|
|
59
|
-
}
|
|
60
68
|
deltaCoordinate(c, direction) {
|
|
61
69
|
return {
|
|
62
70
|
x: c.x + DirectionLinkerSymbol.directionDeltas[direction].dx,
|
|
@@ -73,49 +81,56 @@ class DirectionLinkerSymbol extends Symbol {
|
|
|
73
81
|
// If the color of both are the opposite of the turtle, the turtle doesn't fire any other turtle
|
|
74
82
|
// If no turtle remains, go to final state
|
|
75
83
|
// Final state is State.Satisfied if no gray cell is found, State.Incomplete otherwise
|
|
76
|
-
|
|
77
|
-
if (
|
|
84
|
+
let checkedCouples = this.getInitialCheckedCouples(this.x, this.y, grid);
|
|
85
|
+
if (checkedCouples.some(({ color1, color2 }) => (color1 === null && color2 !== null) ||
|
|
86
|
+
(color1 !== null && color2 === null))) {
|
|
87
|
+
return State.Error;
|
|
88
|
+
}
|
|
89
|
+
if (checkedCouples.some(({ color1, color2 }) => color1 === Color.Gray || color2 === Color.Gray)) {
|
|
78
90
|
return State.Incomplete;
|
|
79
91
|
}
|
|
80
|
-
|
|
81
|
-
const queue = checkedCouples.
|
|
82
|
-
{ ...p1 },
|
|
83
|
-
{ ...p2 },
|
|
84
|
-
]);
|
|
92
|
+
checkedCouples = checkedCouples.filter(({ color1, color2 }) => color1 !== null && color2 !== null);
|
|
93
|
+
const queue = checkedCouples.slice();
|
|
85
94
|
let grayFound = false;
|
|
86
95
|
while (queue.length > 0) {
|
|
87
96
|
const turtle = queue.shift();
|
|
88
|
-
const
|
|
89
|
-
const color1 =
|
|
90
|
-
const color2 =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
colorSet.delete(null);
|
|
97
|
+
const { pos1, pos2, color1: baseColor1, color2: baseColor2 } = turtle;
|
|
98
|
+
const color1 = getColor(pos1, grid);
|
|
99
|
+
const color2 = getColor(pos2, grid);
|
|
100
|
+
if (color1 === Color.Gray || color2 === Color.Gray) {
|
|
101
|
+
grayFound = true;
|
|
94
102
|
}
|
|
95
|
-
if (
|
|
96
|
-
|
|
103
|
+
else if (color1 === null || color2 === null) {
|
|
104
|
+
if ((color1 === null && color2 === baseColor2) ||
|
|
105
|
+
(color2 === null && color1 === baseColor1)) {
|
|
106
|
+
return State.Error;
|
|
107
|
+
}
|
|
97
108
|
}
|
|
98
|
-
if (
|
|
99
|
-
|
|
109
|
+
else if (color1 !== baseColor1 || color2 !== baseColor2) {
|
|
110
|
+
if (color1 === baseColor1 || color2 === baseColor2) {
|
|
111
|
+
return State.Error;
|
|
112
|
+
}
|
|
100
113
|
}
|
|
101
|
-
if (color1 ===
|
|
114
|
+
if (color1 === baseColor1) {
|
|
102
115
|
const directions = Object.keys(this.linkedDirections);
|
|
103
116
|
for (const direction of directions) {
|
|
104
|
-
const newTurtle =
|
|
105
|
-
this.deltaCoordinate(
|
|
106
|
-
this.deltaCoordinate(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
const newTurtle = {
|
|
118
|
+
pos1: this.deltaCoordinate(pos1, direction),
|
|
119
|
+
pos2: this.deltaCoordinate(pos2, this.linkedDirections[direction]),
|
|
120
|
+
color1: baseColor1,
|
|
121
|
+
color2: baseColor2,
|
|
122
|
+
};
|
|
123
|
+
if (checkedCouples.some(({ pos1, pos2 }) => pos1.x === newTurtle.pos1.x &&
|
|
124
|
+
pos1.y === newTurtle.pos1.y &&
|
|
125
|
+
pos2.x === newTurtle.pos2.x &&
|
|
126
|
+
pos2.y === newTurtle.pos2.y) ||
|
|
127
|
+
(pos1.x === newTurtle.pos2.x &&
|
|
128
|
+
pos1.y === newTurtle.pos2.y &&
|
|
129
|
+
pos2.x === newTurtle.pos1.x &&
|
|
130
|
+
pos2.y === newTurtle.pos1.y)) {
|
|
116
131
|
continue;
|
|
117
132
|
}
|
|
118
|
-
checkedCouples.push(
|
|
133
|
+
checkedCouples.push(newTurtle);
|
|
119
134
|
queue.push(newTurtle);
|
|
120
135
|
}
|
|
121
136
|
}
|
|
@@ -125,73 +140,50 @@ class DirectionLinkerSymbol extends Symbol {
|
|
|
125
140
|
copyWith({ x, y }) {
|
|
126
141
|
return new DirectionLinkerSymbol(x ?? this.x, y ?? this.y);
|
|
127
142
|
}
|
|
128
|
-
getInitialCheckedCouples(x, y) {
|
|
143
|
+
getInitialCheckedCouples(x, y, grid) {
|
|
129
144
|
// 1x1
|
|
130
145
|
if (x % 1 === 0 && y % 1 === 0) {
|
|
131
|
-
return [
|
|
132
|
-
[
|
|
133
|
-
{ x, y },
|
|
134
|
-
{ x, y },
|
|
135
|
-
],
|
|
136
|
-
];
|
|
146
|
+
return [makeTurtle({ x, y }, { x, y }, grid)];
|
|
137
147
|
}
|
|
138
148
|
// 1x2
|
|
139
149
|
if (x % 1 === 0) {
|
|
140
150
|
return [
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
: 0.5),
|
|
150
|
-
},
|
|
151
|
-
],
|
|
151
|
+
makeTurtle({ x, y: y - 0.5 }, {
|
|
152
|
+
x,
|
|
153
|
+
y: y +
|
|
154
|
+
(this.linkedDirections[Direction.Up] === Direction.Up &&
|
|
155
|
+
this.linkedDirections[Direction.Down] === Direction.Down
|
|
156
|
+
? -0.5
|
|
157
|
+
: 0.5),
|
|
158
|
+
}, grid),
|
|
152
159
|
];
|
|
153
160
|
}
|
|
154
161
|
// 2x1
|
|
155
162
|
if (y % 1 === 0) {
|
|
156
163
|
return [
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
y,
|
|
166
|
-
},
|
|
167
|
-
],
|
|
164
|
+
makeTurtle({ x: x - 0.5, y }, {
|
|
165
|
+
x: x +
|
|
166
|
+
(this.linkedDirections[Direction.Left] === Direction.Left &&
|
|
167
|
+
this.linkedDirections[Direction.Right] === Direction.Right
|
|
168
|
+
? -0.5
|
|
169
|
+
: 0.5),
|
|
170
|
+
y,
|
|
171
|
+
}, grid),
|
|
168
172
|
];
|
|
169
173
|
}
|
|
170
174
|
// 2x2
|
|
171
175
|
if (this.linkedDirections[Direction.Left] === Direction.Left &&
|
|
172
176
|
this.linkedDirections[Direction.Right] === Direction.Right) {
|
|
173
177
|
return [
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
{ x: x - 0.5, y: y + 0.5 },
|
|
177
|
-
],
|
|
178
|
-
[
|
|
179
|
-
{ x: x + 0.5, y: y - 0.5 },
|
|
180
|
-
{ x: x + 0.5, y: y + 0.5 },
|
|
181
|
-
],
|
|
178
|
+
makeTurtle({ x: x - 0.5, y: y - 0.5 }, { x: x - 0.5, y: y + 0.5 }, grid),
|
|
179
|
+
makeTurtle({ x: x + 0.5, y: y - 0.5 }, { x: x + 0.5, y: y + 0.5 }, grid),
|
|
182
180
|
];
|
|
183
181
|
}
|
|
184
182
|
if (this.linkedDirections[Direction.Up] === Direction.Up &&
|
|
185
183
|
this.linkedDirections[Direction.Down] === Direction.Down) {
|
|
186
184
|
return [
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
{ x: x + 0.5, y: y - 0.5 },
|
|
190
|
-
],
|
|
191
|
-
[
|
|
192
|
-
{ x: x - 0.5, y: y + 0.5 },
|
|
193
|
-
{ x: x + 0.5, y: y + 0.5 },
|
|
194
|
-
],
|
|
185
|
+
makeTurtle({ x: x - 0.5, y: y - 0.5 }, { x: x + 0.5, y: y - 0.5 }, grid),
|
|
186
|
+
makeTurtle({ x: x - 0.5, y: y + 0.5 }, { x: x + 0.5, y: y + 0.5 }, grid),
|
|
195
187
|
];
|
|
196
188
|
}
|
|
197
189
|
else if ((this.linkedDirections[Direction.Up] === Direction.Left &&
|
|
@@ -199,21 +191,12 @@ class DirectionLinkerSymbol extends Symbol {
|
|
|
199
191
|
(this.linkedDirections[Direction.Up] === Direction.Right &&
|
|
200
192
|
this.linkedDirections[Direction.Right] === Direction.Up)) {
|
|
201
193
|
return [
|
|
202
|
-
|
|
203
|
-
{ x: x - 0.5, y: y - 0.5 },
|
|
204
|
-
{ x: x - 0.5, y: y - 0.5 },
|
|
205
|
-
],
|
|
194
|
+
makeTurtle({ x: x - 0.5, y: y - 0.5 }, { x: x - 0.5, y: y - 0.5 }, grid),
|
|
206
195
|
];
|
|
207
196
|
}
|
|
208
197
|
return [
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
{ x: x + 0.5, y: y + 0.5 },
|
|
212
|
-
],
|
|
213
|
-
[
|
|
214
|
-
{ x: x - 0.5, y: y + 0.5 },
|
|
215
|
-
{ x: x + 0.5, y: y - 0.5 },
|
|
216
|
-
],
|
|
198
|
+
makeTurtle({ x: x - 0.5, y: y - 0.5 }, { x: x + 0.5, y: y + 0.5 }, grid),
|
|
199
|
+
makeTurtle({ x: x - 0.5, y: y + 0.5 }, { x: x + 0.5, y: y - 0.5 }, grid),
|
|
217
200
|
];
|
|
218
201
|
}
|
|
219
202
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConfigType } from '../config.js';
|
|
2
2
|
import GridData from '../grid.js';
|
|
3
|
-
import { Direction, Orientation } from '../primitives.js';
|
|
3
|
+
import { Direction, Orientation, State } from '../primitives.js';
|
|
4
4
|
import DirectionLinkerSymbol from './directionLinkerSymbol.js';
|
|
5
5
|
class LotusSymbol extends DirectionLinkerSymbol {
|
|
6
6
|
/**
|
|
@@ -67,6 +67,23 @@ class LotusSymbol extends DirectionLinkerSymbol {
|
|
|
67
67
|
return Object.freeze(GridData.create(['wwbww', 'bwbwb', 'bwwwb', 'bwwwb']).addSymbol(new LotusSymbol(2, 2, Orientation.Up)));
|
|
68
68
|
}
|
|
69
69
|
validateSymbol(grid) {
|
|
70
|
+
if (this.orientation === Orientation.DownLeft ||
|
|
71
|
+
this.orientation === Orientation.DownRight ||
|
|
72
|
+
this.orientation === Orientation.UpLeft ||
|
|
73
|
+
this.orientation === Orientation.UpRight) {
|
|
74
|
+
if (this.x % 1 === 0 || this.y % 1 === 0)
|
|
75
|
+
if (this.x % 1 !== 0 || this.y % 1 !== 0) {
|
|
76
|
+
if (!grid.getTile(Math.floor(this.x), Math.floor(this.y)).exists &&
|
|
77
|
+
!grid.getTile(Math.ceil(this.x), Math.ceil(this.y)).exists &&
|
|
78
|
+
!grid.getTile(Math.floor(this.x), Math.ceil(this.y)).exists &&
|
|
79
|
+
!grid.getTile(Math.ceil(this.x), Math.floor(this.y)).exists) {
|
|
80
|
+
return State.Satisfied;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
return State.Error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
70
87
|
return super.validateSymbol(grid);
|
|
71
88
|
}
|
|
72
89
|
copyWith({ x, y, orientation, }) {
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { ControlLine, Row } from './data/rules/musicControlLine.js';
|
|
|
24
24
|
import MusicGridRule from './data/rules/musicGridRule.js';
|
|
25
25
|
import MysteryRule from './data/rules/mysteryRule.js';
|
|
26
26
|
import OffByXRule from './data/rules/offByXRule.js';
|
|
27
|
+
import PerfectionRule from './data/rules/perfectionRule.js';
|
|
27
28
|
import RegionAreaRule from './data/rules/regionAreaRule.js';
|
|
28
29
|
import RegionShapeRule from './data/rules/regionShapeRule.js';
|
|
29
30
|
import Rule from './data/rules/rule.js';
|
|
@@ -95,4 +96,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
95
96
|
import TileData from './data/tile.js';
|
|
96
97
|
import TileConnections from './data/tileConnections.js';
|
|
97
98
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
98
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, GridConnections, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, 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, };
|
|
99
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, GridConnections, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, 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
|
@@ -27,6 +27,7 @@ import { ControlLine, Row } from './data/rules/musicControlLine.js';
|
|
|
27
27
|
import MusicGridRule from './data/rules/musicGridRule.js';
|
|
28
28
|
import MysteryRule from './data/rules/mysteryRule.js';
|
|
29
29
|
import OffByXRule from './data/rules/offByXRule.js';
|
|
30
|
+
import PerfectionRule from './data/rules/perfectionRule.js';
|
|
30
31
|
import RegionAreaRule from './data/rules/regionAreaRule.js';
|
|
31
32
|
import RegionShapeRule from './data/rules/regionShapeRule.js';
|
|
32
33
|
import Rule from './data/rules/rule.js';
|
|
@@ -98,4 +99,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
|
|
|
98
99
|
import TileData from './data/tile.js';
|
|
99
100
|
import TileConnections from './data/tileConnections.js';
|
|
100
101
|
import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
|
|
101
|
-
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, GridConnections, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, 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, };
|
|
102
|
+
export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, GridConnections, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, 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, };
|