@logic-pad/core 0.4.5 → 0.5.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.
@@ -17,9 +17,25 @@ export declare enum MajorRule {
17
17
  Underclued = "underclued"
18
18
  }
19
19
  export declare enum State {
20
+ /**
21
+ * Describes the violation of a rule.
22
+ */
20
23
  Error = "error",
24
+ /**
25
+ * Describes that a rule is satisfied and complete in the current grid.
26
+ */
21
27
  Satisfied = "satisfied",
22
- Incomplete = "incomplete"
28
+ /**
29
+ * Describes that a rule is not violated, but is not yet complete in the current grid.
30
+ */
31
+ Incomplete = "incomplete",
32
+ /**
33
+ * Describes that a rule is violated but ignored due to the effect of another rule.
34
+ */
35
+ Ignored = "ignored"
36
+ }
37
+ export declare namespace State {
38
+ function isSatisfied(state: State): boolean;
23
39
  }
24
40
  export type RuleState = {
25
41
  readonly state: State.Error;
@@ -28,6 +44,8 @@ export type RuleState = {
28
44
  readonly state: State.Satisfied;
29
45
  } | {
30
46
  readonly state: State.Incomplete;
47
+ } | {
48
+ readonly state: State.Ignored;
31
49
  };
32
50
  export interface GridState {
33
51
  final: State;
@@ -9,9 +9,29 @@ export var MajorRule;
9
9
  })(MajorRule || (MajorRule = {}));
10
10
  export var State;
11
11
  (function (State) {
12
+ /**
13
+ * Describes the violation of a rule.
14
+ */
12
15
  State["Error"] = "error";
16
+ /**
17
+ * Describes that a rule is satisfied and complete in the current grid.
18
+ */
13
19
  State["Satisfied"] = "satisfied";
20
+ /**
21
+ * Describes that a rule is not violated, but is not yet complete in the current grid.
22
+ */
14
23
  State["Incomplete"] = "incomplete";
24
+ /**
25
+ * Describes that a rule is violated but ignored due to the effect of another rule.
26
+ */
27
+ State["Ignored"] = "ignored";
28
+ })(State || (State = {}));
29
+ // eslint-disable-next-line @typescript-eslint/no-namespace
30
+ (function (State) {
31
+ function isSatisfied(state) {
32
+ return state === State.Satisfied || state === State.Ignored;
33
+ }
34
+ State.isSatisfied = isSatisfied;
15
35
  })(State || (State = {}));
16
36
  export var Color;
