@logic-pad/core 0.26.2 → 0.26.3
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 +3264 -3264
- package/dist/benchmark/helper.d.ts +21 -0
- package/dist/benchmark/helper.js +34 -0
- package/dist/benchmark/prepareBench.d.ts +1 -0
- package/dist/benchmark/prepareBench.js +140 -0
- package/dist/benchmark/runBench.d.ts +1 -0
- package/dist/benchmark/runBench.js +206 -0
- package/dist/src/data/config.d.ts +119 -0
- package/dist/src/data/config.js +72 -0
- package/dist/src/data/configurable.d.ts +14 -0
- package/dist/src/data/configurable.js +26 -0
- package/dist/src/data/dataHelper.d.ts +92 -0
- package/dist/src/data/dataHelper.js +217 -0
- package/dist/src/data/events/eventHelper.d.ts +1 -0
- package/dist/src/data/events/eventHelper.js +6 -0
- package/dist/src/data/events/onFinalValidation.d.ts +14 -0
- package/dist/src/data/events/onFinalValidation.js +4 -0
- package/dist/src/data/events/onGetTile.d.ts +7 -0
- package/dist/src/data/events/onGetTile.js +4 -0
- package/dist/src/data/events/onGridChange.d.ts +6 -0
- package/dist/src/data/events/onGridChange.js +4 -0
- package/dist/src/data/events/onGridResize.d.ts +9 -0
- package/dist/src/data/events/onGridResize.js +4 -0
- package/dist/src/data/events/onSetGrid.d.ts +7 -0
- package/dist/src/data/events/onSetGrid.js +19 -0
- package/dist/src/data/events/onSymbolDisplay.d.ts +16 -0
- package/dist/src/data/events/onSymbolDisplay.js +4 -0
- package/dist/src/data/events/onSymbolMerge.d.ts +10 -0
- package/dist/src/data/events/onSymbolMerge.js +4 -0
- package/dist/src/data/events/onSymbolValidation.d.ts +18 -0
- package/dist/src/data/events/onSymbolValidation.js +4 -0
- package/dist/src/data/grid.d.ts +410 -0
- package/dist/src/data/grid.js +1106 -0
- package/dist/src/data/gridConnections.d.ts +25 -0
- package/dist/src/data/gridConnections.js +309 -0
- package/dist/src/data/gridZones.d.ts +26 -0
- package/dist/src/data/gridZones.js +117 -0
- package/dist/src/data/instruction.d.ts +26 -0
- package/dist/src/data/instruction.js +29 -0
- package/dist/src/data/primitives.d.ts +138 -0
- package/dist/src/data/primitives.js +177 -0
- package/dist/src/data/puzzle.d.ts +73 -0
- package/dist/src/data/puzzle.js +105 -0
- package/dist/src/data/rules/banPatternRule.d.ts +30 -0
- package/dist/src/data/rules/banPatternRule.js +125 -0
- package/dist/src/data/rules/cellCountPerZoneRule.d.ts +23 -0
- package/dist/src/data/rules/cellCountPerZoneRule.js +39 -0
- package/dist/src/data/rules/cellCountRule.d.ts +33 -0
- package/dist/src/data/rules/cellCountRule.js +138 -0
- package/dist/src/data/rules/completePatternRule.d.ts +24 -0
- package/dist/src/data/rules/completePatternRule.js +46 -0
- package/dist/src/data/rules/connectAllRule.d.ts +29 -0
- package/dist/src/data/rules/connectAllRule.js +88 -0
- package/dist/src/data/rules/connectZonesRule.d.ts +29 -0
- package/dist/src/data/rules/connectZonesRule.js +111 -0
- package/dist/src/data/rules/containsShapeRule.d.ts +34 -0
- package/dist/src/data/rules/containsShapeRule.js +125 -0
- package/dist/src/data/rules/customRule.d.ts +34 -0
- package/dist/src/data/rules/customRule.js +74 -0
- package/dist/src/data/rules/differentCountPerZoneRule.d.ts +30 -0
- package/dist/src/data/rules/differentCountPerZoneRule.js +96 -0
- package/dist/src/data/rules/exactCountPerZoneRule.d.ts +33 -0
- package/dist/src/data/rules/exactCountPerZoneRule.js +99 -0
- package/dist/src/data/rules/foresightRule.d.ts +36 -0
- package/dist/src/data/rules/foresightRule.js +107 -0
- package/dist/src/data/rules/index.d.ts +3 -0
- package/dist/src/data/rules/index.js +10 -0
- package/dist/src/data/rules/lyingSymbolRule.d.ts +31 -0
- package/dist/src/data/rules/lyingSymbolRule.js +207 -0
- package/dist/src/data/rules/musicControlLine.d.ts +82 -0
- package/dist/src/data/rules/musicControlLine.js +167 -0
- package/dist/src/data/rules/musicGridRule.d.ts +51 -0
- package/dist/src/data/rules/musicGridRule.js +212 -0
- package/dist/src/data/rules/mysteryRule.d.ts +39 -0
- package/dist/src/data/rules/mysteryRule.js +146 -0
- package/dist/src/data/rules/noLoopsRule.d.ts +29 -0
- package/dist/src/data/rules/noLoopsRule.js +218 -0
- package/dist/src/data/rules/offByXRule.d.ts +32 -0
- package/dist/src/data/rules/offByXRule.js +124 -0
- package/dist/src/data/rules/perfectionRule.d.ts +45 -0
- package/dist/src/data/rules/perfectionRule.js +158 -0
- package/dist/src/data/rules/regionAreaRule.d.ts +34 -0
- package/dist/src/data/rules/regionAreaRule.js +149 -0
- package/dist/src/data/rules/regionShapeRule.d.ts +22 -0
- package/dist/src/data/rules/regionShapeRule.js +58 -0
- package/dist/src/data/rules/rule.d.ts +18 -0
- package/dist/src/data/rules/rule.js +19 -0
- package/dist/src/data/rules/rules.gen.d.ts +23 -0
- package/dist/src/data/rules/rules.gen.js +27 -0
- package/dist/src/data/rules/sameCountPerZoneRule.d.ts +30 -0
- package/dist/src/data/rules/sameCountPerZoneRule.js +95 -0
- package/dist/src/data/rules/sameShapeRule.d.ts +28 -0
- package/dist/src/data/rules/sameShapeRule.js +68 -0
- package/dist/src/data/rules/symbolsPerRegionRule.d.ts +38 -0
- package/dist/src/data/rules/symbolsPerRegionRule.js +181 -0
- package/dist/src/data/rules/undercluedRule.d.ts +24 -0
- package/dist/src/data/rules/undercluedRule.js +53 -0
- package/dist/src/data/rules/uniqueShapeRule.d.ts +28 -0
- package/dist/src/data/rules/uniqueShapeRule.js +65 -0
- package/dist/src/data/rules/wrapAroundRule.d.ts +36 -0
- package/dist/src/data/rules/wrapAroundRule.js +241 -0
- package/dist/src/data/serializer/allSerializers.d.ts +35 -0
- package/dist/src/data/serializer/allSerializers.js +78 -0
- package/dist/src/data/serializer/compressor/allCompressors.d.ts +14 -0
- package/dist/src/data/serializer/compressor/allCompressors.js +43 -0
- package/dist/src/data/serializer/compressor/checksumCompressor.d.ts +6 -0
- package/dist/src/data/serializer/compressor/checksumCompressor.js +21 -0
- package/dist/src/data/serializer/compressor/compressorBase.d.ts +16 -0
- package/dist/src/data/serializer/compressor/compressorBase.js +2 -0
- package/dist/src/data/serializer/compressor/deflateCompressor.d.ts +7 -0
- package/dist/src/data/serializer/compressor/deflateCompressor.js +17 -0
- package/dist/src/data/serializer/compressor/gzipCompressor.d.ts +5 -0
- package/dist/src/data/serializer/compressor/gzipCompressor.js +9 -0
- package/dist/src/data/serializer/compressor/streamCompressor.d.ts +6 -0
- package/dist/src/data/serializer/compressor/streamCompressor.js +41 -0
- package/dist/src/data/serializer/serializerBase.d.ts +32 -0
- package/dist/src/data/serializer/serializerBase.js +2 -0
- package/dist/src/data/serializer/serializer_checksum.d.ts +35 -0
- package/dist/src/data/serializer/serializer_checksum.js +179 -0
- package/dist/src/data/serializer/serializer_v0.d.ts +55 -0
- package/dist/src/data/serializer/serializer_v0.js +484 -0
- package/dist/src/data/shapes.d.ts +19 -0
- package/dist/src/data/shapes.js +137 -0
- package/dist/src/data/solver/allSolvers.d.ts +3 -0
- package/dist/src/data/solver/allSolvers.js +13 -0
- package/dist/src/data/solver/auto/autoSolver.d.ts +18 -0
- package/dist/src/data/solver/auto/autoSolver.js +156 -0
- package/dist/src/data/solver/backtrack/backtrackSolver.d.ts +11 -0
- package/dist/src/data/solver/backtrack/backtrackSolver.js +54 -0
- package/dist/src/data/solver/backtrack/backtrackWorker.d.ts +1 -0
- package/dist/src/data/solver/backtrack/backtrackWorker.js +312 -0
- package/dist/src/data/solver/backtrack/data.d.ts +47 -0
- package/dist/src/data/solver/backtrack/data.js +151 -0
- package/dist/src/data/solver/backtrack/rules/banPattern.d.ts +9 -0
- package/dist/src/data/solver/backtrack/rules/banPattern.js +77 -0
- package/dist/src/data/solver/backtrack/rules/cellCount.d.ts +7 -0
- package/dist/src/data/solver/backtrack/rules/cellCount.js +25 -0
- package/dist/src/data/solver/backtrack/rules/connectAll.d.ts +7 -0
- package/dist/src/data/solver/backtrack/rules/connectAll.js +44 -0
- package/dist/src/data/solver/backtrack/rules/regionArea.d.ts +8 -0
- package/dist/src/data/solver/backtrack/rules/regionArea.js +71 -0
- package/dist/src/data/solver/backtrack/rules/regionShape.d.ts +8 -0
- package/dist/src/data/solver/backtrack/rules/regionShape.js +57 -0
- package/dist/src/data/solver/backtrack/rules/sameShape.d.ts +8 -0
- package/dist/src/data/solver/backtrack/rules/sameShape.js +14 -0
- package/dist/src/data/solver/backtrack/rules/symbolsPerRegion.d.ts +10 -0
- package/dist/src/data/solver/backtrack/rules/symbolsPerRegion.js +82 -0
- package/dist/src/data/solver/backtrack/rules/uniqueShape.d.ts +8 -0
- package/dist/src/data/solver/backtrack/rules/uniqueShape.js +14 -0
- package/dist/src/data/solver/backtrack/symbols/areaNumber.d.ts +9 -0
- package/dist/src/data/solver/backtrack/symbols/areaNumber.js +75 -0
- package/dist/src/data/solver/backtrack/symbols/dart.d.ts +8 -0
- package/dist/src/data/solver/backtrack/symbols/dart.js +45 -0
- package/dist/src/data/solver/backtrack/symbols/directionLinker.d.ts +11 -0
- package/dist/src/data/solver/backtrack/symbols/directionLinker.js +121 -0
- package/dist/src/data/solver/backtrack/symbols/focus.d.ts +9 -0
- package/dist/src/data/solver/backtrack/symbols/focus.js +48 -0
- package/dist/src/data/solver/backtrack/symbols/galaxy.d.ts +9 -0
- package/dist/src/data/solver/backtrack/symbols/galaxy.js +14 -0
- package/dist/src/data/solver/backtrack/symbols/letter.d.ts +9 -0
- package/dist/src/data/solver/backtrack/symbols/letter.js +95 -0
- package/dist/src/data/solver/backtrack/symbols/lotus.d.ts +11 -0
- package/dist/src/data/solver/backtrack/symbols/lotus.js +55 -0
- package/dist/src/data/solver/backtrack/symbols/minesweeper.d.ts +9 -0
- package/dist/src/data/solver/backtrack/symbols/minesweeper.js +44 -0
- package/dist/src/data/solver/backtrack/symbols/myopia.d.ts +7 -0
- package/dist/src/data/solver/backtrack/symbols/myopia.js +73 -0
- package/dist/src/data/solver/backtrack/symbols/viewpoint.d.ts +7 -0
- package/dist/src/data/solver/backtrack/symbols/viewpoint.js +51 -0
- package/dist/src/data/solver/cspuz/cspuzSolver.d.ts +13 -0
- package/dist/src/data/solver/cspuz/cspuzSolver.js +124 -0
- package/dist/src/data/solver/cspuz/cspuzWorker.d.ts +1 -0
- package/dist/src/data/solver/cspuz/cspuzWorker.js +82 -0
- package/dist/src/data/solver/cspuz/jsonify.d.ts +3 -0
- package/dist/src/data/solver/cspuz/jsonify.js +215 -0
- package/dist/src/data/solver/eventIteratingSolver.d.ts +8 -0
- package/dist/src/data/solver/eventIteratingSolver.js +54 -0
- package/dist/src/data/solver/solver.d.ts +77 -0
- package/dist/src/data/solver/solver.js +59 -0
- package/dist/src/data/solver/universal/universalSolver.d.ts +7 -0
- package/dist/src/data/solver/universal/universalSolver.js +13 -0
- package/dist/src/data/solver/universal/universalWorker.d.ts +1 -0
- package/dist/src/data/solver/universal/universalWorker.js +128 -0
- package/dist/src/data/symbols/areaNumberSymbol.d.ts +31 -0
- package/dist/src/data/symbols/areaNumberSymbol.js +80 -0
- package/dist/src/data/symbols/customIconSymbol.d.ts +35 -0
- package/dist/src/data/symbols/customIconSymbol.js +94 -0
- package/dist/src/data/symbols/customSymbol.d.ts +25 -0
- package/dist/src/data/symbols/customSymbol.js +45 -0
- package/dist/src/data/symbols/customTextSymbol.d.ts +35 -0
- package/dist/src/data/symbols/customTextSymbol.js +95 -0
- package/dist/src/data/symbols/dartSymbol.d.ts +36 -0
- package/dist/src/data/symbols/dartSymbol.js +96 -0
- package/dist/src/data/symbols/directionLinkerSymbol.d.ts +29 -0
- package/dist/src/data/symbols/directionLinkerSymbol.js +232 -0
- package/dist/src/data/symbols/everyLetterSymbol.d.ts +32 -0
- package/dist/src/data/symbols/everyLetterSymbol.js +119 -0
- package/dist/src/data/symbols/focusSymbol.d.ts +40 -0
- package/dist/src/data/symbols/focusSymbol.js +159 -0
- package/dist/src/data/symbols/galaxySymbol.d.ts +27 -0
- package/dist/src/data/symbols/galaxySymbol.js +61 -0
- package/dist/src/data/symbols/hiddenSymbol.d.ts +38 -0
- package/dist/src/data/symbols/hiddenSymbol.js +113 -0
- package/dist/src/data/symbols/houseSymbol.d.ts +33 -0
- package/dist/src/data/symbols/houseSymbol.js +104 -0
- package/dist/src/data/symbols/index.d.ts +3 -0
- package/dist/src/data/symbols/index.js +10 -0
- package/dist/src/data/symbols/letterSymbol.d.ts +32 -0
- package/dist/src/data/symbols/letterSymbol.js +118 -0
- package/dist/src/data/symbols/lotusSymbol.d.ts +30 -0
- package/dist/src/data/symbols/lotusSymbol.js +132 -0
- package/dist/src/data/symbols/minesweeperSymbol.d.ts +33 -0
- package/dist/src/data/symbols/minesweeperSymbol.js +106 -0
- package/dist/src/data/symbols/myopiaSymbol.d.ts +37 -0
- package/dist/src/data/symbols/myopiaSymbol.js +182 -0
- package/dist/src/data/symbols/numberSymbol.d.ts +19 -0
- package/dist/src/data/symbols/numberSymbol.js +32 -0
- package/dist/src/data/symbols/symbol.d.ts +29 -0
- package/dist/src/data/symbols/symbol.js +87 -0
- package/dist/src/data/symbols/symbols.gen.d.ts +15 -0
- package/dist/src/data/symbols/symbols.gen.js +19 -0
- package/dist/src/data/symbols/unsupportedSymbol.d.ts +23 -0
- package/dist/src/data/symbols/unsupportedSymbol.js +47 -0
- package/dist/src/data/symbols/viewpointSymbol.d.ts +32 -0
- package/dist/src/data/symbols/viewpointSymbol.js +95 -0
- package/dist/src/data/tile.d.ts +26 -0
- package/dist/src/data/tile.js +56 -0
- package/dist/src/data/tileConnections.d.ts +25 -0
- package/dist/src/data/tileConnections.js +74 -0
- package/dist/src/data/validate.d.ts +5 -0
- package/dist/src/data/validate.js +131 -0
- package/dist/src/data/validateAsync.d.ts +15 -0
- package/dist/src/data/validateAsync.js +71 -0
- package/dist/src/data/validateAsyncWorker.d.ts +1 -0
- package/dist/src/data/validateAsyncWorker.js +9 -0
- package/dist/src/index.d.ts +109 -0
- package/dist/src/index.js +112 -0
- package/dist/src/polyfill/streamPolyfill.d.ts +2 -0
- package/dist/src/polyfill/streamPolyfill.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import GridData from '../grid.js';
|
|
2
|
+
import GridConnections from '../gridConnections.js';
|
|
3
|
+
import TileData from '../tile.js';
|
|
4
|
+
import { ConfigType, } from '../config.js';
|
|
5
|
+
import { Color, DIRECTIONS, ORIENTATIONS, Orientation, directionToggle, orientationToggle, INSTRUMENTS, } from '../primitives.js';
|
|
6
|
+
import { array, escape, unescape } from '../dataHelper.js';
|
|
7
|
+
import { allRules } from '../rules/index.js';
|
|
8
|
+
import { allSymbols } from '../symbols/index.js';
|
|
9
|
+
import SerializerBase from './serializerBase.js';
|
|
10
|
+
import { ControlLine, Row } from '../rules/musicControlLine.js';
|
|
11
|
+
import GridZones from '../gridZones.js';
|
|
12
|
+
export const OFFSETS = [
|
|
13
|
+
{ x: 0, y: -1 },
|
|
14
|
+
{ x: -1, y: 0 },
|
|
15
|
+
{ x: 1, y: 0 },
|
|
16
|
+
{ x: 0, y: 1 },
|
|
17
|
+
];
|
|
18
|
+
export const orientationChars = {
|
|
19
|
+
[Orientation.Up]: 'u',
|
|
20
|
+
[Orientation.UpRight]: 'x',
|
|
21
|
+
[Orientation.Right]: 'r',
|
|
22
|
+
[Orientation.DownRight]: 'z',
|
|
23
|
+
[Orientation.Down]: 'd',
|
|
24
|
+
[Orientation.DownLeft]: 'y',
|
|
25
|
+
[Orientation.Left]: 'l',
|
|
26
|
+
[Orientation.UpLeft]: 'w',
|
|
27
|
+
};
|
|
28
|
+
export default class SerializerV0 extends SerializerBase {
|
|
29
|
+
version = 0;
|
|
30
|
+
stringifyTile(tile) {
|
|
31
|
+
if (!tile.exists)
|
|
32
|
+
return '.';
|
|
33
|
+
const char = tile.color === Color.Gray ? 'n' : tile.color === Color.Dark ? 'b' : 'w';
|
|
34
|
+
return tile.fixed ? char.toUpperCase() : char;
|
|
35
|
+
}
|
|
36
|
+
parseTile(str) {
|
|
37
|
+
return TileData.create(str);
|
|
38
|
+
}
|
|
39
|
+
stringifyControlLine(line) {
|
|
40
|
+
const result = [];
|
|
41
|
+
result.push(`c${line.column}`);
|
|
42
|
+
if (line.bpm !== null)
|
|
43
|
+
result.push(`b${line.bpm}`);
|
|
44
|
+
if (line.pedal !== null)
|
|
45
|
+
result.push(`p${line.pedal ? '1' : '0'}`);
|
|
46
|
+
if (line.checkpoint)
|
|
47
|
+
result.push('s');
|
|
48
|
+
result.push(`r${line.rows
|
|
49
|
+
.map(row => `i${row.instrument ?? ''}v${row.velocity ?? ''}n${row.note ?? ''}`)
|
|
50
|
+
.join(',')}`);
|
|
51
|
+
return result.join('|');
|
|
52
|
+
}
|
|
53
|
+
parseControlLine(str) {
|
|
54
|
+
let column = null;
|
|
55
|
+
let bpm = null;
|
|
56
|
+
let pedal = null;
|
|
57
|
+
let checkpoint = false;
|
|
58
|
+
const rows = [];
|
|
59
|
+
const data = str.split('|');
|
|
60
|
+
for (const entry of data) {
|
|
61
|
+
const key = entry.charAt(0);
|
|
62
|
+
const value = entry.slice(1);
|
|
63
|
+
switch (key) {
|
|
64
|
+
case 'c':
|
|
65
|
+
column = value === '' ? null : Number(value);
|
|
66
|
+
break;
|
|
67
|
+
case 'b':
|
|
68
|
+
bpm = value === '' ? null : Number(value);
|
|
69
|
+
break;
|
|
70
|
+
case 'p':
|
|
71
|
+
pedal = value === '1' ? true : value === '0' ? false : null;
|
|
72
|
+
break;
|
|
73
|
+
case 's':
|
|
74
|
+
checkpoint = true;
|
|
75
|
+
break;
|
|
76
|
+
case 'r':
|
|
77
|
+
rows.push(...value.split(',').map(row => {
|
|
78
|
+
const match = /^(?:i(\w*?))?v([\d.]*?)n(.*)$/.exec(row);
|
|
79
|
+
if (!match)
|
|
80
|
+
return new Row(null, null, null);
|
|
81
|
+
const [, instrument, velocity, note] = match;
|
|
82
|
+
return new Row(note === '' ? null : note, instrument === '' ||
|
|
83
|
+
!INSTRUMENTS.includes(instrument)
|
|
84
|
+
? null
|
|
85
|
+
: instrument, velocity === '' ? null : Number(velocity));
|
|
86
|
+
}));
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return new ControlLine(column ?? 0, bpm, pedal, checkpoint, rows);
|
|
91
|
+
}
|
|
92
|
+
stringifyConfig(instruction, config) {
|
|
93
|
+
switch (config.type) {
|
|
94
|
+
case ConfigType.Boolean:
|
|
95
|
+
return (config.field +
|
|
96
|
+
'=' +
|
|
97
|
+
(instruction[config.field] ? '1' : '0'));
|
|
98
|
+
case ConfigType.Number:
|
|
99
|
+
case ConfigType.Color:
|
|
100
|
+
case ConfigType.Comparison:
|
|
101
|
+
case ConfigType.Wrapping:
|
|
102
|
+
case ConfigType.Direction:
|
|
103
|
+
case ConfigType.Orientation:
|
|
104
|
+
return (config.field +
|
|
105
|
+
'=' +
|
|
106
|
+
instruction[config.field]);
|
|
107
|
+
case ConfigType.NullableBoolean:
|
|
108
|
+
return (config.field +
|
|
109
|
+
'=' +
|
|
110
|
+
(instruction[config.field] === null
|
|
111
|
+
? ''
|
|
112
|
+
: instruction[config.field]
|
|
113
|
+
? '1'
|
|
114
|
+
: '0'));
|
|
115
|
+
case ConfigType.NullableNumber:
|
|
116
|
+
return (config.field +
|
|
117
|
+
'=' +
|
|
118
|
+
(instruction[config.field] === null
|
|
119
|
+
? ''
|
|
120
|
+
: String(instruction[config.field])));
|
|
121
|
+
case ConfigType.DirectionToggle:
|
|
122
|
+
return (config.field +
|
|
123
|
+
'=' +
|
|
124
|
+
DIRECTIONS.filter(dir => instruction[config.field][dir])
|
|
125
|
+
.map(x => orientationChars[x])
|
|
126
|
+
.join(''));
|
|
127
|
+
case ConfigType.OrientationToggle:
|
|
128
|
+
return (config.field +
|
|
129
|
+
'=' +
|
|
130
|
+
ORIENTATIONS.filter(dir => instruction[config.field][dir])
|
|
131
|
+
.map(x => orientationChars[x])
|
|
132
|
+
.join(''));
|
|
133
|
+
case ConfigType.String:
|
|
134
|
+
case ConfigType.Icon:
|
|
135
|
+
return (config.field +
|
|
136
|
+
'=' +
|
|
137
|
+
escape(instruction[config.field]));
|
|
138
|
+
case ConfigType.NullableNote:
|
|
139
|
+
return (config.field +
|
|
140
|
+
'=' +
|
|
141
|
+
escape(instruction[config.field] === null
|
|
142
|
+
? ''
|
|
143
|
+
: escape(String(instruction[config.field]))));
|
|
144
|
+
case ConfigType.NullableInstrument:
|
|
145
|
+
return (config.field +
|
|
146
|
+
'=' +
|
|
147
|
+
escape(instruction[config.field] === null
|
|
148
|
+
? ''
|
|
149
|
+
: String(instruction[config.field])));
|
|
150
|
+
case ConfigType.Tile:
|
|
151
|
+
case ConfigType.Shape:
|
|
152
|
+
case ConfigType.Grid:
|
|
153
|
+
return (config.field +
|
|
154
|
+
'=' +
|
|
155
|
+
escape(this.stringifyGrid(instruction[config.field])));
|
|
156
|
+
case ConfigType.NullableGrid:
|
|
157
|
+
return (config.field +
|
|
158
|
+
'=' +
|
|
159
|
+
escape(instruction[config.field] === null
|
|
160
|
+
? ''
|
|
161
|
+
: this.stringifyGrid(instruction[config.field])));
|
|
162
|
+
case ConfigType.ControlLines:
|
|
163
|
+
return (config.field +
|
|
164
|
+
'=' +
|
|
165
|
+
escape(instruction[config.field]
|
|
166
|
+
.map(line => this.stringifyControlLine(line))
|
|
167
|
+
.join(':')));
|
|
168
|
+
case ConfigType.SolvePath:
|
|
169
|
+
return (config.field +
|
|
170
|
+
'=' +
|
|
171
|
+
escape(instruction[config.field]
|
|
172
|
+
?.map(pos => `${pos.x}_${pos.y}`)
|
|
173
|
+
.join('/') ?? ''));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
parseConfig(configs, entry) {
|
|
177
|
+
const [key, value] = entry.split('=');
|
|
178
|
+
const config = configs.find(x => x.field === key);
|
|
179
|
+
if (!config) {
|
|
180
|
+
console.warn(`Unknown config: ${key} when parsing ${entry}`);
|
|
181
|
+
return [key, value];
|
|
182
|
+
}
|
|
183
|
+
switch (config.type) {
|
|
184
|
+
case ConfigType.Boolean:
|
|
185
|
+
return [config.field, value === '1'];
|
|
186
|
+
case ConfigType.NullableBoolean:
|
|
187
|
+
return [config.field, value === '' ? null : value === '1'];
|
|
188
|
+
case ConfigType.Number:
|
|
189
|
+
return [config.field, Number(value)];
|
|
190
|
+
case ConfigType.NullableNumber:
|
|
191
|
+
return [config.field, value === '' ? null : Number(value)];
|
|
192
|
+
case ConfigType.Color:
|
|
193
|
+
return [config.field, value];
|
|
194
|
+
case ConfigType.Comparison:
|
|
195
|
+
return [config.field, value];
|
|
196
|
+
case ConfigType.Wrapping:
|
|
197
|
+
return [config.field, value];
|
|
198
|
+
case ConfigType.Direction:
|
|
199
|
+
return [config.field, value];
|
|
200
|
+
case ConfigType.DirectionToggle: {
|
|
201
|
+
const toggle = directionToggle();
|
|
202
|
+
for (const dir of DIRECTIONS) {
|
|
203
|
+
toggle[dir] = value.includes(orientationChars[dir]);
|
|
204
|
+
}
|
|
205
|
+
return [config.field, toggle];
|
|
206
|
+
}
|
|
207
|
+
case ConfigType.Orientation:
|
|
208
|
+
return [config.field, value];
|
|
209
|
+
case ConfigType.OrientationToggle: {
|
|
210
|
+
const toggle = orientationToggle();
|
|
211
|
+
for (const dir of ORIENTATIONS) {
|
|
212
|
+
toggle[dir] = value.includes(orientationChars[dir]);
|
|
213
|
+
}
|
|
214
|
+
return [config.field, toggle];
|
|
215
|
+
}
|
|
216
|
+
case ConfigType.String:
|
|
217
|
+
case ConfigType.Icon:
|
|
218
|
+
return [config.field, unescape(value)];
|
|
219
|
+
case ConfigType.Tile:
|
|
220
|
+
case ConfigType.Shape:
|
|
221
|
+
case ConfigType.Grid:
|
|
222
|
+
return [config.field, this.parseGrid(unescape(value))];
|
|
223
|
+
case ConfigType.NullableGrid:
|
|
224
|
+
return [
|
|
225
|
+
config.field,
|
|
226
|
+
value === '' ? null : this.parseGrid(unescape(value)),
|
|
227
|
+
];
|
|
228
|
+
case ConfigType.ControlLines:
|
|
229
|
+
return [
|
|
230
|
+
config.field,
|
|
231
|
+
unescape(value)
|
|
232
|
+
.split(':')
|
|
233
|
+
.map(line => this.parseControlLine(line)),
|
|
234
|
+
];
|
|
235
|
+
case ConfigType.NullableNote:
|
|
236
|
+
return [config.field, value === '' ? null : unescape(value)];
|
|
237
|
+
case ConfigType.NullableInstrument:
|
|
238
|
+
return [
|
|
239
|
+
config.field,
|
|
240
|
+
value === '' ? null : unescape(value),
|
|
241
|
+
];
|
|
242
|
+
case ConfigType.SolvePath:
|
|
243
|
+
return [
|
|
244
|
+
config.field,
|
|
245
|
+
value === ''
|
|
246
|
+
? []
|
|
247
|
+
: value.split('/').map(pos => {
|
|
248
|
+
const [x, y] = pos.split('_');
|
|
249
|
+
return { x: Number(x), y: Number(y) };
|
|
250
|
+
}),
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
stringifyInstruction(instruction) {
|
|
255
|
+
return `${instruction.id},${instruction.configs?.map(config => this.stringifyConfig(instruction, config)).join(',') ?? ''}`;
|
|
256
|
+
}
|
|
257
|
+
stringifyRule(rule) {
|
|
258
|
+
return this.stringifyInstruction(rule);
|
|
259
|
+
}
|
|
260
|
+
stringifySymbol(symbol) {
|
|
261
|
+
return this.stringifyInstruction(symbol);
|
|
262
|
+
}
|
|
263
|
+
parseRule(str) {
|
|
264
|
+
const [id, ...entries] = str.split(',');
|
|
265
|
+
const instruction = allRules.get(id);
|
|
266
|
+
if (!instruction)
|
|
267
|
+
throw new Error(`Unknown rule: ${id}`);
|
|
268
|
+
const configs = instruction.configs;
|
|
269
|
+
if (configs == null)
|
|
270
|
+
return instruction.copyWith({});
|
|
271
|
+
return instruction.copyWith(Object.fromEntries(entries
|
|
272
|
+
.filter(entry => entry !== '')
|
|
273
|
+
.map(entry => this.parseConfig(configs, entry))));
|
|
274
|
+
}
|
|
275
|
+
parseSymbol(str) {
|
|
276
|
+
const [id, ...entries] = str.split(',');
|
|
277
|
+
const instruction = allSymbols.get(id);
|
|
278
|
+
if (!instruction)
|
|
279
|
+
throw new Error(`Unknown symbol: ${id}`);
|
|
280
|
+
const configs = instruction.configs;
|
|
281
|
+
if (configs == null)
|
|
282
|
+
return instruction.copyWith({});
|
|
283
|
+
return instruction.copyWith(Object.fromEntries(entries.map(entry => this.parseConfig(configs, entry))));
|
|
284
|
+
}
|
|
285
|
+
stringifyConnections(connections) {
|
|
286
|
+
const maxX = connections.edges.reduce((max, edge) => Math.max(max, edge.x1, edge.x2), 0);
|
|
287
|
+
const maxY = connections.edges.reduce((max, edge) => Math.max(max, edge.y1, edge.y2), 0);
|
|
288
|
+
const result = array(maxX + 1, maxY + 1, () => '.');
|
|
289
|
+
for (let y = 0; y <= maxY; y++) {
|
|
290
|
+
for (let x = 0; x <= maxX; x++) {
|
|
291
|
+
if (result[y][x] !== '.') {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const tiles = connections.getConnectedTiles({ x, y });
|
|
295
|
+
if (tiles.length < 2) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const existingChars = [];
|
|
299
|
+
for (const { x: tx, y: ty } of tiles) {
|
|
300
|
+
for (const { x: dx, y: dy } of OFFSETS) {
|
|
301
|
+
if (tx + dx > maxX ||
|
|
302
|
+
ty + dy > maxY ||
|
|
303
|
+
tx + dx < 0 ||
|
|
304
|
+
ty + dy < 0) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (result[ty + dy][tx + dx] !== '.')
|
|
308
|
+
existingChars.push(result[ty + dy][tx + dx]);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
let char = 'A';
|
|
312
|
+
while (existingChars.includes(char)) {
|
|
313
|
+
char = String.fromCharCode(char.charCodeAt(0) + 1);
|
|
314
|
+
}
|
|
315
|
+
for (const connection of tiles) {
|
|
316
|
+
result[connection.y][connection.x] = char;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return `C${maxX + 1}:${result.map(row => row.join('')).join('')}`.replace(/\.+$/, '');
|
|
321
|
+
}
|
|
322
|
+
parseConnections(input) {
|
|
323
|
+
if (!input.startsWith('C')) {
|
|
324
|
+
throw new Error('Invalid grid connections\n' + input);
|
|
325
|
+
}
|
|
326
|
+
const [size, data] = input.slice(1).split(':');
|
|
327
|
+
const width = Number(size);
|
|
328
|
+
const tiles = array(width, Math.ceil(data.length / width), (x, y) => data[y * width + x]);
|
|
329
|
+
return GridConnections.create(tiles.map(row => row.join('')));
|
|
330
|
+
}
|
|
331
|
+
stringifyZones(zones) {
|
|
332
|
+
return `Z${zones.edges.map(edge => `${edge.x1}_${edge.y1}_${edge.x2 - edge.x1}_${edge.y2 - edge.y1}`).join(':')}`;
|
|
333
|
+
}
|
|
334
|
+
parseZones(input) {
|
|
335
|
+
if (!input.startsWith('Z')) {
|
|
336
|
+
throw new Error('Invalid grid zones\n' + input);
|
|
337
|
+
}
|
|
338
|
+
const data = input.slice(1).split(':');
|
|
339
|
+
return new GridZones(data.map(entry => {
|
|
340
|
+
const [x1, y1, w, h] = entry.split('_').map(Number);
|
|
341
|
+
return { x1, y1, x2: x1 + w, y2: y1 + h };
|
|
342
|
+
}));
|
|
343
|
+
}
|
|
344
|
+
stringifyTiles(tiles) {
|
|
345
|
+
return `T${tiles[0]?.length ?? 0}:${tiles.map(row => row.map(tile => this.stringifyTile(tile)).join('')).join('')}`;
|
|
346
|
+
}
|
|
347
|
+
parseTiles(input) {
|
|
348
|
+
if (!input.startsWith('T')) {
|
|
349
|
+
throw new Error('Invalid grid data\n' + input);
|
|
350
|
+
}
|
|
351
|
+
const [size, data] = input.slice(1).split(':');
|
|
352
|
+
const width = Number(size);
|
|
353
|
+
return array(width, Math.ceil(data.length / width), (x, y) => this.parseTile(data.charAt(y * width + x)));
|
|
354
|
+
}
|
|
355
|
+
stringifyRules(rules) {
|
|
356
|
+
return `R${rules.map(rule => this.stringifyRule(rule)).join(':')}`;
|
|
357
|
+
}
|
|
358
|
+
parseRules(input) {
|
|
359
|
+
if (!input.startsWith('R')) {
|
|
360
|
+
throw new Error('Invalid rules\n' + input);
|
|
361
|
+
}
|
|
362
|
+
return input
|
|
363
|
+
.slice(1)
|
|
364
|
+
.split(':')
|
|
365
|
+
.filter(rule => rule !== '')
|
|
366
|
+
.map(rule => this.parseRule(rule));
|
|
367
|
+
}
|
|
368
|
+
stringifySymbols(symbols) {
|
|
369
|
+
return `S${Array.from(symbols.values())
|
|
370
|
+
.flat()
|
|
371
|
+
.map(symbol => this.stringifySymbol(symbol))
|
|
372
|
+
.join(':')}`;
|
|
373
|
+
}
|
|
374
|
+
parseSymbols(input) {
|
|
375
|
+
if (!input.startsWith('S')) {
|
|
376
|
+
throw new Error('Invalid symbols\n' + input);
|
|
377
|
+
}
|
|
378
|
+
const symbols = new Map();
|
|
379
|
+
input
|
|
380
|
+
.slice(1)
|
|
381
|
+
.split(':')
|
|
382
|
+
.filter(symbol => symbol !== '')
|
|
383
|
+
.forEach(symbol => {
|
|
384
|
+
const parsed = this.parseSymbol(symbol);
|
|
385
|
+
if (symbols.has(parsed.id)) {
|
|
386
|
+
symbols.set(parsed.id, [...symbols.get(parsed.id), parsed]);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
symbols.set(parsed.id, [parsed]);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
return symbols;
|
|
393
|
+
}
|
|
394
|
+
stringifyGrid(grid) {
|
|
395
|
+
const data = [
|
|
396
|
+
this.stringifyTiles(grid.tiles),
|
|
397
|
+
this.stringifyConnections(grid.connections),
|
|
398
|
+
this.stringifyZones(grid.zones),
|
|
399
|
+
this.stringifySymbols(grid.symbols),
|
|
400
|
+
this.stringifyRules(grid.rules),
|
|
401
|
+
];
|
|
402
|
+
return `${grid.width}x${grid.height}|${data.join('|')}`;
|
|
403
|
+
}
|
|
404
|
+
parseGrid(input) {
|
|
405
|
+
const data = input.split('|');
|
|
406
|
+
let width;
|
|
407
|
+
let height;
|
|
408
|
+
let tiles;
|
|
409
|
+
let connections;
|
|
410
|
+
let zones;
|
|
411
|
+
let symbols;
|
|
412
|
+
let rules;
|
|
413
|
+
for (const d of data) {
|
|
414
|
+
if (/^\d+x\d+$/.test(d)) {
|
|
415
|
+
[width, height] = d.split('x').map(Number);
|
|
416
|
+
}
|
|
417
|
+
else if (d.startsWith('T')) {
|
|
418
|
+
tiles = this.parseTiles(d);
|
|
419
|
+
}
|
|
420
|
+
else if (d.startsWith('C')) {
|
|
421
|
+
connections = this.parseConnections(d);
|
|
422
|
+
}
|
|
423
|
+
else if (d.startsWith('Z')) {
|
|
424
|
+
zones = this.parseZones(d);
|
|
425
|
+
}
|
|
426
|
+
else if (d.startsWith('S')) {
|
|
427
|
+
symbols = this.parseSymbols(d);
|
|
428
|
+
}
|
|
429
|
+
else if (d.startsWith('R')) {
|
|
430
|
+
rules = this.parseRules(d);
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
throw new Error(`Invalid data: ${d}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return GridData.create(width ?? tiles?.[0].length ?? 0, height ?? tiles?.length ?? 0, tiles, connections, zones, symbols, rules);
|
|
437
|
+
}
|
|
438
|
+
stringifyGridWithSolution(puzzle) {
|
|
439
|
+
let grid = puzzle.grid;
|
|
440
|
+
if (puzzle.solution !== null) {
|
|
441
|
+
const tiles = array(puzzle.grid.width, puzzle.grid.height, (x, y) => {
|
|
442
|
+
const tile = puzzle.grid.getTile(x, y);
|
|
443
|
+
const solutionTile = puzzle.solution.getTile(x, y);
|
|
444
|
+
return tile.exists &&
|
|
445
|
+
!tile.fixed &&
|
|
446
|
+
solutionTile.exists &&
|
|
447
|
+
solutionTile.color !== Color.Gray
|
|
448
|
+
? tile.copyWith({
|
|
449
|
+
color: puzzle.solution.tiles[y][x].color,
|
|
450
|
+
})
|
|
451
|
+
: tile;
|
|
452
|
+
});
|
|
453
|
+
grid = puzzle.grid.copyWith({ tiles });
|
|
454
|
+
}
|
|
455
|
+
return this.stringifyGrid(grid);
|
|
456
|
+
}
|
|
457
|
+
parseGridWithSolution(input) {
|
|
458
|
+
const grid = this.parseGrid(input);
|
|
459
|
+
const reset = grid.resetTiles();
|
|
460
|
+
return {
|
|
461
|
+
grid: reset,
|
|
462
|
+
solution: grid.colorEquals(reset) ? null : grid,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
stringifyPuzzle(puzzle) {
|
|
466
|
+
return JSON.stringify({
|
|
467
|
+
title: puzzle.title,
|
|
468
|
+
grid: this.stringifyGridWithSolution(puzzle),
|
|
469
|
+
difficulty: puzzle.difficulty,
|
|
470
|
+
author: puzzle.author,
|
|
471
|
+
description: puzzle.description,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
parsePuzzle(input) {
|
|
475
|
+
const { grid: gridString, title, author, description, difficulty, } = JSON.parse(input);
|
|
476
|
+
return {
|
|
477
|
+
title,
|
|
478
|
+
author,
|
|
479
|
+
description,
|
|
480
|
+
difficulty,
|
|
481
|
+
...this.parseGridWithSolution(gridString),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import GridData from './grid.js';
|
|
2
|
+
import { Color, Position } from './primitives.js';
|
|
3
|
+
import TileData from './tile.js';
|
|
4
|
+
export interface ShapeElement {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
color: Color;
|
|
8
|
+
}
|
|
9
|
+
export interface Shape {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
elements: ShapeElement[];
|
|
13
|
+
}
|
|
14
|
+
export declare function shapeEquals(a: Shape, b: Shape): boolean;
|
|
15
|
+
export declare function tilesToShape(tiles: readonly (readonly TileData[])[]): Shape;
|
|
16
|
+
export declare function positionsToShape(positions: Position[], color: Color): Shape;
|
|
17
|
+
export declare function getShapeVariants(shape: Shape): Shape[];
|
|
18
|
+
export declare function normalizeShape(shape: Shape): Shape;
|
|
19
|
+
export declare function sanitizePatternGrid(pattern: GridData, tileMapper?: (tile: TileData) => TileData): GridData;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import GridConnections from './gridConnections.js';
|
|
2
|
+
import GridZones from './gridZones.js';
|
|
3
|
+
import { Color } from './primitives.js';
|
|
4
|
+
const colorIndex = {
|
|
5
|
+
[Color.Dark]: 2,
|
|
6
|
+
[Color.Light]: 1,
|
|
7
|
+
[Color.Gray]: 0,
|
|
8
|
+
};
|
|
9
|
+
function compareColor(a, b) {
|
|
10
|
+
return colorIndex[a] - colorIndex[b];
|
|
11
|
+
}
|
|
12
|
+
function compareElement(a, b) {
|
|
13
|
+
if (!a && !b)
|
|
14
|
+
return 0;
|
|
15
|
+
if (!a)
|
|
16
|
+
return -1;
|
|
17
|
+
if (!b)
|
|
18
|
+
return 1;
|
|
19
|
+
return a.y - b.y || a.x - b.x || compareColor(a.color, b.color);
|
|
20
|
+
}
|
|
21
|
+
function compareShape(a, b) {
|
|
22
|
+
for (let i = 0; i < Math.max(a.elements.length, b.elements.length); i++) {
|
|
23
|
+
const cmp = compareElement(a.elements[i], b.elements[i]);
|
|
24
|
+
if (cmp !== 0)
|
|
25
|
+
return cmp;
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
export function shapeEquals(a, b) {
|
|
30
|
+
return compareShape(a, b) === 0;
|
|
31
|
+
}
|
|
32
|
+
function recenterShape(shape) {
|
|
33
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
34
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
35
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
36
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
37
|
+
for (const element of shape.elements) {
|
|
38
|
+
minX = Math.min(minX, element.x);
|
|
39
|
+
minY = Math.min(minY, element.y);
|
|
40
|
+
maxX = Math.max(maxX, element.x);
|
|
41
|
+
maxY = Math.max(maxY, element.y);
|
|
42
|
+
}
|
|
43
|
+
for (const element of shape.elements) {
|
|
44
|
+
element.x -= minX;
|
|
45
|
+
element.y -= minY;
|
|
46
|
+
}
|
|
47
|
+
shape.width = maxX - minX + 1;
|
|
48
|
+
shape.height = maxY - minY + 1;
|
|
49
|
+
if (!Number.isFinite(shape.width)) {
|
|
50
|
+
shape.width = 0;
|
|
51
|
+
}
|
|
52
|
+
if (!Number.isFinite(shape.height)) {
|
|
53
|
+
shape.height = 0;
|
|
54
|
+
}
|
|
55
|
+
return shape;
|
|
56
|
+
}
|
|
57
|
+
export function tilesToShape(tiles) {
|
|
58
|
+
const shape = {
|
|
59
|
+
width: Math.max(...tiles.map(row => row.length)),
|
|
60
|
+
height: tiles.length,
|
|
61
|
+
elements: [],
|
|
62
|
+
};
|
|
63
|
+
for (let y = 0; y < tiles.length; y++) {
|
|
64
|
+
for (let x = 0; x < tiles[y].length; x++) {
|
|
65
|
+
const tile = tiles[y][x];
|
|
66
|
+
if (tile.exists && tile.color !== Color.Gray) {
|
|
67
|
+
shape.elements.push({ x, y, color: tile.color });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return recenterShape(shape);
|
|
72
|
+
}
|
|
73
|
+
export function positionsToShape(positions, color) {
|
|
74
|
+
return recenterShape({
|
|
75
|
+
width: 0,
|
|
76
|
+
height: 0,
|
|
77
|
+
elements: positions.map(p => ({ x: p.x, y: p.y, color })),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const shapeVariants = [
|
|
81
|
+
{ x: 'x', y: 'y' },
|
|
82
|
+
{ x: '-y', y: 'x' },
|
|
83
|
+
{ x: '-x', y: '-y' },
|
|
84
|
+
{ x: 'y', y: '-x' },
|
|
85
|
+
{ x: '-x', y: 'y' },
|
|
86
|
+
{ x: 'x', y: '-y' },
|
|
87
|
+
{ x: 'y', y: 'x' },
|
|
88
|
+
{ x: '-y', y: '-x' },
|
|
89
|
+
];
|
|
90
|
+
function mapCoord(map, x, y, width, height) {
|
|
91
|
+
switch (map) {
|
|
92
|
+
case 'x':
|
|
93
|
+
return x;
|
|
94
|
+
case 'y':
|
|
95
|
+
return y;
|
|
96
|
+
case '-x':
|
|
97
|
+
return width - 1 - x;
|
|
98
|
+
case '-y':
|
|
99
|
+
return height - 1 - y;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function getShapeVariants(shape) {
|
|
103
|
+
const variants = shapeVariants.map(({ x, y }) => ({
|
|
104
|
+
width: x.endsWith('x') ? shape.width : shape.height,
|
|
105
|
+
height: y.endsWith('y') ? shape.height : shape.width,
|
|
106
|
+
elements: shape.elements
|
|
107
|
+
.map(element => ({
|
|
108
|
+
x: mapCoord(x, element.x, element.y, shape.width, shape.height),
|
|
109
|
+
y: mapCoord(y, element.x, element.y, shape.width, shape.height),
|
|
110
|
+
color: element.color,
|
|
111
|
+
}))
|
|
112
|
+
.sort(compareElement),
|
|
113
|
+
}));
|
|
114
|
+
const uniqueVariants = [];
|
|
115
|
+
for (const variant of variants) {
|
|
116
|
+
if (!uniqueVariants.some(shape => shapeEquals(shape, variant))) {
|
|
117
|
+
uniqueVariants.push(variant);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return uniqueVariants;
|
|
121
|
+
}
|
|
122
|
+
export function normalizeShape(shape) {
|
|
123
|
+
const variants = getShapeVariants(shape);
|
|
124
|
+
return variants.reduce((min, variant) => (compareShape(variant, min) < 0 ? variant : min), variants[0]);
|
|
125
|
+
}
|
|
126
|
+
export function sanitizePatternGrid(pattern, tileMapper = t => t) {
|
|
127
|
+
return (pattern
|
|
128
|
+
// unlock all tiles
|
|
129
|
+
.withTiles(tiles => tiles.map(row => row.map(t => tileMapper(t.exists
|
|
130
|
+
? t.withFixed(false)
|
|
131
|
+
: t.copyWith({ exists: true, color: Color.Gray, fixed: false })))))
|
|
132
|
+
// strip all symbols and rules
|
|
133
|
+
.withRules([])
|
|
134
|
+
.withSymbols(new Map())
|
|
135
|
+
.withConnections(new GridConnections())
|
|
136
|
+
.withZones(new GridZones()));
|
|
137
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import UniversalSolver from './universal/universalSolver.js';
|
|
2
|
+
import BacktrackSolver from './backtrack/backtrackSolver.js';
|
|
3
|
+
import CspuzSolver from './cspuz/cspuzSolver.js';
|
|
4
|
+
import AutoSolver from './auto/autoSolver.js';
|
|
5
|
+
const allSolvers = new Map();
|
|
6
|
+
function register(prototype) {
|
|
7
|
+
allSolvers.set(prototype.id, prototype);
|
|
8
|
+
}
|
|
9
|
+
register(new AutoSolver());
|
|
10
|
+
register(new CspuzSolver());
|
|
11
|
+
register(new BacktrackSolver());
|
|
12
|
+
register(new UniversalSolver());
|
|
13
|
+
export { allSolvers };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import GridData from '../../grid.js';
|
|
2
|
+
import Solver from '../solver.js';
|
|
3
|
+
import Instruction from '../../instruction.js';
|
|
4
|
+
export default class AutoSolver extends Solver {
|
|
5
|
+
readonly id = "auto";
|
|
6
|
+
readonly author = "various contributors";
|
|
7
|
+
readonly description = "Automatically select the fastest solver based on supported instructions and environment.";
|
|
8
|
+
readonly supportsCancellation = true;
|
|
9
|
+
private static readonly nonAdditiveInstructions;
|
|
10
|
+
isGridSupported(grid: GridData): boolean;
|
|
11
|
+
isInstructionSupported(grid: GridData, instruction: Instruction): boolean;
|
|
12
|
+
protected isEnvironmentSupported(): Promise<boolean>;
|
|
13
|
+
private fillSolution;
|
|
14
|
+
private fixGrid;
|
|
15
|
+
private solveWithProgress;
|
|
16
|
+
private solveOne;
|
|
17
|
+
solve(grid: GridData, abortSignal?: AbortSignal): AsyncGenerator<GridData | null>;
|
|
18
|
+
}
|