@logic-pad/core 0.2.2 → 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.
@@ -401,7 +401,11 @@ declare global {
401
401
  val: T
402
402
  ): val is T & GridChangeHandler;
403
403
  export interface SetGridHandler {
404
- onSetGrid(oldGrid: GridData, newGrid: GridData): GridData;
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(_oldGrid: GridData, newGrid: GridData): GridData;
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(count: number, regenInterval: number, startFull: boolean);
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;
@@ -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 type AnyConfig = BooleanConfig | NullableBooleanConfig | NumberConfig | NullableNumberConfig | StringConfig | ColorConfig | ComparisonConfig | DirectionConfig | DirectionToggleConfig | OrientationConfig | OrientationToggleConfig | TileConfig | GridConfig | NullableGridConfig | IconConfig | ControlLinesConfig | NullableNoteConfig;
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
  *
@@ -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;
@@ -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) {
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, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logic-pad/core",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",