17
37
  (function (Color) {
@@ -26,7 +26,9 @@ class BanPatternRule extends Rule {
26
26
  });
27
27
  this.pattern = pattern
28
28
  // unlock all tiles
29
- .withTiles(tiles => tiles.map(row => row.map(t => t.withFixed(false))))
29
+ .withTiles(tiles => tiles.map(row => row.map(t => t.exists
30
+ ? t.withFixed(false)
31
+ : t.copyWith({ exists: true, color: Color.Gray, fixed: false }))))
30
32
  // strip all symbols and rules
31
33
  .withRules([])
32
34
  .withSymbols(new Map());
@@ -0,0 +1,30 @@
1
+ import { AnyConfig } from '../config.js';
2
+ import { FinalValidationHandler } from '../events/onFinalValidation.js';
3
+ import GridData from '../grid.js';
4
+ import { GridState, RuleState } from '../primitives.js';
5
+ import Rule, { SearchVariant } from './rule.js';
6
+ export default class LyingSymbolRule extends Rule implements FinalValidationHandler {
7
+ readonly count: number;
8
+ private static readonly EXAMPLE_GRID;
9
+ private static readonly CONFIGS;
10
+ private static readonly SEARCH_VARIANTS;
11
+ /**
12
+ * **<count> symbols are lying and can be ignored**
13
+ *
14
+ * @param count Number of lying symbols
15
+ */
16
+ constructor(count: number);
17
+ get id(): string;
18
+ get explanation(): string;
19
+ get configs(): readonly AnyConfig[] | null;
20
+ createExampleGrid(): GridData;
21
+ get searchVariants(): SearchVariant[];
22
+ validateGrid(_: GridData): RuleState;
23
+ get isSingleton(): boolean;
24
+ onFinalValidation(grid: GridData, solution: GridData | null, state: GridState): GridState;
25
+ copyWith({ count }: {
26
+ count?: number;
27
+ }): this;
28
+ withCount(count: number): this;
29
+ }
30
+ export declare const instance: LyingSymbolRule;
@@ -0,0 +1,214 @@
1
+ import { ConfigType } from '../config.js';
2
+ import GridData from '../grid.js';
3
+ import { Color, State } from '../primitives.js';
4
+ import Rule from './rule.js';
5
+ import CustomIconSymbol from '../symbols/customIconSymbol.js';
6
+ import validateGrid from '../validate.js';
7
+ import Symbol from '../symbols/symbol.js';
8
+ class IgnoredSymbol extends Symbol {
9
+ constructor(symbol) {
10
+ super(symbol.x, symbol.y);
11
+ Object.defineProperty(this, "symbol", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: symbol
16
+ });
17
+ this.symbol = symbol;
18
+ }
19
+ get id() {
20
+ return this.symbol.id;
21
+ }
22
+ get explanation() {
23
+ return this.symbol.explanation;
24
+ }
25
+ get configs() {
26
+ return this.symbol.configs;
27
+ }
28
+ createExampleGrid() {
29
+ return this.symbol.createExampleGrid();
30
+ }
31
+ get necessaryForCompletion() {
32
+ return this.symbol.necessaryForCompletion;
33
+ }
34
+ get visibleWhenSolving() {
35
+ return this.symbol.visibleWhenSolving;
36
+ }
37
+ get sortOrder() {
38
+ return this.symbol.sortOrder;
39
+ }
40
+ validateSymbol(_grid, _solution) {
41
+ return State.Ignored;
42
+ }
43
+ copyWith({ symbol }) {
44
+ return new IgnoredSymbol(symbol ?? this.symbol);
45
+ }
46
+ withSymbol(symbol) {
47
+ return this.copyWith({ symbol });
48
+ }
49
+ }
50
+ class IgnoredRule extends Rule {
51
+ constructor(rule, state) {
52
+ super();
53
+ Object.defineProperty(this, "rule", {
54
+ enumerable: true,
55
+ configurable: true,
56
+ writable: true,
57
+ value: rule
58
+ });
59
+ Object.defineProperty(this, "state", {
60
+ enumerable: true,
61
+ configurable: true,
62
+ writable: true,
63
+ value: state
64
+ });
65
+ this.rule = rule;
66
+ this.state = state;
67
+ }
68
+ get searchVariants() {
69
+ return [];
70
+ }
71
+ get id() {
72
+ return this.rule.id;
73
+ }
74
+ get explanation() {
75
+ return this.rule.explanation;
76
+ }
77
+ createExampleGrid() {
78
+ return this.rule.createExampleGrid();
79
+ }
80
+ get necessaryForCompletion() {
81
+ return this.rule.necessaryForCompletion;
82
+ }
83
+ get visibleWhenSolving() {
84
+ return this.rule.visibleWhenSolving;
85
+ }
86
+ get isSingleton() {
87
+ return this.rule.isSingleton;
88
+ }
89
+ validateGrid(_grid) {
90
+ if (this.state === State.Error)
91
+ return { state: State.Error, positions: [] };
92
+ else
93
+ return { state: this.state };
94
+ }
95
+ copyWith({ rule, state }) {
96
+ return new IgnoredRule(rule ?? this.rule, state ?? this.state);
97
+ }
98
+ }
99
+ class LyingSymbolRule extends Rule {
100
+ /**
101
+ * **<count> symbols are lying and can be ignored**
102
+ *
103
+ * @param count Number of lying symbols
104
+ */
105
+ constructor(count) {
106
+ super();
107
+ Object.defineProperty(this, "count", {
108
+ enumerable: true,
109
+ configurable: true,
110
+ writable: true,
111
+ value: count
112
+ });
113
+ this.count = count;
114
+ }
115
+ get id() {
116
+ return `lying_symbols`;
117
+ }
118
+ get explanation() {
119
+ return `${this.count} symbol${this.count <= 1 ? ' is' : 's are'} *lying* and can be ignored`;
120
+ }
121
+ get configs() {
122
+ return LyingSymbolRule.CONFIGS;
123
+ }
124
+ createExampleGrid() {
125
+ return LyingSymbolRule.EXAMPLE_GRID;
126
+ }
127
+ get searchVariants() {
128
+ return LyingSymbolRule.SEARCH_VARIANTS;
129
+ }
130
+ validateGrid(_) {
131
+ return { state: State.Incomplete };
132
+ }
133
+ get isSingleton() {
134
+ return true;
135
+ }
136
+ onFinalValidation(grid, solution, state) {
137
+ const ignoredSymbols = [];
138
+ state.symbols.forEach((values, key) => {
139
+ values.forEach((state, idx) => {
140
+ if (state === State.Error)
141
+ ignoredSymbols.push([key, idx]);
142
+ });
143
+ });
144
+ if (ignoredSymbols.length > this.count) {
145
+ const thisIdx = grid.rules.findIndex(rule => rule.id === this.id);
146
+ return {
147
+ final: State.Error,
148
+ rules: state.rules.map((rule, idx) => idx === thisIdx ? { state: State.Error, positions: [] } : rule),
149
+ symbols: state.symbols,
150
+ };
151
+ }
152
+ const newSymbols = new Map();
153
+ grid.symbols.forEach((values, key) => {
154
+ values.forEach((symbol, idx) => {
155
+ if (!newSymbols.has(key)) {
156
+ newSymbols.set(key, []);
157
+ }
158
+ if (ignoredSymbols.some(([k, i]) => k === key && i === idx)) {
159
+ newSymbols.get(key).push(new IgnoredSymbol(symbol));
160
+ }
161
+ else {
162
+ newSymbols.get(key).push(symbol);
163
+ }
164
+ });
165
+ });
166
+ const newRules = grid.rules.map(rule => rule.id === this.id
167
+ ? new IgnoredRule(this, ignoredSymbols.length === this.count
168
+ ? State.Satisfied
169
+ : grid.getTileCount(true, false, Color.Gray) === 0
170
+ ? State.Error
171
+ : State.Incomplete)
172
+ : rule);
173
+ return validateGrid(grid.copyWith({ rules: newRules, symbols: newSymbols }), solution);
174
+ }
175
+ copyWith({ count }) {
176
+ return new LyingSymbolRule(count ?? this.count);
177
+ }
178
+ withCount(count) {
179
+ return this.copyWith({ count });
180
+ }
181
+ }
182
+ Object.defineProperty(LyingSymbolRule, "EXAMPLE_GRID", {
183
+ enumerable: true,
184
+ configurable: true,
185
+ writable: true,
186
+ value: Object.freeze(GridData.create(['.']).addSymbol(new CustomIconSymbol('', GridData.create([]), 0, 0, 'MdOutlineDeblur')))
187
+ });
188
+ Object.defineProperty(LyingSymbolRule, "CONFIGS", {
189
+ enumerable: true,
190
+ configurable: true,
191
+ writable: true,
192
+ value: Object.freeze([
193
+ {
194
+ type: ConfigType.Number,
195
+ default: 1,
196
+ min: 1,
197
+ max: 100,
198
+ step: 1,
199
+ field: 'count',
200
+ description: 'Number of liars',
201
+ configurable: true,
202
+ },
203
+ ])
204
+ });
205
+ Object.defineProperty(LyingSymbolRule, "SEARCH_VARIANTS", {
206
+ enumerable: true,
207
+ configurable: true,
208
+ writable: true,
209
+ value: [
210
+ new LyingSymbolRule(1).searchVariant(),
211
+ ]
212
+ });
213
+ export default LyingSymbolRule;
214
+ export const instance = new LyingSymbolRule(1);
@@ -52,7 +52,7 @@ class MysteryRule extends Rule {
52
52
  return false;
53
53
  }
