@logic-pad/core 0.6.1 → 0.9.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 +134 -11
- package/dist/data/config.d.ts +6 -2
- package/dist/data/config.js +1 -0
- package/dist/data/events/onGetTile.d.ts +7 -0
- package/dist/data/events/onGetTile.js +4 -0
- package/dist/data/grid.d.ts +9 -3
- package/dist/data/grid.js +50 -10
- package/dist/data/primitives.d.ts +9 -1
- package/dist/data/primitives.js +14 -0
- package/dist/data/rules/banPatternRule.js +11 -6
- package/dist/data/rules/cellCountPerZoneRule.js +9 -7
- package/dist/data/rules/regionShapeRule.js +7 -3
- package/dist/data/rules/rules.gen.d.ts +1 -0
- package/dist/data/rules/rules.gen.js +1 -0
- package/dist/data/rules/wrapAroundRule.d.ts +34 -0
- package/dist/data/rules/wrapAroundRule.js +271 -0
- package/dist/data/serializer/serializer_v0.js +3 -0
- package/dist/data/solver/backtrack/backtrackSolver.d.ts +1 -0
- package/dist/data/solver/backtrack/backtrackSolver.js +8 -0
- package/dist/data/solver/backtrack/backtrackWorker.js +11 -0
- package/dist/data/solver/backtrack/symbols/focus.d.ts +9 -0
- package/dist/data/solver/backtrack/symbols/focus.js +59 -0
- package/dist/data/solver/eventIteratingSolver.d.ts +3 -2
- package/dist/data/solver/eventIteratingSolver.js +13 -2
- package/dist/data/solver/solver.d.ts +11 -6
- package/dist/data/solver/universal/universalSolver.d.ts +1 -0
- package/dist/data/solver/universal/universalSolver.js +6 -0
- package/dist/data/solver/universal/universalWorker.js +5 -0
- package/dist/data/solver/z3/z3Solver.d.ts +2 -0
- package/dist/data/solver/z3/z3Solver.js +12 -0
- package/dist/data/symbols/directionLinkerSymbol.js +15 -9
- package/dist/data/symbols/focusSymbol.d.ts +30 -0
- package/dist/data/symbols/focusSymbol.js +110 -0
- package/dist/data/symbols/minesweeperSymbol.d.ts +1 -1
- package/dist/data/symbols/minesweeperSymbol.js +9 -2
- package/dist/data/symbols/symbols.gen.d.ts +1 -0
- package/dist/data/symbols/symbols.gen.js +1 -0
- package/dist/data/symbols/viewpointSymbol.js +10 -11
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/package.json +1 -1
|
@@ -29,6 +29,7 @@ declare global {
|
|
|
29
29
|
MusicGrid = 'music',
|
|
30
30
|
CompletePattern = 'complete_pattern',
|
|
31
31
|
Underclued = 'underclued',
|
|
32
|
+
WrapAround = 'wrap_around',
|
|
32
33
|
}
|
|
33
34
|
export declare enum State {
|
|
34
35
|
/**
|
|
@@ -81,6 +82,13 @@ declare global {
|
|
|
81
82
|
AtMost = 'le',
|
|
82
83
|
}
|
|
83
84
|
export declare const COMPARISONS: readonly Comparison[];
|
|
85
|
+
export declare enum Wrapping {
|
|
86
|
+
None = 'none',
|
|
87
|
+
Wrap = 'wrap',
|
|
88
|
+
WrapReverse = 'wrap-reverse',
|
|
89
|
+
ReflectReverse = 'reflect-reverse',
|
|
90
|
+
}
|
|
91
|
+
export declare const WRAPPINGS: readonly Wrapping[];
|
|
84
92
|
export declare enum Direction {
|
|
85
93
|
Up = 'up',
|
|
86
94
|
Down = 'down',
|
|
@@ -632,6 +640,43 @@ declare global {
|
|
|
632
640
|
get validateWithSolution(): boolean;
|
|
633
641
|
get isSingleton(): boolean;
|
|
634
642
|
}
|
|
643
|
+
export interface GetTileHandler {
|
|
644
|
+
onGetTile(x: number, y: number, grid: GridData): Position$1;
|
|
645
|
+
}
|
|
646
|
+
export declare function handlesGetTile<T extends Instruction>(
|
|
647
|
+
val: T
|
|
648
|
+
): val is T & GetTileHandler;
|
|
649
|
+
export declare class WrapAroundRule extends Rule implements GetTileHandler {
|
|
650
|
+
readonly horizontal: Wrapping;
|
|
651
|
+
readonly vertical: Wrapping;
|
|
652
|
+
private static readonly EXAMPLE_GRID_NONE;
|
|
653
|
+
private static readonly EXAMPLE_GRID_HORIZONTAL;
|
|
654
|
+
private static readonly EXAMPLE_GRID_VERTICAL;
|
|
655
|
+
private static readonly SEARCH_VARIANTS;
|
|
656
|
+
private static readonly CONFIGS;
|
|
657
|
+
/**
|
|
658
|
+
* **The left and right edges are connected (in reverse)**
|
|
659
|
+
*
|
|
660
|
+
* @param horizontal - The horizontal wrapping.
|
|
661
|
+
* @param vertical - The vertical wrapping.
|
|
662
|
+
*/
|
|
663
|
+
constructor(horizontal: Wrapping, vertical: Wrapping);
|
|
664
|
+
onGetTile(x: number, y: number, grid: GridData): Position$1;
|
|
665
|
+
get id(): string;
|
|
666
|
+
get explanation(): string;
|
|
667
|
+
createExampleGrid(): GridData;
|
|
668
|
+
get configs(): readonly AnyConfig[] | null;
|
|
669
|
+
get searchVariants(): SearchVariant[];
|
|
670
|
+
validateGrid(grid: GridData): RuleState;
|
|
671
|
+
copyWith({
|
|
672
|
+
horizontal,
|
|
673
|
+
vertical,
|
|
674
|
+
}: {
|
|
675
|
+
horizontal?: Wrapping;
|
|
676
|
+
vertical?: Wrapping;
|
|
677
|
+
}): this;
|
|
678
|
+
get isSingleton(): boolean;
|
|
679
|
+
}
|
|
635
680
|
export declare const NEIGHBOR_OFFSETS: Position$1[];
|
|
636
681
|
export declare class GridData {
|
|
637
682
|
readonly width: number;
|
|
@@ -644,6 +689,7 @@ declare global {
|
|
|
644
689
|
readonly musicGrid: CachedAccess<MusicGridRule | undefined>;
|
|
645
690
|
readonly completePattern: CachedAccess<CompletePatternRule | undefined>;
|
|
646
691
|
readonly underclued: CachedAccess<UndercluedRule | undefined>;
|
|
692
|
+
readonly wrapAround: CachedAccess<WrapAroundRule | undefined>;
|
|
647
693
|
/**
|
|
648
694
|
* Create a new grid with tiles, connections, symbols and rules.
|
|
649
695
|
*
|
|
@@ -742,6 +788,7 @@ declare global {
|
|
|
742
788
|
symbols?: ReadonlyMap<string, readonly Symbol$1[]>;
|
|
743
789
|
rules?: readonly Rule[];
|
|
744
790
|
}): GridData;
|
|
791
|
+
toArrayCoordinates(x: number, y: number): Position$1;
|
|
745
792
|
isPositionValid(x: number, y: number): boolean;
|
|
746
793
|
/**
|
|
747
794
|
* Safely get the tile at the given position.
|
|
@@ -934,12 +981,20 @@ declare global {
|
|
|
934
981
|
* @param position The position to start the iteration from. This position is included in the iteration.
|
|
935
982
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
936
983
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
984
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
937
985
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
938
986
|
*/
|
|
939
987
|
iterateArea<T>(
|
|
940
988
|
position: Position$1,
|
|
941
989
|
predicate: (tile: TileData) => boolean,
|
|
942
|
-
callback: (
|
|
990
|
+
callback: (
|
|
991
|
+
tile: TileData,
|
|
992
|
+
x: number,
|
|
993
|
+
y: number,
|
|
994
|
+
logicalX: number,
|
|
995
|
+
logicalY: number
|
|
996
|
+
) => undefined | T,
|
|
997
|
+
visited?: boolean[][]
|
|
943
998
|
): T | undefined;
|
|
944
999
|
/**
|
|
945
1000
|
* Iterate over all tiles in a straight line from the given position in the given direction that satisfy the predicate.
|
|
@@ -950,13 +1005,21 @@ declare global {
|
|
|
950
1005
|
* @param direction The direction to iterate in.
|
|
951
1006
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
952
1007
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
1008
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
953
1009
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
954
1010
|
*/
|
|
955
1011
|
iterateDirection<T>(
|
|
956
1012
|
position: Position$1,
|
|
957
1013
|
direction: Direction | Orientation,
|
|
958
1014
|
predicate: (tile: TileData) => boolean,
|
|
959
|
-
callback: (
|
|
1015
|
+
callback: (
|
|
1016
|
+
tile: TileData,
|
|
1017
|
+
x: number,
|
|
1018
|
+
y: number,
|
|
1019
|
+
logicalX: number,
|
|
1020
|
+
logicalY: number
|
|
1021
|
+
) => T | undefined,
|
|
1022
|
+
visited?: boolean[][]
|
|
960
1023
|
): T | undefined;
|
|
961
1024
|
/**
|
|
962
1025
|
* Iterate over all tiles in a straight line from the given position in the given direction that satisfy the predicate.
|
|
@@ -967,13 +1030,21 @@ declare global {
|
|
|
967
1030
|
* @param direction The direction to iterate in.
|
|
968
1031
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
969
1032
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
1033
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
970
1034
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
971
1035
|
*/
|
|
972
1036
|
iterateDirectionAll<T>(
|
|
973
1037
|
position: Position$1,
|
|
974
1038
|
direction: Direction | Orientation,
|
|
975
1039
|
predicate: (tile: TileData) => boolean,
|
|
976
|
-
callback: (
|
|
1040
|
+
callback: (
|
|
1041
|
+
tile: TileData,
|
|
1042
|
+
x: number,
|
|
1043
|
+
y: number,
|
|
1044
|
+
logicalX: number,
|
|
1045
|
+
logicalY: number
|
|
1046
|
+
) => T | undefined,
|
|
1047
|
+
visited?: boolean[][]
|
|
977
1048
|
): T | undefined;
|
|
978
1049
|
/**
|
|
979
1050
|
* Check if every tile in the grid is filled with a color other than gray.
|
|
@@ -1125,6 +1196,7 @@ declare global {
|
|
|
1125
1196
|
String = 'string',
|
|
1126
1197
|
Color = 'color',
|
|
1127
1198
|
Comparison = 'comparison',
|
|
1199
|
+
Wrapping = 'wrapping',
|
|
1128
1200
|
Direction = 'direction',
|
|
1129
1201
|
DirectionToggle = 'directionToggle',
|
|
1130
1202
|
Orientation = 'orientation',
|
|
@@ -1174,6 +1246,9 @@ declare global {
|
|
|
1174
1246
|
export interface ComparisonConfig extends Config<Comparison> {
|
|
1175
1247
|
readonly type: ConfigType.Comparison;
|
|
1176
1248
|
}
|
|
1249
|
+
export interface WrappingConfig extends Config<Wrapping> {
|
|
1250
|
+
readonly type: ConfigType.Wrapping;
|
|
1251
|
+
}
|
|
1177
1252
|
export interface DirectionConfig extends Config<Direction> {
|
|
1178
1253
|
readonly type: ConfigType.Direction;
|
|
1179
1254
|
}
|
|
@@ -1217,6 +1292,7 @@ declare global {
|
|
|
1217
1292
|
| StringConfig
|
|
1218
1293
|
| ColorConfig
|
|
1219
1294
|
| ComparisonConfig
|
|
1295
|
+
| WrappingConfig
|
|
1220
1296
|
| DirectionConfig
|
|
1221
1297
|
| DirectionToggleConfig
|
|
1222
1298
|
| OrientationConfig
|
|
@@ -1957,9 +2033,6 @@ declare global {
|
|
|
1957
2033
|
stringifyPuzzle(puzzle: Puzzle): string;
|
|
1958
2034
|
parsePuzzle(input: string): Puzzle;
|
|
1959
2035
|
}
|
|
1960
|
-
export interface CancelRef {
|
|
1961
|
-
cancel?: () => void;
|
|
1962
|
-
}
|
|
1963
2036
|
/**
|
|
1964
2037
|
* Base class that all solvers must extend.
|
|
1965
2038
|
*/
|
|
@@ -1970,10 +2043,18 @@ declare global {
|
|
|
1970
2043
|
* This is also displayed to the user when selecting a solver.
|
|
1971
2044
|
*/
|
|
1972
2045
|
abstract get id(): string;
|
|
2046
|
+
/**
|
|
2047
|
+
* The author(s) of the solver.
|
|
2048
|
+
*/
|
|
2049
|
+
abstract get author(): string;
|
|
1973
2050
|
/**
|
|
1974
2051
|
* A short paragraph describing when the user should use this solver.
|
|
1975
2052
|
*/
|
|
1976
2053
|
abstract get description(): string;
|
|
2054
|
+
/**
|
|
2055
|
+
* Whether the solver supports cancellation. If `true`, the solver must respond to the abort signal if it is provided.
|
|
2056
|
+
*/
|
|
2057
|
+
abstract get supportsCancellation(): boolean;
|
|
1977
2058
|
/**
|
|
1978
2059
|
* Solve the given grid. The implementation should delegate long-running tasks to a worker thread and yield solutions
|
|
1979
2060
|
* asynchronously.
|
|
@@ -1989,12 +2070,12 @@ declare global {
|
|
|
1989
2070
|
*
|
|
1990
2071
|
* @param grid The grid to solve. The provided grid is guaranteed to be supported by the solver. Some tiles in the
|
|
1991
2072
|
* grid may already be filled by the user. It is up to the solver to decide whether to respect these tiles or not.
|
|
1992
|
-
* @param
|
|
1993
|
-
*
|
|
2073
|
+
* @param abortSignal An optional signal that the solver should subscribe to in order to cancel the operation. If the
|
|
2074
|
+
* solver does not support cancellation, it should ignore this parameter.
|
|
1994
2075
|
*/
|
|
1995
2076
|
abstract solve(
|
|
1996
2077
|
grid: GridData,
|
|
1997
|
-
|
|
2078
|
+
abortSignal?: AbortSignal
|
|
1998
2079
|
): AsyncGenerator<GridData | null>;
|
|
1999
2080
|
/**
|
|
2000
2081
|
* Check if the solver supports the current browser environment. This method is called once when the user first clicks
|
|
@@ -2027,15 +2108,17 @@ declare global {
|
|
|
2027
2108
|
}
|
|
2028
2109
|
export declare const allSolvers: Map<string, Solver>;
|
|
2029
2110
|
export declare abstract class EventIteratingSolver extends Solver {
|
|
2111
|
+
readonly supportsCancellation = true;
|
|
2030
2112
|
protected abstract createWorker(): Worker;
|
|
2031
2113
|
solve(
|
|
2032
2114
|
grid: GridData,
|
|
2033
|
-
|
|
2115
|
+
abortSignal?: AbortSignal
|
|
2034
2116
|
): AsyncGenerator<GridData | null>;
|
|
2035
2117
|
}
|
|
2036
2118
|
export declare class BacktrackSolver extends EventIteratingSolver {
|
|
2037
2119
|
private static readonly supportedInstrs;
|
|
2038
2120
|
readonly id = 'backtrack';
|
|
2121
|
+
readonly author = 'ALaggyDev';
|
|
2039
2122
|
readonly description =
|
|
2040
2123
|
'Solves puzzles using backtracking with optimizations (blazingly fast). Support most rules and symbols (including underclued).';
|
|
2041
2124
|
protected createWorker(): Worker;
|
|
@@ -2280,6 +2363,43 @@ declare global {
|
|
|
2280
2363
|
y: number
|
|
2281
2364
|
): Position$1 | null;
|
|
2282
2365
|
}
|
|
2366
|
+
export declare class FocusSymbol extends NumberSymbol {
|
|
2367
|
+
private static readonly CONFIGS;
|
|
2368
|
+
private static readonly EXAMPLE_GRID;
|
|
2369
|
+
/**
|
|
2370
|
+
* **Focus Numbers count directly adjacent cells of the same color**
|
|
2371
|
+
* @param x - The x-coordinate of the symbol.
|
|
2372
|
+
* @param y - The y-coordinate of the symbol.
|
|
2373
|
+
* @param number - The focus number.
|
|
2374
|
+
*/
|
|
2375
|
+
constructor(x: number, y: number, number: number);
|
|
2376
|
+
get id(): string;
|
|
2377
|
+
get placementStep(): number;
|
|
2378
|
+
get explanation(): string;
|
|
2379
|
+
get configs(): readonly AnyConfig[] | null;
|
|
2380
|
+
createExampleGrid(): GridData;
|
|
2381
|
+
countTiles(grid: GridData): {
|
|
2382
|
+
completed: number;
|
|
2383
|
+
possible: number;
|
|
2384
|
+
};
|
|
2385
|
+
copyWith({
|
|
2386
|
+
x,
|
|
2387
|
+
y,
|
|
2388
|
+
number,
|
|
2389
|
+
}: {
|
|
2390
|
+
x?: number;
|
|
2391
|
+
y?: number;
|
|
2392
|
+
number?: number;
|
|
2393
|
+
}): this;
|
|
2394
|
+
withNumber(number: number): this;
|
|
2395
|
+
}
|
|
2396
|
+
export declare class FocusBTModule extends BTModule {
|
|
2397
|
+
instr: FocusSymbol;
|
|
2398
|
+
private cachedCheckResult?;
|
|
2399
|
+
constructor(instr: FocusSymbol);
|
|
2400
|
+
checkGlobal(grid: BTGridData): CheckResult | false;
|
|
2401
|
+
private buildCheckAndRating;
|
|
2402
|
+
}
|
|
2283
2403
|
export declare class GalaxySymbol extends DirectionLinkerSymbol {
|
|
2284
2404
|
readonly x: number;
|
|
2285
2405
|
readonly y: number;
|
|
@@ -2387,7 +2507,7 @@ declare global {
|
|
|
2387
2507
|
private static readonly CONFIGS;
|
|
2388
2508
|
private static readonly EXAMPLE_GRID;
|
|
2389
2509
|
/**
|
|
2390
|
-
* **Minesweeper
|
|
2510
|
+
* **Minesweeper Numbers count opposite cells in 8 adjacent spaces**
|
|
2391
2511
|
*
|
|
2392
2512
|
* @param x - The x-coordinate of the symbol.
|
|
2393
2513
|
* @param y - The y-coordinate of the symbol.
|
|
@@ -2511,6 +2631,7 @@ declare global {
|
|
|
2511
2631
|
}
|
|
2512
2632
|
export declare class UniversalSolver extends EventIteratingSolver {
|
|
2513
2633
|
readonly id = 'universal';
|
|
2634
|
+
readonly author = 'romain22222, Lysine';
|
|
2514
2635
|
readonly description =
|
|
2515
2636
|
'A backtracking solver that supports all rules and symbols (including underclued) but is less optimized.';
|
|
2516
2637
|
protected createWorker(): Worker;
|
|
@@ -2601,8 +2722,10 @@ declare global {
|
|
|
2601
2722
|
): import('grilops').Direction;
|
|
2602
2723
|
export declare class Z3Solver extends Solver {
|
|
2603
2724
|
readonly id = 'z3';
|
|
2725
|
+
readonly author = 'Lysine';
|
|
2604
2726
|
readonly description =
|
|
2605
2727
|
'Good for confirming that a solution is unique, especially for larger puzzles. It is otherwise slower than most solvers in small to medium-sized puzzles.';
|
|
2728
|
+
readonly supportsCancellation = false;
|
|
2606
2729
|
isEnvironmentSupported(): Promise<boolean>;
|
|
2607
2730
|
solve(grid: GridData): AsyncGenerator<GridData | null>;
|
|
2608
2731
|
isInstructionSupported(instructionId: string): boolean;
|
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, Position } from './primitives.js';
|
|
2
|
+
import { Color, Comparison, Direction, DirectionToggle, Orientation, OrientationToggle, Position, Wrapping } from './primitives.js';
|
|
3
3
|
import { ControlLine } from './rules/musicControlLine.js';
|
|
4
4
|
export declare enum ConfigType {
|
|
5
5
|
Boolean = "boolean",
|
|
@@ -9,6 +9,7 @@ export declare enum ConfigType {
|
|
|
9
9
|
String = "string",
|
|
10
10
|
Color = "color",
|
|
11
11
|
Comparison = "comparison",
|
|
12
|
+
Wrapping = "wrapping",
|
|
12
13
|
Direction = "direction",
|
|
13
14
|
DirectionToggle = "directionToggle",
|
|
14
15
|
Orientation = "orientation",
|
|
@@ -58,6 +59,9 @@ export interface ColorConfig extends Config<Color> {
|
|
|
58
59
|
export interface ComparisonConfig extends Config<Comparison> {
|
|
59
60
|
readonly type: ConfigType.Comparison;
|
|
60
61
|
}
|
|
62
|
+
export interface WrappingConfig extends Config<Wrapping> {
|
|
63
|
+
readonly type: ConfigType.Wrapping;
|
|
64
|
+
}
|
|
61
65
|
export interface DirectionConfig extends Config<Direction> {
|
|
62
66
|
readonly type: ConfigType.Direction;
|
|
63
67
|
}
|
|
@@ -93,7 +97,7 @@ export interface NullableNoteConfig extends Config<string | null> {
|
|
|
93
97
|
export interface SolvePathConfig extends Config<Position[]> {
|
|
94
98
|
readonly type: ConfigType.SolvePath;
|
|
95
99
|
}
|
|
96
|
-
export type AnyConfig = BooleanConfig | NullableBooleanConfig | NumberConfig | NullableNumberConfig | StringConfig | ColorConfig | ComparisonConfig | DirectionConfig | DirectionToggleConfig | OrientationConfig | OrientationToggleConfig | TileConfig | GridConfig | NullableGridConfig | IconConfig | ControlLinesConfig | NullableNoteConfig | SolvePathConfig;
|
|
100
|
+
export type AnyConfig = BooleanConfig | NullableBooleanConfig | NumberConfig | NullableNumberConfig | StringConfig | ColorConfig | ComparisonConfig | WrappingConfig | DirectionConfig | DirectionToggleConfig | OrientationConfig | OrientationToggleConfig | TileConfig | GridConfig | NullableGridConfig | IconConfig | ControlLinesConfig | NullableNoteConfig | SolvePathConfig;
|
|
97
101
|
/**
|
|
98
102
|
* Compare two config values for equality, using an appropriate method for the config type.
|
|
99
103
|
*
|
package/dist/data/config.js
CHANGED
|
@@ -8,6 +8,7 @@ export var ConfigType;
|
|
|
8
8
|
ConfigType["String"] = "string";
|
|
9
9
|
ConfigType["Color"] = "color";
|
|
10
10
|
ConfigType["Comparison"] = "comparison";
|
|
11
|
+
ConfigType["Wrapping"] = "wrapping";
|
|
11
12
|
ConfigType["Direction"] = "direction";
|
|
12
13
|
ConfigType["DirectionToggle"] = "directionToggle";
|
|
13
14
|
ConfigType["Orientation"] = "orientation";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Instruction from '../instruction.js';
|
|
2
|
+
import { Position } from '../primitives.js';
|
|
3
|
+
import GridData from '../grid.js';
|
|
4
|
+
export interface GetTileHandler {
|
|
5
|
+
onGetTile(x: number, y: number, grid: GridData): Position;
|
|
6
|
+
}
|
|
7
|
+
export declare function handlesGetTile<T extends Instruction>(val: T): val is T & GetTileHandler;
|
package/dist/data/grid.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import MusicGridRule from './rules/musicGridRule.js';
|
|
|
8
8
|
import CompletePatternRule from './rules/completePatternRule.js';
|
|
9
9
|
import UndercluedRule from './rules/undercluedRule.js';
|
|
10
10
|
import GridZones from './gridZones.js';
|
|
11
|
+
import WrapAroundRule from './rules/wrapAroundRule.js';
|
|
11
12
|
export declare const NEIGHBOR_OFFSETS: Position[];
|
|
12
13
|
export default class GridData {
|
|
13
14
|
readonly width: number;
|
|
@@ -20,6 +21,7 @@ export default class GridData {
|
|
|
20
21
|
readonly musicGrid: CachedAccess<MusicGridRule | undefined>;
|
|
21
22
|
readonly completePattern: CachedAccess<CompletePatternRule | undefined>;
|
|
22
23
|
readonly underclued: CachedAccess<UndercluedRule | undefined>;
|
|
24
|
+
readonly wrapAround: CachedAccess<WrapAroundRule | undefined>;
|
|
23
25
|
/**
|
|
24
26
|
* Create a new grid with tiles, connections, symbols and rules.
|
|
25
27
|
*
|
|
@@ -86,6 +88,7 @@ export default class GridData {
|
|
|
86
88
|
symbols?: ReadonlyMap<string, readonly Symbol[]>;
|
|
87
89
|
rules?: readonly Rule[];
|
|
88
90
|
}): GridData;
|
|
91
|
+
toArrayCoordinates(x: number, y: number): Position;
|
|
89
92
|
isPositionValid(x: number, y: number): boolean;
|
|
90
93
|
/**
|
|
91
94
|
* Safely get the tile at the given position.
|
|
@@ -255,9 +258,10 @@ export default class GridData {
|
|
|
255
258
|
* @param position The position to start the iteration from. This position is included in the iteration.
|
|
256
259
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
257
260
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
261
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
258
262
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
259
263
|
*/
|
|
260
|
-
iterateArea<T>(position: Position, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number) => undefined | T): T | undefined;
|
|
264
|
+
iterateArea<T>(position: Position, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number, logicalX: number, logicalY: number) => undefined | T, visited?: boolean[][]): T | undefined;
|
|
261
265
|
/**
|
|
262
266
|
* Iterate over all tiles in a straight line from the given position in the given direction that satisfy the predicate.
|
|
263
267
|
* The iteration stops when the callback returns a value that is not undefined.
|
|
@@ -267,9 +271,10 @@ export default class GridData {
|
|
|
267
271
|
* @param direction The direction to iterate in.
|
|
268
272
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
269
273
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
274
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
270
275
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
271
276
|
*/
|
|
272
|
-
iterateDirection<T>(position: Position, direction: Direction | Orientation, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number) => T | undefined): T | undefined;
|
|
277
|
+
iterateDirection<T>(position: Position, direction: Direction | Orientation, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number, logicalX: number, logicalY: number) => T | undefined, visited?: boolean[][]): T | undefined;
|
|
273
278
|
/**
|
|
274
279
|
* Iterate over all tiles in a straight line from the given position in the given direction that satisfy the predicate.
|
|
275
280
|
* The iteration stops when the callback returns a value that is not undefined.
|
|
@@ -279,9 +284,10 @@ export default class GridData {
|
|
|
279
284
|
* @param direction The direction to iterate in.
|
|
280
285
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
281
286
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
287
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
282
288
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
283
289
|
*/
|
|
284
|
-
iterateDirectionAll<T>(position: Position, direction: Direction | Orientation, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number) => T | undefined): T | undefined;
|
|
290
|
+
iterateDirectionAll<T>(position: Position, direction: Direction | Orientation, predicate: (tile: TileData) => boolean, callback: (tile: TileData, x: number, y: number, logicalX: number, logicalY: number) => T | undefined, visited?: boolean[][]): T | undefined;
|
|
285
291
|
/**
|
|
286
292
|
* Check if every tile in the grid is filled with a color other than gray.
|
|
287
293
|
*
|
package/dist/data/grid.js
CHANGED
|
@@ -88,6 +88,12 @@ export default class GridData {
|
|
|
88
88
|
writable: true,
|
|
89
89
|
value: CachedAccess.of(() => this.findRule(rule => rule.id === MajorRule.Underclued))
|
|
90
90
|
});
|
|
91
|
+
Object.defineProperty(this, "wrapAround", {
|
|
92
|
+
enumerable: true,
|
|
93
|
+
configurable: true,
|
|
94
|
+
writable: true,
|
|
95
|
+
value: CachedAccess.of(() => this.findRule(rule => rule.id === MajorRule.WrapAround))
|
|
96
|
+
});
|
|
91
97
|
this.width = width;
|
|
92
98
|
this.height = height;
|
|
93
99
|
this.tiles = tiles ?? array(width, height, () => TileData.empty());
|
|
@@ -141,7 +147,30 @@ export default class GridData {
|
|
|
141
147
|
fastCopyWith({ width, height, tiles, connections, zones, symbols, rules, }) {
|
|
142
148
|
return new GridData(width ?? this.width, height ?? this.height, tiles ?? this.tiles, connections ?? this.connections, zones ?? this.zones, symbols ?? this.symbols, rules ?? this.rules);
|
|
143
149
|
}
|
|
150
|
+
toArrayCoordinates(x, y) {
|
|
151
|
+
// // This is the preferred way to compute tile coordinates, but for performance reasons we will just access the
|
|
152
|
+
// // wrap-around rule directly.
|
|
153
|
+
// this.rules.forEach(rule => {
|
|
154
|
+
// if (handlesGetTile(rule)) {
|
|
155
|
+
// ({ x, y } = rule.onGetTile(x, y));
|
|
156
|
+
// }
|
|
157
|
+
// });
|
|
158
|
+
// this.symbols.forEach(list =>
|
|
159
|
+
// list.forEach(symbol => {
|
|
160
|
+
// if (handlesGetTile(symbol)) {
|
|
161
|
+
// ({ x, y } = symbol.onGetTile(x, y));
|
|
162
|
+
// }
|
|
163
|
+
// })
|
|
164
|
+
// );
|
|
165
|
+
if (this.wrapAround.value) {
|
|
166
|
+
return this.wrapAround.value.onGetTile(x, y, this);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
return { x, y };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
144
172
|
isPositionValid(x, y) {
|
|
173
|
+
({ x, y } = this.toArrayCoordinates(x, y));
|
|
145
174
|
return x >= 0 && x < this.width && y >= 0 && y < this.height;
|
|
146
175
|
}
|
|
147
176
|
/**
|
|
@@ -151,7 +180,8 @@ export default class GridData {
|
|
|
151
180
|
* @returns The tile at the given position, or a non-existent tile if the position is invalid.
|
|
152
181
|
*/
|
|
153
182
|
getTile(x, y) {
|
|
154
|
-
|
|
183
|
+
({ x, y } = this.toArrayCoordinates(x, y));
|
|
184
|
+
if (x < 0 || x >= this.width || y < 0 || y >= this.height)
|
|
155
185
|
return TileData.doesNotExist();
|
|
156
186
|
return this.tiles[y][x];
|
|
157
187
|
}
|
|
@@ -166,6 +196,7 @@ export default class GridData {
|
|
|
166
196
|
* @returns The new tile array with updated tiles.
|
|
167
197
|
*/
|
|
168
198
|
setTile(x, y, tile) {
|
|
199
|
+
({ x, y } = this.toArrayCoordinates(x, y));
|
|
169
200
|
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
|
|
170
201
|
return this.tiles;
|
|
171
202
|
}
|
|
@@ -173,6 +204,7 @@ export default class GridData {
|
|
|
173
204
|
const tiles = this.tiles.map(row => [...row]);
|
|
174
205
|
const newTile = typeof tile === 'function' ? tile(tiles[y][x]) : tile;
|
|
175
206
|
changing.forEach(({ x, y }) => {
|
|
207
|
+
({ x, y } = this.toArrayCoordinates(x, y));
|
|
176
208
|
tiles[y][x] = tiles[y][x].withColor(newTile.color);
|
|
177
209
|
});
|
|
178
210
|
tiles[y][x] = newTile;
|
|
@@ -587,22 +619,23 @@ export default class GridData {
|
|
|
587
619
|
* @param position The position to start the iteration from. This position is included in the iteration.
|
|
588
620
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
589
621
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
622
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
590
623
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
591
624
|
*/
|
|
592
|
-
iterateArea(position, predicate, callback) {
|
|
625
|
+
iterateArea(position, predicate, callback, visited = array(this.width, this.height, () => false)) {
|
|
593
626
|
const tile = this.getTile(position.x, position.y);
|
|
594
627
|
if (!tile.exists || !predicate(tile)) {
|
|
595
628
|
return;
|
|
596
629
|
}
|
|
597
|
-
const visited = array(this.width, this.height, () => false);
|
|
598
630
|
const stack = [position];
|
|
599
631
|
while (stack.length > 0) {
|
|
600
632
|
const { x, y } = stack.pop();
|
|
601
|
-
|
|
633
|
+
const { x: arrX, y: arrY } = this.toArrayCoordinates(x, y);
|
|
634
|
+
if (visited[arrY][arrX]) {
|
|
602
635
|
continue;
|
|
603
636
|
}
|
|
604
|
-
visited[
|
|
605
|
-
const ret = callback(this.getTile(x, y), x, y);
|
|
637
|
+
visited[arrY][arrX] = true;
|
|
638
|
+
const ret = callback(this.getTile(x, y), arrX, arrY, x, y);
|
|
606
639
|
if (ret !== undefined)
|
|
607
640
|
return ret;
|
|
608
641
|
for (const offset of NEIGHBOR_OFFSETS) {
|
|
@@ -624,10 +657,11 @@ export default class GridData {
|
|
|
624
657
|
* @param direction The direction to iterate in.
|
|
625
658
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
626
659
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
660
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
627
661
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
628
662
|
*/
|
|
629
|
-
iterateDirection(position, direction, predicate, callback) {
|
|
630
|
-
return this.iterateDirectionAll(position, direction, tile => tile.exists && predicate(tile), callback);
|
|
663
|
+
iterateDirection(position, direction, predicate, callback, visited = array(this.width, this.height, () => false)) {
|
|
664
|
+
return this.iterateDirectionAll(position, direction, tile => tile.exists && predicate(tile), callback, visited);
|
|
631
665
|
}
|
|
632
666
|
/**
|
|
633
667
|
* Iterate over all tiles in a straight line from the given position in the given direction that satisfy the predicate.
|
|
@@ -638,16 +672,22 @@ export default class GridData {
|
|
|
638
672
|
* @param direction The direction to iterate in.
|
|
639
673
|
* @param predicate The predicate to test each tile with. The callback is only called for tiles that satisfy this predicate.
|
|
640
674
|
* @param callback The callback to call for each tile that satisfies the predicate. The iteration stops when this callback returns a value that is not undefined.
|
|
675
|
+
* @param visited A 2D array to keep track of visited tiles. This array is modified by the function.
|
|
641
676
|
* @returns The value returned by the callback that stopped the iteration, or undefined if the iteration completed.
|
|
642
677
|
*/
|
|
643
|
-
iterateDirectionAll(position, direction, predicate, callback) {
|
|
678
|
+
iterateDirectionAll(position, direction, predicate, callback, visited = array(this.width, this.height, () => false)) {
|
|
644
679
|
let current = position;
|
|
645
680
|
while (this.isPositionValid(current.x, current.y)) {
|
|
681
|
+
const arrPos = this.toArrayCoordinates(current.x, current.y);
|
|
682
|
+
if (visited[arrPos.y][arrPos.x]) {
|
|
683
|
+
break;
|
|
684
|
+
}
|
|
685
|
+
visited[arrPos.y][arrPos.x] = true;
|
|
646
686
|
const tile = this.getTile(current.x, current.y);
|
|
647
687
|
if (!predicate(tile)) {
|
|
648
688
|
break;
|
|
649
689
|
}
|
|
650
|
-
const ret = callback(tile, current.x, current.y);
|
|
690
|
+
const ret = callback(tile, arrPos.x, arrPos.y, current.x, current.y);
|
|
651
691
|
if (ret !== undefined)
|
|
652
692
|
return ret;
|
|
653
693
|
current = move(current, direction);
|
|
@@ -14,7 +14,8 @@ export interface Edge {
|
|
|
14
14
|
export declare enum MajorRule {
|
|
15
15
|
MusicGrid = "music",
|
|
16
16
|
CompletePattern = "complete_pattern",
|
|
17
|
-
Underclued = "underclued"
|
|
17
|
+
Underclued = "underclued",
|
|
18
|
+
WrapAround = "wrap_around"
|
|
18
19
|
}
|
|
19
20
|
export declare enum State {
|
|
20
21
|
/**
|
|
@@ -63,6 +64,13 @@ export declare enum Comparison {
|
|
|
63
64
|
AtMost = "le"
|
|
64
65
|
}
|
|
65
66
|
export declare const COMPARISONS: readonly Comparison[];
|
|
67
|
+
export declare enum Wrapping {
|
|
68
|
+
None = "none",
|
|
69
|
+
Wrap = "wrap",
|
|
70
|
+
WrapReverse = "wrap-reverse",
|
|
71
|
+
ReflectReverse = "reflect-reverse"
|
|
72
|
+
}
|
|
73
|
+
export declare const WRAPPINGS: readonly Wrapping[];
|
|
66
74
|
export declare enum Direction {
|
|
67
75
|
Up = "up",
|
|
68
76
|
Down = "down",
|
package/dist/data/primitives.js
CHANGED
|
@@ -6,6 +6,7 @@ export var MajorRule;
|
|
|
6
6
|
MajorRule["MusicGrid"] = "music";
|
|
7
7
|
MajorRule["CompletePattern"] = "complete_pattern";
|
|
8
8
|
MajorRule["Underclued"] = "underclued";
|
|
9
|
+
MajorRule["WrapAround"] = "wrap_around";
|
|
9
10
|
})(MajorRule || (MajorRule = {}));
|
|
10
11
|
export var State;
|
|
11
12
|
(function (State) {
|
|
@@ -50,6 +51,19 @@ export const COMPARISONS = [
|
|
|
50
51
|
Comparison.AtLeast,
|
|
51
52
|
Comparison.AtMost,
|
|
52
53
|
];
|
|
54
|
+
export var Wrapping;
|
|
55
|
+
(function (Wrapping) {
|
|
56
|
+
Wrapping["None"] = "none";
|
|
57
|
+
Wrapping["Wrap"] = "wrap";
|
|
58
|
+
Wrapping["WrapReverse"] = "wrap-reverse";
|
|
59
|
+
Wrapping["ReflectReverse"] = "reflect-reverse";
|
|
60
|
+
})(Wrapping || (Wrapping = {}));
|
|
61
|
+
export const WRAPPINGS = [
|
|
62
|
+
Wrapping.None,
|
|
63
|
+
Wrapping.Wrap,
|
|
64
|
+
Wrapping.WrapReverse,
|
|
65
|
+
Wrapping.ReflectReverse,
|
|
66
|
+
];
|
|
53
67
|
export var Direction;
|
|
54
68
|
(function (Direction) {
|
|
55
69
|
Direction["Up"] = "up";
|
|
@@ -71,10 +71,18 @@ class BanPatternRule extends Rule {
|
|
|
71
71
|
}
|
|
72
72
|
validateGrid(grid) {
|
|
73
73
|
for (const pattern of this.cache) {
|
|
74
|
-
for (let y = 0; y <= grid.height -
|
|
75
|
-
for (let x = 0; x <= grid.width -
|
|
74
|
+
for (let y = 0; y <= grid.height - 1; y++) {
|
|
75
|
+
for (let x = 0; x <= grid.width - 1; x++) {
|
|
76
76
|
let match = true;
|
|
77
|
+
const visited = [];
|
|
77
78
|
for (const tile of pattern.elements) {
|
|
79
|
+
const pos = grid.toArrayCoordinates(x + tile.x, y + tile.y);
|
|
80
|
+
if (grid.wrapAround.value && // optimization: not need to check visited if wrapAround is disabled
|
|
81
|
+
visited.some(p => p.x === pos.x && p.y === pos.y)) {
|
|
82
|
+
match = false;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
visited.push(pos);
|
|
78
86
|
const t = grid.getTile(x + tile.x, y + tile.y);
|
|
79
87
|
if (!t.exists || t.color !== tile.color) {
|
|
80
88
|
match = false;
|
|
@@ -84,10 +92,7 @@ class BanPatternRule extends Rule {
|
|
|
84
92
|
if (match) {
|
|
85
93
|
return {
|
|
86
94
|
state: State.Error,
|
|
87
|
-
positions: pattern.elements.map(tile => (
|
|
88
|
-
x: x + tile.x,
|
|
89
|
-
y: y + tile.y,
|
|
90
|
-
})),
|
|
95
|
+
positions: pattern.elements.map(tile => grid.toArrayCoordinates(x + tile.x, y + tile.y)),
|
|
91
96
|
};
|
|
92
97
|
}
|
|
93
98
|
}
|