@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.
- package/assets/logic-core.global.d.ts +54 -3434
- package/dist/data/primitives.d.ts +19 -1
- package/dist/data/primitives.js +20 -0
- package/dist/data/rules/banPatternRule.js +3 -1
- package/dist/data/rules/lyingSymbolRule.d.ts +30 -0
- package/dist/data/rules/lyingSymbolRule.js +214 -0
- package/dist/data/rules/mysteryRule.js +1 -1
- package/dist/data/rules/offByXRule.d.ts +1 -1
- package/dist/data/rules/offByXRule.js +7 -3
- package/dist/data/rules/rules.gen.d.ts +1 -0
- package/dist/data/rules/rules.gen.js +1 -0
- package/dist/data/solver/backtrack/symbols/directionLinker.js +7 -6
- package/dist/data/solver/z3/z3SolverContext.d.ts +2 -797
- package/dist/data/validate.d.ts +1 -1
- package/dist/data/validate.js +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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;
|
package/dist/data/primitives.js
CHANGED
|
@@ -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.
|
|
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);
|
|
@@ -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(
|
|
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(
|
|
42
|
-
return {
|
|
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(
|
|
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 (
|
|
86
|
+
if (ratings.length > 0) {
|
|
86
87
|
return { tilesNeedCheck, ratings };
|
|
87
88
|
}
|
|
88
89
|
const queue = this.initialPositions
|