54
54
  onFinalValidation(grid, _solution, state) {
55
- if (state.final === State.Satisfied)
55
+ if (State.isSatisfied(state.final))
56
56
  return state;
57
57
  if (grid.colorEquals(this.solution))
58
58
  return {
@@ -20,7 +20,7 @@ export default class OffByXRule extends Rule implements SymbolValidationHandler
20
20
  get configs(): readonly AnyConfig[] | null;
21
21
  createExampleGrid(): GridData;
22
22
  get searchVariants(): SearchVariant[];
23
- validateGrid(_grid: GridData): RuleState;
23
+ validateGrid(grid: GridData): RuleState;
24
24
  onSymbolValidation(grid: GridData, symbol: Symbol, _validator: (grid: GridData) => State): State | undefined;
25
25
  get isSingleton(): boolean;
26
26
  copyWith({ number }: {
@@ -1,6 +1,6 @@
1
1
  import { ConfigType } from '../config.js';
2
2
  import GridData from '../grid.js';
3
- import { State } from '../primitives.js';
3
+ import { Color, State } from '../primitives.js';
4
4
  import AreaNumberSymbol from '../symbols/areaNumberSymbol.js';
5
5
  import NumberSymbol from '../symbols/numberSymbol.js';
6
6
  import Rule from './rule.js';
@@ -38,8 +38,12 @@ class OffByXRule extends Rule {
38
38
  get searchVariants() {
39
39
  return OffByXRule.SEARCH_VARIANTS;
40
40
  }
41
- validateGrid(_grid) {
42
- return { state: State.Incomplete };
41
+ validateGrid(grid) {
42
+ return {
43
+ state: grid.getTileCount(true, false, Color.Gray) === 0
44
+ ? State.Satisfied
45
+ : State.Incomplete,
46
+ };
43
47
  }
44
48
  onSymbolValidation(grid, symbol, _validator) {
45
49
  if (symbol instanceof NumberSymbol) {
@@ -5,6 +5,7 @@ export { instance as CompletePatternRule } from './completePatternRule.js';
5
5
  export { instance as ConnectAllRule } from './connectAllRule.js';
6
6
  export { instance as CustomRule } from './customRule.js';
7
7
  export { instance as ForesightRule } from './foresightRule.js';
8
+ export { instance as LyingSymbolRule } from './lyingSymbolRule.js';
8
9
  export { instance as MusicGridRule } from './musicGridRule.js';
9
10
  export { instance as MysteryRule } from './mysteryRule.js';
10
11
  export { instance as OffByXRule } from './offByXRule.js';
@@ -9,6 +9,7 @@ export { instance as CompletePatternRule } from './completePatternRule.js';
9
9
  export { instance as ConnectAllRule } from './connectAllRule.js';
10
10
  export { instance as CustomRule } from './customRule.js';
11
11
  export { instance as ForesightRule } from './foresightRule.js';
12
+ export { instance as LyingSymbolRule } from './lyingSymbolRule.js';
12
13
  export { instance as MusicGridRule } from './musicGridRule.js';
13
14
  export { instance as MysteryRule } from './mysteryRule.js';
14
15
  export { instance as OffByXRule } from './offByXRule.js';
@@ -42,7 +42,6 @@ export default class DirectionLinkerBTModule extends BTModule {
42
42
  this.initialPositions = this.getInitialPositions();
43
43
  const tilesNeedCheck = IntArray2D.create(grid.width, grid.height);
44
44
  const ratings = [];
45
- let checkable = false;
46
45
  for (const pos of this.initialPositions) {
47
46
  const tile = grid.isInBound(pos.x, pos.y)
48
47
  ? grid.getTile(pos.x, pos.y)
@@ -53,6 +52,10 @@ export default class DirectionLinkerBTModule extends BTModule {
53
52
  grid.getTile(oppoPos.x, oppoPos.y) === BTTile.NonExist)
54
53
  return false;
55
54
  else {
55
+ if (grid.getTile(oppoPos.x, oppoPos.y) === BTTile.Empty) {
56
+ tilesNeedCheck.set(oppoPos.x, oppoPos.y, 1);
57
+ ratings.push({ pos: oppoPos, score: 1 });
58
+ }
56
59
  tilesNeedCheck.set(pos.x, pos.y, 1);
57
60
  ratings.push({ pos, score: 1 });
58
61
  }
@@ -69,20 +72,18 @@ export default class DirectionLinkerBTModule extends BTModule {
69
72
  if (oppoPos !== null) {
70
73
  const oppoTile = grid.getTile(oppoPos.x, oppoPos.y);
71
74
  if (oppoTile === BTTile.Empty) {
72
- tilesNeedCheck.set(pos.x, pos.y, 1);
73
- ratings.push({ pos, score: 1 });
75
+ tilesNeedCheck.set(oppoPos.x, oppoPos.y, 1);
76
+ ratings.push({ pos: oppoPos, score: 1 });
74
77
  }
75
78
  else if (oppoTile === BTTile.NonExist)
76
79
  return false;
77
- else
78
- checkable = true;
79
80
  }
80
81
  else {
81
82
  return false;
82
83
  }
83
84
  }
84
85
  }
85
- if (!checkable) {
86
+ if (ratings.length > 0) {
86
87
  return { tilesNeedCheck, ratings };
87
88
  }
88
89
  const queue = this.initialPositions