@logic-pad/core 0.3.0 → 0.4.1

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.
@@ -112,6 +112,30 @@ declare global {
112
112
  Create = 'create',
113
113
  Solve = 'solve',
114
114
  }
115
+ export declare class GridZones {
116
+ readonly edges: readonly Edge[];
117
+ constructor(edges?: readonly Edge[]);
118
+ addEdge(edge: Edge): GridZones;
119
+ removeEdge(edge: Edge): GridZones;
120
+ hasEdge(edge: Edge): boolean;
121
+ getEdgesAt({ x, y }: Position$1): readonly Edge[];
122
+ /**
123
+ * Check if two GridZones objects are equal.
124
+ * @param other The other GridZones object to compare to.
125
+ * @returns Whether the two objects are equal.
126
+ */
127
+ equals(other: GridZones): boolean;
128
+ /**
129
+ * Deduplicate an array of edges.
130
+ * @param edges The array of edges to deduplicate.
131
+ * @returns The deduplicated array of edges.
132
+ */
133
+ static deduplicateEdges(edges: readonly Edge[]): readonly Edge[];
134
+ insertColumn(index: number): GridZones;
135
+ insertRow(index: number): GridZones;
136
+ removeColumn(index: number): GridZones;
137
+ removeRow(index: number): GridZones;
138
+ }
115
139
  export declare class TileConnections {
116
140
  [y: number]: {
117
141
  [x: number]: boolean;
@@ -137,13 +161,10 @@ declare global {
137
161
  set bottomRight(value: boolean);
138
162
  equals(other: TileConnections): boolean;
139
163
  }
140
- export declare class GridConnections {
141
- readonly edges: readonly Edge[];
164
+ export declare class GridConnections extends GridZones {
142
165
  constructor(edges?: readonly Edge[]);
143
166
  addEdge(edge: Edge): GridConnections;
144
167
  removeEdge(edge: Edge): GridConnections;
145
- isConnected(edge: Edge): boolean;
146
- getConnectionsAt({ x, y }: Position$1): readonly Edge[];
147
168
  getForTile({ x, y }: Position$1): TileConnections;
148
169
  getConnectedTiles({ x, y }: Position$1): readonly Position$1[];
149
170
  /**
@@ -156,18 +177,6 @@ declare global {
156
177
  * @returns The created connections. You can apply this to a GridData object using GridData.withConnections.
157
178
  */
158
179
  static create(array: string[]): GridConnections;
159
- /**
160
- * Check if two GridConnections objects are equal.
161
- * @param other The other GridConnections object to compare to.
162
- * @returns Whether the two objects are equal.
163
- */
164
- equals(other: GridConnections): boolean;
165
- /**
166
- * Deduplicate an array of edges.
167
- * @param edges The array of edges to deduplicate.
168
- * @returns The deduplicated array of edges.
169
- */
170
- static deduplicateEdges(edges: readonly Edge[]): readonly Edge[];
171
180
  insertColumn(index: number): GridConnections;
172
181
  insertRow(index: number): GridConnections;
173
182
  removeColumn(index: number): GridConnections;
@@ -188,6 +197,13 @@ declare global {
188
197
  x: number;
189
198
  y: number;
190
199
  };
200
+ /**
201
+ * Check if two edges are the same, regardless of direction.
202
+ * @param a The first edge.
203
+ * @param b The second edge.
204
+ * @returns Whether the edges are the same.
205
+ */
206
+ export declare function isSameEdge(a: Edge, b: Edge): boolean;
191
207
  /**
192
208
  * Convert the given direction to a rotation in degrees.
193
209
  * @param direction The direction to convert.
@@ -577,11 +593,13 @@ declare global {
577
593
  get validateWithSolution(): boolean;
578
594
  get isSingleton(): boolean;
579
595
  }
596
+ export declare const NEIGHBOR_OFFSETS: Position$1[];
580
597
  export declare class GridData {
581
598
  readonly width: number;
582
599
  readonly height: number;
583
600
  readonly tiles: readonly (readonly TileData[])[];
584
601
  readonly connections: GridConnections;
602
+ readonly zones: GridZones;
585
603
  readonly symbols: ReadonlyMap<string, readonly Symbol$1[]>;
586
604
  readonly rules: readonly Rule[];
587
605
  readonly musicGrid: CachedAccess<MusicGridRule | undefined>;
@@ -593,6 +611,7 @@ declare global {
593
611
  * @param height The height of the grid.
594
612
  * @param tiles The tiles of the grid.
595
613
  * @param connections The connections of the grid, which determines which tiles are merged.
614
+ * @param zones The zones of the grid.
596
615
  * @param symbols The symbols in the grid.
597
616
  * @param rules The rules of the grid.
598
617
  */
@@ -601,6 +620,7 @@ declare global {
601
620
  height: number,
602
621
  tiles?: readonly (readonly TileData[])[],
603
622
  connections?: GridConnections,
623
+ zones?: GridZones,
604
624
  symbols?: ReadonlyMap<string, readonly Symbol$1[]>,
605
625
  rules?: readonly Rule[]
606
626
  );
@@ -614,6 +634,7 @@ declare global {
614
634
  height,
615
635
  tiles,
616
636
  connections,
637
+ zones,
617
638
  symbols,
618
639
  rules,
619
640
  }: {
@@ -621,6 +642,7 @@ declare global {
621
642
  height?: number;
622
643
  tiles?: readonly (readonly TileData[])[];
623
644
  connections?: GridConnections;
645
+ zones?: GridZones;
624
646
  symbols?: ReadonlyMap<string, readonly Symbol$1[]>;
625
647
  rules?: readonly Rule[];
626
648
  }): GridData;
@@ -668,6 +690,12 @@ declare global {
668
690
  | GridConnections
669
691
  | ((value: GridConnections) => GridConnections)
670
692
  ): GridData;
693
+ /**
694
+ * Add or modify the zones in the grid.
695
+ * @param zones The new zones to add or modify.
696
+ * @returns The new grid with the new zones.
697
+ */
698
+ withZones(zones: GridZones | ((value: GridZones) => GridZones)): GridData;
671
699
  /**
672
700
  * Add or modify the symbols in the grid.
673
701
  * @param symbols The new symbols to add or modify.
@@ -1332,6 +1360,28 @@ declare global {
1332
1360
  copyWith({ pattern }: { pattern?: GridData }): this;
1333
1361
  withPattern(pattern: GridData): this;
1334
1362
  }
1363
+ export declare class CellCountPerZoneRule extends Rule {
1364
+ readonly color: Color;
1365
+ private static readonly CONFIGS;
1366
+ private static readonly EXAMPLE_GRID_LIGHT;
1367
+ private static readonly EXAMPLE_GRID_DARK;
1368
+ private static readonly EXAMPLE_GRID_GRAY;
1369
+ private static readonly SEARCH_VARIANTS;
1370
+ /**
1371
+ * **Every zone has the same number of &lt;color&gt; cells.**
1372
+ *
1373
+ * @param color - The color of the cells to count.
1374
+ */
1375
+ constructor(color: Color);
1376
+ get id(): string;
1377
+ get explanation(): string;
1378
+ get configs(): readonly AnyConfig[] | null;
1379
+ createExampleGrid(): GridData;
1380
+ get searchVariants(): SearchVariant[];
1381
+ validateGrid(grid: GridData): RuleState;
1382
+ copyWith({ color }: { color?: Color }): this;
1383
+ withColor(color: Color): this;
1384
+ }
1335
1385
  export declare class CellCountRule extends Rule {
1336
1386
  readonly color: Color;
1337
1387
  readonly count: number;
@@ -1746,6 +1796,8 @@ declare global {
1746
1796
  abstract parseSymbol(str: string): Symbol$1;
1747
1797
  abstract stringifyConnections(connections: GridConnections): string;
1748
1798
  abstract parseConnections(input: string): GridConnections;
1799
+ abstract stringifyZones(zones: GridZones): string;
1800
+ abstract parseZones(input: string): GridZones;
1749
1801
  abstract stringifyTiles(tiles: readonly (readonly TileData[])[]): string;
1750
1802
  abstract parseTiles(input: string): TileData[][];
1751
1803
  abstract stringifyRules(rules: readonly Rule[]): string;
@@ -1777,6 +1829,8 @@ declare global {
1777
1829
  parseSymbol(str: string): Symbol$1;
1778
1830
  stringifyConnections(connections: GridConnections): string;
1779
1831
  parseConnections(input: string): GridConnections;
1832
+ stringifyZones(zones: GridZones): string;
1833
+ parseZones(input: string): GridZones;
1780
1834
  stringifyTiles(tiles: readonly (readonly TileData[])[]): string;
1781
1835
  parseTiles(input: string): TileData[][];
1782
1836
  stringifyRules(rules: readonly Rule[]): string;
@@ -1,4 +1,4 @@
1
- import { Direction, Orientation, Position } from './primitives.js';
1
+ import { Direction, Edge, Orientation, Position } from './primitives.js';
2
2
  /**
3
3
  * Offset the given position by a given step in the given direction.
4
4
  * @param position The position to offset.
@@ -10,6 +10,13 @@ export declare function move(position: Position, direction: Direction | Orientat
10
10
  x: number;
11
11
  y: number;
12
12
  };
13
+ /**
14
+ * Check if two edges are the same, regardless of direction.
15
+ * @param a The first edge.
16
+ * @param b The second edge.
17
+ * @returns Whether the edges are the same.
18
+ */
19
+ export declare function isSameEdge(a: Edge, b: Edge): boolean;
13
20
  /**
14
21
  * Convert the given direction to a rotation in degrees.
15
22
  * @param direction The direction to convert.
@@ -30,6 +30,16 @@ export function move(position, direction, step = 1) {
30
30
  return { x: position.x + step, y: position.y + step };
31
31
  }
32
32
  }
33
+ /**
34
+ * Check if two edges are the same, regardless of direction.
35
+ * @param a The first edge.
36
+ * @param b The second edge.
37
+ * @returns Whether the edges are the same.
38
+ */
39
+ export function isSameEdge(a, b) {
40
+ return ((a.x1 === b.x1 && a.y1 === b.y1 && a.x2 === b.x2 && a.y2 === b.y2) ||
41
+ (a.x1 === b.x2 && a.y1 === b.y2 && a.x2 === b.x1 && a.y2 === b.y1));
42
+ }
33
43
  /**
34
44
  * Convert the given direction to a rotation in degrees.
35
45
  * @param direction The direction to convert.
@@ -7,11 +7,14 @@ import TileData from './tile.js';
7
7
  import MusicGridRule from './rules/musicGridRule.js';
8
8
  import CompletePatternRule from './rules/completePatternRule.js';
9
9
  import UndercluedRule from './rules/undercluedRule.js';
10
+ import GridZones from './gridZones.js';
11
+ export declare const NEIGHBOR_OFFSETS: Position[];
10
12
  export default class GridData {
11
13
  readonly width: number;
12
14
  readonly height: number;
13
15
  readonly tiles: readonly (readonly TileData[])[];
14
16
  readonly connections: GridConnections;
17
+ readonly zones: GridZones;
15
18
  readonly symbols: ReadonlyMap<string, readonly Symbol[]>;
16
19
  readonly rules: readonly Rule[];
17
20
  readonly musicGrid: CachedAccess<MusicGridRule | undefined>;
@@ -23,20 +26,22 @@ export default class GridData {
23
26
  * @param height The height of the grid.
24
27
  * @param tiles The tiles of the grid.
25
28
  * @param connections The connections of the grid, which determines which tiles are merged.
29
+ * @param zones The zones of the grid.
26
30
  * @param symbols The symbols in the grid.
27
31
  * @param rules The rules of the grid.
28
32
  */
29
- constructor(width: number, height: number, tiles?: readonly (readonly TileData[])[], connections?: GridConnections, symbols?: ReadonlyMap<string, readonly Symbol[]>, rules?: readonly Rule[]);
33
+ constructor(width: number, height: number, tiles?: readonly (readonly TileData[])[], connections?: GridConnections, zones?: GridZones, symbols?: ReadonlyMap<string, readonly Symbol[]>, rules?: readonly Rule[]);
30
34
  /**
31
35
  * Copy the current grid while modifying the provided properties.
32
36
  * @param param0 The properties to modify.
33
37
  * @returns The new grid with the modified properties.
34
38
  */
35
- copyWith({ width, height, tiles, connections, symbols, rules, }: {
39
+ copyWith({ width, height, tiles, connections, zones, symbols, rules, }: {
36
40
  width?: number;
37
41
  height?: number;
38
42
  tiles?: readonly (readonly TileData[])[];
39
43
  connections?: GridConnections;
44
+ zones?: GridZones;
40
45
  symbols?: ReadonlyMap<string, readonly Symbol[]>;
41
46
  rules?: readonly Rule[];
42
47
  }): GridData;
@@ -72,6 +77,12 @@ export default class GridData {
72
77
  * @returns The new grid with the new connections.
73
78
  */
74
79
  withConnections(connections: GridConnections | ((value: GridConnections) => GridConnections)): GridData;
80
+ /**
81
+ * Add or modify the zones in the grid.
82
+ * @param zones The new zones to add or modify.
83
+ * @returns The new grid with the new zones.
84
+ */
85
+ withZones(zones: GridZones | ((value: GridZones) => GridZones)): GridData;
75
86
  /**
76
87
  * Add or modify the symbols in the grid.
77
88
  * @param symbols The new symbols to add or modify.
package/dist/data/grid.js CHANGED
@@ -5,7 +5,8 @@ import GridConnections from './gridConnections.js';
5
5
  import { CachedAccess, array, move } from './dataHelper.js';
6
6
  import { Color, MajorRule, } from './primitives.js';
7
7
  import TileData from './tile.js';
8
- const NEIGHBOR_OFFSETS = [
8
+ import GridZones from './gridZones.js';
9
+ export const NEIGHBOR_OFFSETS = [
9
10
  { x: -1, y: 0 },
10
11
  { x: 1, y: 0 },
11
12
  { x: 0, y: -1 },
@@ -19,10 +20,11 @@ export default class GridData {
19
20
  * @param height The height of the grid.
20
21
  * @param tiles The tiles of the grid.
21
22
  * @param connections The connections of the grid, which determines which tiles are merged.
23
+ * @param zones The zones of the grid.
22
24
  * @param symbols The symbols in the grid.
23
25
  * @param rules The rules of the grid.
24
26
  */
25
- constructor(width, height, tiles, connections, symbols, rules) {
27
+ constructor(width, height, tiles, connections, zones, symbols, rules) {
26
28
  Object.defineProperty(this, "width", {
27
29
  enumerable: true,
28
30
  configurable: true,
@@ -47,6 +49,12 @@ export default class GridData {
47
49
  writable: true,
48
50
  value: void 0
49
51
  });
52
+ Object.defineProperty(this, "zones", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
50
58
  Object.defineProperty(this, "symbols", {
51
59
  enumerable: true,
52
60
  configurable: true,
@@ -83,6 +91,7 @@ export default class GridData {
83
91
  this.height = height;
84
92
  this.tiles = tiles ?? array(width, height, () => TileData.empty());
85
93
  this.connections = connections ?? new GridConnections();
94
+ this.zones = zones ?? new GridZones();
86
95
  const newSymbols = symbols
87
96
  ? GridData.deduplicateSymbols(symbols)
88
97
  : new Map();
@@ -108,8 +117,8 @@ export default class GridData {
108
117
  * @param param0 The properties to modify.
109
118
  * @returns The new grid with the modified properties.
110
119
  */
111
- copyWith({ width, height, tiles, connections, symbols, rules, }) {
112
- return new GridData(width ?? this.width, height ?? this.height, tiles ?? this.tiles, connections ?? this.connections, symbols ?? this.symbols, rules ?? this.rules);
120
+ copyWith({ width, height, tiles, connections, zones, symbols, rules, }) {
121
+ return new GridData(width ?? this.width, height ?? this.height, tiles ?? this.tiles, connections ?? this.connections, zones ?? this.zones, symbols ?? this.symbols, rules ?? this.rules);
113
122
  }
114
123
  isPositionValid(x, y) {
115
124
  return x >= 0 && x < this.width && y >= 0 && y < this.height;
@@ -173,6 +182,16 @@ export default class GridData {
173
182
  : connections,
174
183
  });
175
184
  }
185
+ /**
186
+ * Add or modify the zones in the grid.
187
+ * @param zones The new zones to add or modify.
188
+ * @returns The new grid with the new zones.
189
+ */
190
+ withZones(zones) {
191
+ return this.copyWith({
192
+ zones: typeof zones === 'function' ? zones(this.zones) : zones,
193
+ });
194
+ }
176
195
  /**
177
196
  * Add or modify the symbols in the grid.
178
197
  * @param symbols The new symbols to add or modify.
@@ -346,6 +365,7 @@ export default class GridData {
346
365
  return this.getTile(x - 1, y);
347
366
  });
348
367
  const connections = this.connections.insertColumn(index);
368
+ const zones = this.zones.insertColumn(index);
349
369
  const rules = this.rules
350
370
  .map(rule => {
351
371
  if (handlesGridResize(rule))
@@ -366,6 +386,7 @@ export default class GridData {
366
386
  width: this.width + 1,
367
387
  tiles,
368
388
  connections,
389
+ zones,
369
390
  rules,
370
391
  symbols,
371
392
  });
@@ -386,6 +407,7 @@ export default class GridData {
386
407
  return this.getTile(x, y - 1);
387
408
  });
388
409
  const connections = this.connections.insertRow(index);
410
+ const zones = this.zones.insertRow(index);
389
411
  const rules = this.rules
390
412
  .map(rule => {
391
413
  if (handlesGridResize(rule))
@@ -406,6 +428,7 @@ export default class GridData {
406
428
  height: this.height + 1,
407
429
  tiles,
408
430
  connections,
431
+ zones,
409
432
  rules,
410
433
  symbols,
411
434
  });
@@ -420,6 +443,7 @@ export default class GridData {
420
443
  return this;
421
444
  const tiles = array(this.width - 1, this.height, (x, y) => x < index ? this.getTile(x, y) : this.getTile(x + 1, y));
422
445
  const connections = this.connections.removeColumn(index);
446
+ const zones = this.zones.removeColumn(index);
423
447
  const rules = this.rules
424
448
  .map(rule => {
425
449
  if (handlesGridResize(rule))
@@ -440,6 +464,7 @@ export default class GridData {
440
464
  width: this.width - 1,
441
465
  tiles,
442
466
  connections,
467
+ zones,
443
468
  rules,
444
469
  symbols,
445
470
  });
@@ -454,6 +479,7 @@ export default class GridData {
454
479
  return this;
455
480
  const tiles = array(this.width, this.height - 1, (x, y) => y < index ? this.getTile(x, y) : this.getTile(x, y + 1));
456
481
  const connections = this.connections.removeRow(index);
482
+ const zones = this.zones.removeRow(index);
457
483
  const rules = this.rules
458
484
  .map(rule => {
459
485
  if (handlesGridResize(rule))
@@ -474,6 +500,7 @@ export default class GridData {
474
500
  height: this.height - 1,
475
501
  tiles,
476
502
  connections,
503
+ zones,
477
504
  rules,
478
505
  symbols,
479
506
  });
@@ -573,10 +600,7 @@ export default class GridData {
573
600
  return ret;
574
601
  for (const offset of NEIGHBOR_OFFSETS) {
575
602
  const next = { x: x + offset.x, y: y + offset.y };
576
- if (next.x >= 0 &&
577
- next.x < this.width &&
578
- next.y >= 0 &&
579
- next.y < this.height) {
603
+ if (this.isPositionValid(next.x, next.y)) {
580
604
  const nextTile = this.getTile(next.x, next.y);
581
605
  if (nextTile.exists && predicate(nextTile))
582
606
  stack.push(next);
@@ -747,6 +771,21 @@ export default class GridData {
747
771
  x2: edge.x2 - origin.x,
748
772
  y2: edge.y2 - origin.y,
749
773
  })));
774
+ const zones = new GridZones(this.zones.edges
775
+ .filter(edge => edge.x1 >= origin.x &&
776
+ edge.y1 >= origin.y &&
777
+ edge.x2 >= origin.x &&
778
+ edge.y2 >= origin.y &&
779
+ edge.x1 < origin.x + width &&
780
+ edge.y1 < origin.y + height &&
781
+ edge.x2 < origin.x + width &&
782
+ edge.y2 < origin.y + height)
783
+ .map(edge => ({
784
+ x1: edge.x1 - origin.x,
785
+ y1: edge.y1 - origin.y,
786
+ x2: edge.x2 - origin.x,
787
+ y2: edge.y2 - origin.y,
788
+ })));
750
789
  const symbols = new Map();
751
790
  for (const [id, symbolList] of this.symbols) {
752
791
  const newSymbolList = symbolList.filter(symbol => symbol.x >= origin.x &&
@@ -756,7 +795,7 @@ export default class GridData {
756
795
  if (newSymbolList.length > 0)
757
796
  symbols.set(id, newSymbolList);
758
797
  }
759
- return new GridData(width, height, newTiles, connections, symbols, this.rules);
798
+ return new GridData(width, height, newTiles, connections, zones, symbols, this.rules);
760
799
  }
761
800
  pasteTiles(origin, grid) {
762
801
  if (!(grid instanceof GridData))
@@ -775,6 +814,15 @@ export default class GridData {
775
814
  y2: edge.y2 + origin.y,
776
815
  })),
777
816
  ]);
817
+ const zones = new GridZones([
818
+ ...this.zones.edges,
819
+ ...grid.zones.edges.map(edge => ({
820
+ x1: edge.x1 + origin.x,
821
+ y1: edge.y1 + origin.y,
822
+ x2: edge.x2 + origin.x,
823
+ y2: edge.y2 + origin.y,
824
+ })),
825
+ ]);
778
826
  const symbols = new Map(this.symbols);
779
827
  for (const [id, sourceList] of grid.symbols) {
780
828
  const symbolList = sourceList.map(symbol => symbol.copyWith({ x: symbol.x + origin.x, y: symbol.y + origin.y }));
@@ -786,7 +834,13 @@ export default class GridData {
786
834
  }
787
835
  }
788
836
  const rules = [...this.rules, ...grid.rules];
789
- return this.copyWith({ tiles: newTiles, connections, symbols, rules });
837
+ return this.copyWith({
838
+ tiles: newTiles,
839
+ connections,
840
+ zones,
841
+ symbols,
842
+ rules,
843
+ });
790
844
  }
791
845
  /**
792
846
  * Check if this grid is equal to another grid in terms of size and tile colors.
@@ -839,6 +893,8 @@ export default class GridData {
839
893
  return false;
840
894
  if (!this.connections.equals(other.connections))
841
895
  return false;
896
+ if (!this.zones.equals(other.zones))
897
+ return false;
842
898
  if (this.symbols.size !== other.symbols.size)
843
899
  return false;
844
900
  for (const [id, symbols] of this.symbols) {
@@ -1,12 +1,10 @@
1
+ import GridZones from './gridZones.js';
1
2
  import { Edge, Position } from './primitives.js';
2
3
  import TileConnections from './tileConnections.js';
3
- export default class GridConnections {
4
- readonly edges: readonly Edge[];
4
+ export default class GridConnections extends GridZones {
5
5
  constructor(edges?: readonly Edge[]);
6
6
  addEdge(edge: Edge): GridConnections;
7
7
  removeEdge(edge: Edge): GridConnections;
8
- isConnected(edge: Edge): boolean;
9
- getConnectionsAt({ x, y }: Position): readonly Edge[];
10
8
  getForTile({ x, y }: Position): TileConnections;
11
9
  getConnectedTiles({ x, y }: Position): readonly Position[];
12
10
  /**
@@ -19,18 +17,6 @@ export default class GridConnections {
19
17
  * @returns The created connections. You can apply this to a GridData object using GridData.withConnections.
20
18
  */
21
19
  static create(array: string[]): GridConnections;
22
- /**
23
- * Check if two GridConnections objects are equal.
24
- * @param other The other GridConnections object to compare to.
25
- * @returns Whether the two objects are equal.
26
- */
27
- equals(other: GridConnections): boolean;
28
- /**
29
- * Deduplicate an array of edges.
30
- * @param edges The array of edges to deduplicate.
31
- * @returns The deduplicated array of edges.
32
- */
33
- static deduplicateEdges(edges: readonly Edge[]): readonly Edge[];
34
20
  insertColumn(index: number): GridConnections;
35
21
  insertRow(index: number): GridConnections;
36
22
  removeColumn(index: number): GridConnections;
@@ -1,17 +1,9 @@
1
+ import { isSameEdge } from './dataHelper.js';
2
+ import GridZones from './gridZones.js';
1
3
  import TileConnections from './tileConnections.js';
2
- function isSameEdge(a, b) {
3
- return ((a.x1 === b.x1 && a.y1 === b.y1 && a.x2 === b.x2 && a.y2 === b.y2) ||
4
- (a.x1 === b.x2 && a.y1 === b.y2 && a.x2 === b.x1 && a.y2 === b.y1));
5
- }
6
- export default class GridConnections {
4
+ export default class GridConnections extends GridZones {
7
5
  constructor(edges) {
8
- Object.defineProperty(this, "edges", {
9
- enumerable: true,
10
- configurable: true,
11
- writable: true,
12
- value: void 0
13
- });
14
- this.edges = GridConnections.deduplicateEdges(edges ?? []);
6
+ super(edges);
15
7
  }
16
8
  addEdge(edge) {
17
9
  if (this.edges.some(e => isSameEdge(e, edge))) {
@@ -22,26 +14,18 @@ export default class GridConnections {
22
14
  removeEdge(edge) {
23
15
  return new GridConnections(this.edges.filter(e => !isSameEdge(e, edge)));
24
16
  }
25
- isConnected(edge) {
26
- if (edge.x1 === edge.x2 && edge.y1 === edge.y2)
27
- return true;
28
- return this.edges.some(e => isSameEdge(e, edge));
29
- }
30
- getConnectionsAt({ x, y }) {
31
- return this.edges.filter(e => (e.x1 === x && e.y1 === y) || (e.x2 === x && e.y2 === y));
32
- }
33
17
  getForTile({ x, y }) {
34
18
  const result = new TileConnections();
35
19
  // Get all connections within 2 steps of the tile
36
- const edges = this.getConnectionsAt({ x, y });
20
+ const edges = this.getEdgesAt({ x, y });
37
21
  const edges2 = [
38
22
  ...edges,
39
23
  ...edges.flatMap(edge => {
40
24
  if (edge.x1 === x && edge.y1 === y) {
41
- return this.getConnectionsAt({ x: edge.x2, y: edge.y2 });
25
+ return this.getEdgesAt({ x: edge.x2, y: edge.y2 });
42
26
  }
43
27
  else {
44
- return this.getConnectionsAt({ x: edge.x1, y: edge.y1 });
28
+ return this.getEdgesAt({ x: edge.x1, y: edge.y1 });
45
29
  }
46
30
  }),
47
31
  ];
@@ -89,7 +73,7 @@ export default class GridConnections {
89
73
  }
90
74
  visited.add(`${current.x},${current.y}`);
91
75
  result.push(current);
92
- const edges = this.getConnectionsAt(current);
76
+ const edges = this.getEdgesAt(current);
93
77
  for (const edge of edges) {
94
78
  if (edge.x1 === current.x && edge.y1 === current.y) {
95
79
  queue.push({ x: edge.x2, y: edge.y2 });
@@ -127,28 +111,6 @@ export default class GridConnections {
127
111
  }
128
112
  return new GridConnections(edges);
129
113
  }
130
- /**
131
- * Check if two GridConnections objects are equal.
132
- * @param other The other GridConnections object to compare to.
133
- * @returns Whether the two objects are equal.
134
- */
135
- equals(other) {
136
- if (this.edges.length !== other.edges.length)
137
- return false;
138
- for (const edge of this.edges) {
139
- if (!other.isConnected(edge))
140
- return false;
141
- }
142
- return true;
143
- }
144
- /**
145
- * Deduplicate an array of edges.
146
- * @param edges The array of edges to deduplicate.
147
- * @returns The deduplicated array of edges.
148
- */
149
- static deduplicateEdges(edges) {
150
- return edges.filter((edge, index) => edges.findIndex(e => isSameEdge(e, edge)) === index);
151
- }
152
114
  insertColumn(index) {
153
115
  return new GridConnections(this.edges.flatMap(edge => {
154
116
  if ((edge.x1 < index && edge.x2 < index) ||
@@ -0,0 +1,25 @@
1
+ import { Edge, Position } from './primitives.js';
2
+ export default class GridZones {
3
+ readonly edges: readonly Edge[];
4
+ constructor(edges?: readonly Edge[]);
5
+ addEdge(edge: Edge): GridZones;
6
+ removeEdge(edge: Edge): GridZones;
7
+ hasEdge(edge: Edge): boolean;
8
+ getEdgesAt({ x, y }: Position): readonly Edge[];
9
+ /**
10
+ * Check if two GridZones objects are equal.
11
+ * @param other The other GridZones object to compare to.
12
+ * @returns Whether the two objects are equal.
13
+ */
14
+ equals(other: GridZones): boolean;
15
+ /**
16
+ * Deduplicate an array of edges.
17
+ * @param edges The array of edges to deduplicate.
18
+ * @returns The deduplicated array of edges.
19
+ */
20
+ static deduplicateEdges(edges: readonly Edge[]): readonly Edge[];
21
+ insertColumn(index: number): GridZones;
22
+ insertRow(index: number): GridZones;
23
+ removeColumn(index: number): GridZones;
24
+ removeRow(index: number): GridZones;
25
+ }
@@ -0,0 +1,91 @@
1
+ import { isSameEdge } from './dataHelper.js';
2
+ export default class GridZones {
3
+ constructor(edges) {
4
+ Object.defineProperty(this, "edges", {
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true,
8
+ value: void 0
9
+ });
10
+ this.edges = GridZones.deduplicateEdges(edges ?? []);
11
+ }
12
+ addEdge(edge) {
13
+ if (this.edges.some(e => isSameEdge(e, edge))) {
14
+ return this;
15
+ }
16
+ return new GridZones([...this.edges, edge]);
17
+ }
18
+ removeEdge(edge) {
19
+ return new GridZones(this.edges.filter(e => !isSameEdge(e, edge)));
20
+ }
21
+ hasEdge(edge) {
22
+ if (edge.x1 === edge.x2 && edge.y1 === edge.y2)
23
+ return true;
24
+ return this.edges.some(e => isSameEdge(e, edge));
25
+ }
26
+ getEdgesAt({ x, y }) {
27
+ return this.edges.filter(e => (e.x1 === x && e.y1 === y) || (e.x2 === x && e.y2 === y));
28
+ }
29
+ /**
30
+ * Check if two GridZones objects are equal.
31
+ * @param other The other GridZones object to compare to.
32
+ * @returns Whether the two objects are equal.
33
+ */
34
+ equals(other) {
35
+ if (this.edges.length !== other.edges.length)
36
+ return false;
37
+ for (const edge of this.edges) {
38
+ if (!other.hasEdge(edge))
39
+ return false;
40
+ }
41
+ return true;
42
+ }
43
+ /**
44
+ * Deduplicate an array of edges.
45
+ * @param edges The array of edges to deduplicate.
46
+ * @returns The deduplicated array of edges.
47
+ */
48
+ static deduplicateEdges(edges) {
49
+ return edges.filter((edge, index) => edges.findIndex(e => isSameEdge(e, edge)) === index);
50
+ }
51
+ insertColumn(index) {
52
+ return new GridZones(this.edges.map(edge => {
53
+ if (edge.x1 < index || edge.x2 < index) {
54
+ return edge;
55
+ }
56
+ else {
57
+ return { x1: edge.x1 + 1, y1: edge.y1, x2: edge.x2 + 1, y2: edge.y2 };
58
+ }
59
+ }));
60
+ }
61
+ insertRow(index) {
62
+ return new GridZones(this.edges.map(edge => {
63
+ if (edge.y1 < index || edge.y2 < index) {
64
+ return edge;
65
+ }
66
+ else {
67
+ return { x1: edge.x1, y1: edge.y1 + 1, x2: edge.x2, y2: edge.y2 + 1 };
68
+ }
69
+ }));
70
+ }
71
+ removeColumn(index) {
72
+ return new GridZones(this.edges.map(edge => {
73
+ if (edge.x1 > index || edge.x2 > index) {
74
+ return { x1: edge.x1 - 1, y1: edge.y1, x2: edge.x2 - 1, y2: edge.y2 };
75
+ }
76
+ else {
77
+ return edge;
78
+ }
79
+ }));
80
+ }
81
+ removeRow(index) {
82
+ return new GridZones(this.edges.map(edge => {
83
+ if (edge.y1 > index || edge.y2 > index) {
84
+ return { x1: edge.x1, y1: edge.y1 - 1, x2: edge.x2, y2: edge.y2 - 1 };
85
+ }
86
+ else {
87
+ return edge;
88
+ }
89
+ }));
90
+ }
91
+ }
@@ -0,0 +1,29 @@
1
+ import { AnyConfig } from '../config.js';
2
+ import GridData from '../grid.js';
3
+ import { Color, RuleState } from '../primitives.js';
4
+ import Rule, { SearchVariant } from './rule.js';
5
+ export default class CellCountPerZoneRule extends Rule {
6
+ readonly color: Color;
7
+ private static readonly CONFIGS;
8
+ private static readonly EXAMPLE_GRID_LIGHT;
9
+ private static readonly EXAMPLE_GRID_DARK;
10
+ private static readonly EXAMPLE_GRID_GRAY;
11
+ private static readonly SEARCH_VARIANTS;
12
+ /**
13
+ * **Every zone has the same number of &lt;color&gt; cells.**
14
+ *
15
+ * @param color - The color of the cells to count.
16
+ */
17
+ constructor(color: Color);
18
+ get id(): string;
19
+ get explanation(): string;
20
+ get configs(): readonly AnyConfig[] | null;
21
+ createExampleGrid(): GridData;
22
+ get searchVariants(): SearchVariant[];
23
+ validateGrid(grid: GridData): RuleState;
24
+ copyWith({ color }: {
25
+ color?: Color;
26
+ }): this;
27
+ withColor(color: Color): this;
28
+ }
29
+ export declare const instance: CellCountPerZoneRule;
@@ -0,0 +1,165 @@
1
+ import { ConfigType } from '../config.js';
2
+ import { array } from '../dataHelper.js';
3
+ import GridData, { NEIGHBOR_OFFSETS } from '../grid.js';
4
+ import GridZones from '../gridZones.js';
5
+ import { Color, State } from '../primitives.js';
6
+ import Rule from './rule.js';
7
+ class CellCountPerZoneRule extends Rule {
8
+ /**
9
+ * **Every zone has the same number of &lt;color&gt; cells.**
10
+ *
11
+ * @param color - The color of the cells to count.
12
+ */
13
+ constructor(color) {
14
+ super();
15
+ Object.defineProperty(this, "color", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: color
20
+ });
21
+ this.color = color;
22
+ }
23
+ get id() {
24
+ return `zone_cell_count`;
25
+ }
26
+ get explanation() {
27
+ return `Every zone has the same number of ${this.color} cells`;
28
+ }
29
+ get configs() {
30
+ return CellCountPerZoneRule.CONFIGS;
31
+ }
32
+ createExampleGrid() {
33
+ if (this.color === Color.Light) {
34
+ return CellCountPerZoneRule.EXAMPLE_GRID_LIGHT;
35
+ }
36
+ else if (this.color === Color.Dark) {
37
+ return CellCountPerZoneRule.EXAMPLE_GRID_DARK;
38
+ }
39
+ else {
40
+ return CellCountPerZoneRule.EXAMPLE_GRID_GRAY;
41
+ }
42
+ }
43
+ get searchVariants() {
44
+ return CellCountPerZoneRule.SEARCH_VARIANTS;
45
+ }
46
+ validateGrid(grid) {
47
+ let complete = true;
48
+ const visited = array(grid.width, grid.height, (i, j) => !grid.getTile(i, j).exists);
49
+ const zones = [];
50
+ while (true) {
51
+ const seed = grid.find((_tile, x, y) => !visited[y][x]);
52
+ if (!seed)
53
+ break;
54
+ const zone = {
55
+ positions: [],
56
+ completed: 0,
57
+ possible: 0,
58
+ };
59
+ const stack = [seed];
60
+ while (stack.length > 0) {
61
+ const { x, y } = stack.pop();
62
+ if (visited[y][x])
63
+ continue;
64
+ visited[y][x] = true;
65
+ zone.positions.push({ x, y });
66
+ if (grid.getTile(x, y).color === this.color) {
67
+ zone.completed++;
68
+ }
69
+ else if (grid.getTile(x, y).color === Color.Gray) {
70
+ zone.possible++;
71
+ complete = false;
72
+ }
73
+ for (const offset of NEIGHBOR_OFFSETS) {
74
+ const next = { x: x + offset.x, y: y + offset.y };
75
+ if (!grid.zones.edges.some(e => (e.x1 === x &&
76
+ e.y1 === y &&
77
+ e.x2 === next.x &&
78
+ e.y2 === next.y) ||
79
+ (e.x1 === next.x && e.y1 === next.y && e.x2 === x && e.y2 === y))) {
80
+ const nextTile = grid.getTile(next.x, next.y);
81
+ if (nextTile.exists) {
82
+ stack.push(next);
83
+ }
84
+ }
85
+ }
86
+ }
87
+ zones.push(zone);
88
+ }
89
+ if (zones.length <= 1) {
90
+ return { state: complete ? State.Satisfied : State.Incomplete };
91
+ }
92
+ else {
93
+ const errorZone = zones.find(z => zones.some(zz => zz !== z &&
94
+ (zz.completed > z.completed + z.possible ||
95
+ zz.completed + zz.possible < z.completed)));
96
+ if (errorZone) {
97
+ return {
98
+ state: State.Error,
99
+ positions: errorZone.positions,
100
+ };
101
+ }
102
+ else {
103
+ return { state: complete ? State.Satisfied : State.Incomplete };
104
+ }
105
+ }
106
+ }
107
+ copyWith({ color }) {
108
+ return new CellCountPerZoneRule(color ?? this.color);
109
+ }
110
+ withColor(color) {
111
+ return this.copyWith({ color });
112
+ }
113
+ }
114
+ Object.defineProperty(CellCountPerZoneRule, "CONFIGS", {
115
+ enumerable: true,
116
+ configurable: true,
117
+ writable: true,
118
+ value: Object.freeze([
119
+ {
120
+ type: ConfigType.Color,
121
+ default: Color.Light,
122
+ allowGray: true,
123
+ field: 'color',
124
+ description: 'Color',
125
+ configurable: true,
126
+ },
127
+ ])
128
+ });
129
+ Object.defineProperty(CellCountPerZoneRule, "EXAMPLE_GRID_LIGHT", {
130
+ enumerable: true,
131
+ configurable: true,
132
+ writable: true,
133
+ value: Object.freeze(GridData.create(['bwbbb', 'wbbwb', 'bbbwb', 'bwbwb'])
134
+ .withZones(new GridZones([
135
+ { x1: 0, y1: 1, x2: 0, y2: 2 },
136
+ { x1: 1, y1: 1, x2: 1, y2: 2 },
137
+ { x1: 2, y1: 1, x2: 2, y2: 2 },
138
+ { x1: 3, y1: 1, x2: 3, y2: 2 },
139
+ { x1: 4, y1: 1, x2: 4, y2: 2 },
140
+ ]))
141
+ .addRule(new CellCountPerZoneRule(Color.Light)))
142
+ });
143
+ Object.defineProperty(CellCountPerZoneRule, "EXAMPLE_GRID_DARK", {
144
+ enumerable: true,
145
+ configurable: true,
146
+ writable: true,
147
+ value: Object.freeze(CellCountPerZoneRule.EXAMPLE_GRID_LIGHT.withTiles(tiles => tiles.map(row => row.map(tile => tile.withColor(tile.color === Color.Dark ? Color.Light : Color.Dark)))))
148
+ });
149
+ Object.defineProperty(CellCountPerZoneRule, "EXAMPLE_GRID_GRAY", {
150
+ enumerable: true,
151
+ configurable: true,
152
+ writable: true,
153
+ value: Object.freeze(CellCountPerZoneRule.EXAMPLE_GRID_LIGHT.withTiles(tiles => tiles.map(row => row.map(tile => tile.withColor(tile.color === Color.Light ? Color.Gray : tile.color)))))
154
+ });
155
+ Object.defineProperty(CellCountPerZoneRule, "SEARCH_VARIANTS", {
156
+ enumerable: true,
157
+ configurable: true,
158
+ writable: true,
159
+ value: [
160
+ new CellCountPerZoneRule(Color.Light).searchVariant(),
161
+ new CellCountPerZoneRule(Color.Dark).searchVariant(),
162
+ ]
163
+ });
164
+ export default CellCountPerZoneRule;
165
+ export const instance = new CellCountPerZoneRule(Color.Light);
@@ -1,4 +1,5 @@
1
1
  export { instance as BanPatternRule } from './banPatternRule.js';
2
+ export { instance as CellCountPerZoneRule } from './cellCountPerZoneRule.js';
2
3
  export { instance as CellCountRule } from './cellCountRule.js';
3
4
  export { instance as CompletePatternRule } from './completePatternRule.js';
4
5
  export { instance as ConnectAllRule } from './connectAllRule.js';
@@ -3,6 +3,7 @@
3
3
  // @ts-nocheck
4
4
  // noinspection JSUnusedGlobalSymbols
5
5
  export { instance as BanPatternRule } from './banPatternRule.js';
6
+ export { instance as CellCountPerZoneRule } from './cellCountPerZoneRule.js';
6
7
  export { instance as CellCountRule } from './cellCountRule.js';
7
8
  export { instance as CompletePatternRule } from './completePatternRule.js';
8
9
  export { instance as ConnectAllRule } from './connectAllRule.js';
@@ -4,6 +4,7 @@ import Rule from '../rules/rule.js';
4
4
  import TileData from '../tile.js';
5
5
  import Symbol from '../symbols/symbol.js';
6
6
  import { Puzzle } from '../puzzle.js';
7
+ import GridZones from '../gridZones.js';
7
8
  export default abstract class SerializerBase {
8
9
  abstract get version(): number;
9
10
  abstract stringifyTile(tile: TileData): string;
@@ -14,6 +15,8 @@ export default abstract class SerializerBase {
14
15
  abstract parseSymbol(str: string): Symbol;
15
16
  abstract stringifyConnections(connections: GridConnections): string;
16
17
  abstract parseConnections(input: string): GridConnections;
18
+ abstract stringifyZones(zones: GridZones): string;
19
+ abstract parseZones(input: string): GridZones;
17
20
  abstract stringifyTiles(tiles: readonly (readonly TileData[])[]): string;
18
21
  abstract parseTiles(input: string): TileData[][];
19
22
  abstract stringifyRules(rules: readonly Rule[]): string;
@@ -8,6 +8,7 @@ import { AnyConfig } from '../config.js';
8
8
  import SerializerBase from './serializerBase.js';
9
9
  import { Puzzle } from '../puzzle.js';
10
10
  import { ControlLine } from '../rules/musicControlLine.js';
11
+ import GridZones from '../gridZones.js';
11
12
  export default class SerializerV0 extends SerializerBase {
12
13
  readonly version = 0;
13
14
  stringifyTile(tile: TileData): string;
@@ -23,6 +24,8 @@ export default class SerializerV0 extends SerializerBase {
23
24
  parseSymbol(str: string): Symbol;
24
25
  stringifyConnections(connections: GridConnections): string;
25
26
  parseConnections(input: string): GridConnections;
27
+ stringifyZones(zones: GridZones): string;
28
+ parseZones(input: string): GridZones;
26
29
  stringifyTiles(tiles: readonly (readonly TileData[])[]): string;
27
30
  parseTiles(input: string): TileData[][];
28
31
  stringifyRules(rules: readonly Rule[]): string;
@@ -8,6 +8,7 @@ import { allRules } from '../rules/index.js';
8
8
  import { allSymbols } from '../symbols/index.js';
9
9
  import SerializerBase from './serializerBase.js';
10
10
  import { ControlLine, Row } from '../rules/musicControlLine.js';
11
+ import GridZones from '../gridZones.js';
11
12
  const OFFSETS = [
12
13
  { x: 0, y: -1 },
13
14
  { x: -1, y: 0 },
@@ -314,6 +315,19 @@ export default class SerializerV0 extends SerializerBase {
314
315
  const tiles = array(width, Math.ceil(data.length / width), (x, y) => data[y * width + x]);
315
316
  return GridConnections.create(tiles.map(row => row.join('')));
316
317
  }
318
+ stringifyZones(zones) {
319
+ return `Z${zones.edges.map(edge => `${edge.x1}_${edge.y1}_${edge.x2 - edge.x1}_${edge.y2 - edge.y1}`).join(':')}`;
320
+ }
321
+ parseZones(input) {
322
+ if (!input.startsWith('Z')) {
323
+ throw new Error('Invalid grid zones\n' + input);
324
+ }
325
+ const data = input.slice(1).split(':');
326
+ return new GridZones(data.map(entry => {
327
+ const [x1, y1, w, h] = entry.split('_').map(Number);
328
+ return { x1, y1, x2: x1 + w, y2: y1 + h };
329
+ }));
330
+ }
317
331
  stringifyTiles(tiles) {
318
332
  return `T${tiles[0]?.length ?? 0}:${tiles.map(row => row.map(tile => this.stringifyTile(tile)).join('')).join('')}`;
319
333
  }
@@ -368,6 +382,7 @@ export default class SerializerV0 extends SerializerBase {
368
382
  const data = [
369
383
  this.stringifyTiles(grid.tiles),
370
384
  this.stringifyConnections(grid.connections),
385
+ this.stringifyZones(grid.zones),
371
386
  this.stringifySymbols(grid.symbols),
372
387
  this.stringifyRules(grid.rules),
373
388
  ];
@@ -379,6 +394,7 @@ export default class SerializerV0 extends SerializerBase {
379
394
  let height;
380
395
  let tiles;
381
396
  let connections;
397
+ let zones;
382
398
  let symbols;
383
399
  let rules;
384
400
  for (const d of data) {
@@ -391,6 +407,9 @@ export default class SerializerV0 extends SerializerBase {
391
407
  else if (d.startsWith('C')) {
392
408
  connections = this.parseConnections(d);
393
409
  }
410
+ else if (d.startsWith('Z')) {
411
+ zones = this.parseZones(d);
412
+ }
394
413
  else if (d.startsWith('S')) {
395
414
  symbols = this.parseSymbols(d);
396
415
  }
@@ -401,7 +420,7 @@ export default class SerializerV0 extends SerializerBase {
401
420
  throw new Error(`Invalid data: ${d}`);
402
421
  }
403
422
  }
404
- return new GridData(width ?? tiles?.[0].length ?? 0, height ?? tiles?.length ?? 0, tiles, connections, symbols, rules);
423
+ return new GridData(width ?? tiles?.[0].length ?? 0, height ?? tiles?.length ?? 0, tiles, connections, zones, symbols, rules);
405
424
  }
406
425
  stringifyPuzzle(puzzle) {
407
426
  let grid = puzzle.grid;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ConfigType, configEquals } from './data/config.js';
2
2
  import Configurable from './data/configurable.js';
3
- import { CachedAccess, allEqual, array, directionToRotation, escape, maxBy, minBy, move, orientationToRotation, resize, unescape } from './data/dataHelper.js';
3
+ import { CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape } from './data/dataHelper.js';
4
4
  import { isEventHandler } from './data/events/eventHelper.js';
5
5
  import { handlesFinalValidation } from './data/events/onFinalValidation.js';
6
6
  import { handlesGridChange } from './data/events/onGridChange.js';
@@ -8,12 +8,14 @@ import { handlesGridResize } from './data/events/onGridResize.js';
8
8
  import { handlesSetGrid } from './data/events/onSetGrid.js';
9
9
  import { handlesSymbolDisplay } from './data/events/onSymbolDisplay.js';
10
10
  import { handlesSymbolValidation } from './data/events/onSymbolValidation.js';
11
- import GridData from './data/grid.js';
11
+ import GridData, { NEIGHBOR_OFFSETS } from './data/grid.js';
12
12
  import GridConnections from './data/gridConnections.js';
13
+ import GridZones from './data/gridZones.js';
13
14
  import Instruction from './data/instruction.js';
14
15
  import { COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle } from './data/primitives.js';
15
16
  import { MetadataSchema, PuzzleSchema } from './data/puzzle.js';
16
17
  import BanPatternRule from './data/rules/banPatternRule.js';
18
+ import CellCountPerZoneRule from './data/rules/cellCountPerZoneRule.js';
17
19
  import CellCountRule from './data/rules/cellCountRule.js';
18
20
  import CompletePatternRule from './data/rules/completePatternRule.js';
19
21
  import ConnectAllRule from './data/rules/connectAllRule.js';
@@ -96,4 +98,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
96
98
  import TileData from './data/tile.js';
97
99
  import TileConnections from './data/tileConnections.js';
98
100
  import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
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, };
101
+ export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver, UndercluedSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // noinspection JSUnusedGlobalSymbols
4
4
  import { ConfigType, configEquals } from './data/config.js';
5
5
  import Configurable from './data/configurable.js';
6
- import { CachedAccess, allEqual, array, directionToRotation, escape, maxBy, minBy, move, orientationToRotation, resize, unescape } from './data/dataHelper.js';
6
+ import { CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape } from './data/dataHelper.js';
7
7
  import { isEventHandler } from './data/events/eventHelper.js';
8
8
  import { handlesFinalValidation } from './data/events/onFinalValidation.js';
9
9
  import { handlesGridChange } from './data/events/onGridChange.js';
@@ -11,12 +11,14 @@ import { handlesGridResize } from './data/events/onGridResize.js';
11
11
  import { handlesSetGrid } from './data/events/onSetGrid.js';
12
12
  import { handlesSymbolDisplay } from './data/events/onSymbolDisplay.js';
13
13
  import { handlesSymbolValidation } from './data/events/onSymbolValidation.js';
14
- import GridData from './data/grid.js';
14
+ import GridData, { NEIGHBOR_OFFSETS } from './data/grid.js';
15
15
  import GridConnections from './data/gridConnections.js';
16
+ import GridZones from './data/gridZones.js';
16
17
  import Instruction from './data/instruction.js';
17
18
  import { COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle } from './data/primitives.js';
18
19
  import { MetadataSchema, PuzzleSchema } from './data/puzzle.js';
19
20
  import BanPatternRule from './data/rules/banPatternRule.js';
21
+ import CellCountPerZoneRule from './data/rules/cellCountPerZoneRule.js';
20
22
  import CellCountRule from './data/rules/cellCountRule.js';
21
23
  import CompletePatternRule from './data/rules/completePatternRule.js';
22
24
  import ConnectAllRule from './data/rules/connectAllRule.js';
@@ -99,4 +101,4 @@ import ViewpointSymbol from './data/symbols/viewpointSymbol.js';
99
101
  import TileData from './data/tile.js';
100
102
  import TileConnections from './data/tileConnections.js';
101
103
  import validateGrid, { aggregateState, applyFinalOverrides } from './data/validate.js';
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, };
104
+ export { ConfigType, configEquals, Configurable, CachedAccess, allEqual, array, directionToRotation, escape, isSameEdge, maxBy, minBy, move, orientationToRotation, resize, unescape, isEventHandler, handlesFinalValidation, handlesGridChange, handlesGridResize, handlesSetGrid, handlesSymbolDisplay, handlesSymbolValidation, GridData, NEIGHBOR_OFFSETS, GridConnections, GridZones, Instruction, COMPARISONS, Color, Comparison, DIRECTIONS, Direction, MajorRule, Mode, ORIENTATIONS, Orientation, State, directionToggle, orientationToggle, MetadataSchema, PuzzleSchema, BanPatternRule, CellCountPerZoneRule, CellCountRule, CompletePatternRule, ConnectAllRule, CustomRule, ForesightRule, allRules, ControlLine, Row, MusicGridRule, MysteryRule, OffByXRule, PerfectionRule, RegionAreaRule, RegionShapeRule, Rule, SameShapeRule, SymbolsPerRegionRule, UndercluedRule, UniqueShapeRule, Serializer, Compressor, CompressorBase, DeflateCompressor, GzipCompressor, StreamCompressor, SerializerBase, SerializerV0, getShapeVariants, normalizeShape, positionsToShape, shapeEquals, tilesToShape, allSolvers, BacktrackSolver, BTModule, BTGridData, BTTile, IntArray2D, colorToBTTile, createOneTileResult, getOppositeColor, BanPatternBTModule, CellCountBTModule, ConnectAllBTModule, RegionAreaBTModule, RegionShapeBTModule, SameShapeBTModule, SymbolsPerRegionBTModule, UniqueShapeBTModule, AreaNumberBTModule, DartBTModule, DirectionLinkerBTModule, GalaxyBTModule, LetterBTModule, LotusBTModule, MinesweeperBTModule, MyopiaBTModule, ViewpointBTModule, Solver, UndercluedSolver, AreaNumberModule, CellCountModule, ConnectAllModule, DartModule, allZ3Modules, LetterModule, MyopiaModule, RegionAreaModule, ViewpointModule, Z3Module, convertDirection, Z3Solver, Z3SolverContext, AreaNumberSymbol, CustomIconSymbol, CustomSymbol, CustomTextSymbol, DartSymbol, DirectionLinkerSymbol, GalaxySymbol, HiddenSymbol, allSymbols, LetterSymbol, LotusSymbol, MinesweeperSymbol, MultiEntrySymbol, MyopiaSymbol, NumberSymbol, Symbol, ViewpointSymbol, TileData, TileConnections, validateGrid, aggregateState, applyFinalOverrides, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logic-pad/core",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",