@cubingcenter/scrambler 0.7.0 → 0.8.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/README.md +15 -4
- package/dist/core/api.d.ts.map +1 -1
- package/dist/core/api.js +10 -2
- package/dist/puzzles/cube2/solver/browser-loader.d.ts +4 -7
- package/dist/puzzles/cube2/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/browser-loader.js +42 -14
- package/dist/puzzles/cube2/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/generated-assets.js +8 -3
- package/dist/puzzles/cube3/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.js +42 -20
- package/dist/puzzles/cube3/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/generated-assets.js +9 -3
- package/dist/puzzles/cube3/solver/phase1.d.ts +19 -0
- package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase1.js +29 -6
- package/dist/puzzles/cube3/solver/phase2.d.ts +28 -0
- package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase2.js +56 -15
- package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/tables.js +14 -12
- package/dist/puzzles/cube4/browser-worker-pool.d.ts +82 -0
- package/dist/puzzles/cube4/browser-worker-pool.d.ts.map +1 -0
- package/dist/puzzles/cube4/browser-worker-pool.js +205 -0
- package/dist/puzzles/cube4/browser-worker.d.ts +2 -0
- package/dist/puzzles/cube4/browser-worker.d.ts.map +1 -0
- package/dist/puzzles/cube4/browser-worker.js +31 -0
- package/dist/puzzles/cube4/index.d.ts +7 -0
- package/dist/puzzles/cube4/index.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.js +4 -0
- package/dist/puzzles/cube4/moves.d.ts.map +1 -1
- package/dist/puzzles/cube4/moves.js +122 -30
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts +26 -1
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/browser-loader.js +212 -48
- package/dist/puzzles/cube4/reduction/center2.d.ts +24 -0
- package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/center2.js +99 -1
- package/dist/puzzles/cube4/reduction/finish3.d.ts +53 -0
- package/dist/puzzles/cube4/reduction/finish3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/finish3.js +393 -0
- package/dist/puzzles/cube4/reduction/generated/hc-manifest.json +6 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts +5 -3
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/hc-pdb.js +30 -12
- package/dist/puzzles/cube4/reduction/node-loader.d.ts +10 -1
- package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/node-loader.js +170 -36
- package/dist/puzzles/cube4/reduction/pair-transversal.d.ts +28 -0
- package/dist/puzzles/cube4/reduction/pair-transversal.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/pair-transversal.js +107 -0
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts +33 -30
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/phase3-search.js +211 -104
- package/dist/puzzles/cube4/reduction/rotation-fix.d.ts +28 -0
- package/dist/puzzles/cube4/reduction/rotation-fix.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/rotation-fix.js +212 -0
- package/dist/puzzles/cube4/reduction/solve.d.ts +72 -13
- package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/solve.js +374 -92
- package/dist/puzzles/cube4/scramble-cache.d.ts +93 -0
- package/dist/puzzles/cube4/scramble-cache.d.ts.map +1 -0
- package/dist/puzzles/cube4/scramble-cache.js +150 -0
- package/dist/puzzles/cube4/scrambler.d.ts +112 -18
- package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube4/scrambler.js +271 -83
- package/dist/puzzles/cube4/worker-pool.d.ts +139 -0
- package/dist/puzzles/cube4/worker-pool.d.ts.map +1 -0
- package/dist/puzzles/cube4/worker-pool.js +405 -0
- package/dist/puzzles/cube4/worker-protocol.d.ts +58 -0
- package/dist/puzzles/cube4/worker-protocol.d.ts.map +1 -0
- package/dist/puzzles/cube4/worker-protocol.js +58 -0
- package/dist/puzzles/cube4/worker.d.ts +26 -0
- package/dist/puzzles/cube4/worker.d.ts.map +1 -0
- package/dist/puzzles/cube4/worker.js +49 -0
- package/dist/puzzles/pyraminx/solver/browser-loader.d.ts +4 -8
- package/dist/puzzles/pyraminx/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/browser-loader.js +44 -15
- package/dist/puzzles/pyraminx/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/generated-assets.js +8 -3
- package/dist/puzzles/shared/compressed-fetch.d.ts +37 -1
- package/dist/puzzles/shared/compressed-fetch.d.ts.map +1 -1
- package/dist/puzzles/shared/compressed-fetch.js +226 -31
- package/dist/puzzles/shared/load-once.d.ts +16 -0
- package/dist/puzzles/shared/load-once.d.ts.map +1 -0
- package/dist/puzzles/shared/load-once.js +11 -0
- package/dist/puzzles/skewb/solver/browser-loader.d.ts +4 -11
- package/dist/puzzles/skewb/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/browser-loader.js +44 -16
- package/dist/puzzles/skewb/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/generated-assets.js +8 -3
- package/dist/puzzles/sq1/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/sq1/solver/browser-loader.js +58 -26
- package/dist-cjs/core/api.js +10 -2
- package/dist-cjs/puzzles/cube2/solver/browser-loader.js +42 -14
- package/dist-cjs/puzzles/cube2/solver/generated-assets.js +8 -3
- package/dist-cjs/puzzles/cube3/solver/browser-loader.js +42 -20
- package/dist-cjs/puzzles/cube3/solver/generated-assets.js +9 -3
- package/dist-cjs/puzzles/cube3/solver/phase1.js +29 -6
- package/dist-cjs/puzzles/cube3/solver/phase2.js +56 -15
- package/dist-cjs/puzzles/cube3/solver/tables.js +14 -12
- package/dist-cjs/puzzles/cube4/browser-worker-pool.js +211 -0
- package/dist-cjs/puzzles/cube4/index.js +21 -1
- package/dist-cjs/puzzles/cube4/moves.js +122 -30
- package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +212 -48
- package/dist-cjs/puzzles/cube4/reduction/center2.js +102 -2
- package/dist-cjs/puzzles/cube4/reduction/finish3.js +398 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-manifest.json +6 -0
- package/dist-cjs/puzzles/cube4/reduction/hc-pdb.js +31 -12
- package/dist-cjs/puzzles/cube4/reduction/node-loader.js +171 -36
- package/dist-cjs/puzzles/cube4/reduction/pair-transversal.js +112 -0
- package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +211 -104
- package/dist-cjs/puzzles/cube4/reduction/rotation-fix.js +216 -0
- package/dist-cjs/puzzles/cube4/reduction/solve.js +374 -88
- package/dist-cjs/puzzles/cube4/scramble-cache.js +156 -0
- package/dist-cjs/puzzles/cube4/scrambler.js +271 -80
- package/dist-cjs/puzzles/cube4/worker-pool.js +447 -0
- package/dist-cjs/puzzles/cube4/worker-protocol.js +62 -0
- package/dist-cjs/puzzles/pyraminx/solver/browser-loader.js +44 -15
- package/dist-cjs/puzzles/pyraminx/solver/generated-assets.js +8 -3
- package/dist-cjs/puzzles/shared/compressed-fetch.js +229 -31
- package/dist-cjs/puzzles/shared/load-once.js +14 -0
- package/dist-cjs/puzzles/skewb/solver/browser-loader.js +44 -16
- package/dist-cjs/puzzles/skewb/solver/generated-assets.js +8 -3
- package/dist-cjs/puzzles/sq1/solver/browser-loader.js +58 -26
- package/docs/development.md +19 -7
- package/package.json +4 -3
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Placement of the whole-cube rotation fix inside a 4x4 solution.
|
|
4
|
+
*
|
|
5
|
+
* The reduction ends with the cube solved in some orientation, so the solve
|
|
6
|
+
* is `P ++ W(R) ++ Q` where `W(R)` are the 2-4 wide moves of the rotation R
|
|
7
|
+
* (`x` = `Rw Lw'`, ...). A rotation commutes with any move sequence once the
|
|
8
|
+
* sequence's faces are re-mapped:
|
|
9
|
+
*
|
|
10
|
+
* X ++ W(R) ≡ W(R) ++ rotateAlgorithm(X, R)
|
|
11
|
+
*
|
|
12
|
+
* so the fix can sit at ANY point of the solution (with the moves after it
|
|
13
|
+
* re-mapped), and a two-rotation fix can be split across two points. The
|
|
14
|
+
* total is unchanged except at the insertion junctions, where the fix can
|
|
15
|
+
* cancel against same-axis wide moves (`Uw2 · y2` = `Uw2 · Uw2 Dw2` = `Dw2`).
|
|
16
|
+
* `placeRotationFix` picks the placement with the shortest simplified total.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.ROTATION_WORDS = void 0;
|
|
20
|
+
exports.placeRotationFix = placeRotationFix;
|
|
21
|
+
const moves_js_1 = require("../moves.js");
|
|
22
|
+
const state_js_1 = require("../state.js");
|
|
23
|
+
/** Wide-move words of the 9 single rotations. */
|
|
24
|
+
exports.ROTATION_WORDS = {
|
|
25
|
+
"x": ["Rw", "Lw'"],
|
|
26
|
+
"y": ["Uw", "Dw'"],
|
|
27
|
+
"z": ["Fw", "Bw'"],
|
|
28
|
+
"x'": ["Rw'", "Lw"],
|
|
29
|
+
"y'": ["Uw'", "Dw"],
|
|
30
|
+
"z'": ["Fw'", "Bw"],
|
|
31
|
+
"x2": ["Rw2", "Lw2"],
|
|
32
|
+
"y2": ["Uw2", "Dw2"],
|
|
33
|
+
"z2": ["Fw2", "Bw2"]
|
|
34
|
+
};
|
|
35
|
+
const FACE_MAPS = {
|
|
36
|
+
"x": { U: "B", R: "R", F: "U", D: "F", L: "L", B: "D" },
|
|
37
|
+
"x'": { U: "F", R: "R", F: "D", D: "B", L: "L", B: "U" },
|
|
38
|
+
"y": { U: "U", R: "F", F: "L", D: "D", L: "B", B: "R" },
|
|
39
|
+
"y'": { U: "U", R: "B", F: "R", D: "D", L: "F", B: "L" },
|
|
40
|
+
"z": { U: "R", R: "D", F: "F", D: "L", L: "U", B: "B" },
|
|
41
|
+
"z'": { U: "L", R: "U", F: "F", D: "R", L: "D", B: "B" },
|
|
42
|
+
"x2": { U: "D", R: "R", F: "B", D: "U", L: "L", B: "F" },
|
|
43
|
+
"y2": { U: "U", R: "L", F: "B", D: "D", L: "R", B: "F" },
|
|
44
|
+
"z2": { U: "D", R: "L", F: "F", D: "U", L: "R", B: "B" }
|
|
45
|
+
};
|
|
46
|
+
const FACES = ["U", "R", "F", "D", "L", "B"];
|
|
47
|
+
/** Composite face map of a rotation sequence (applied left to right). */
|
|
48
|
+
function faceMapOf(rotations) {
|
|
49
|
+
const map = {};
|
|
50
|
+
for (const face of FACES) {
|
|
51
|
+
let current = face;
|
|
52
|
+
for (const rotation of rotations)
|
|
53
|
+
current = FACE_MAPS[rotation][current];
|
|
54
|
+
map[face] = current;
|
|
55
|
+
}
|
|
56
|
+
return map;
|
|
57
|
+
}
|
|
58
|
+
function remap(moves, map) {
|
|
59
|
+
const out = new Array(moves.length);
|
|
60
|
+
for (let i = 0; i < moves.length; i++) {
|
|
61
|
+
const move = moves[i];
|
|
62
|
+
out[i] = (map[move[0]] + move.slice(1));
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
const rotationKey = (rotations) => (0, moves_js_1.applyCube4Algorithm)((0, state_js_1.createSolvedCube4State)(), rotations.flatMap((rotation) => exports.ROTATION_WORDS[rotation])).centers.join(",");
|
|
67
|
+
/**
|
|
68
|
+
* Every factorization of each rotation element into 1 or 2 single rotations
|
|
69
|
+
* (keyed by the rotated solved cube's centers). Non-minimal ones are kept on
|
|
70
|
+
* purpose: `x2` as `x · x` costs 4 moves but can cancel at two junctions.
|
|
71
|
+
*/
|
|
72
|
+
const FACTORIZATIONS = (() => {
|
|
73
|
+
const names = Object.keys(exports.ROTATION_WORDS);
|
|
74
|
+
const byKey = new Map();
|
|
75
|
+
const add = (sequence) => {
|
|
76
|
+
const key = rotationKey(sequence);
|
|
77
|
+
const list = byKey.get(key);
|
|
78
|
+
if (!list)
|
|
79
|
+
byKey.set(key, [sequence]);
|
|
80
|
+
else
|
|
81
|
+
list.push(sequence);
|
|
82
|
+
};
|
|
83
|
+
for (const a of names)
|
|
84
|
+
add([a]);
|
|
85
|
+
for (const a of names)
|
|
86
|
+
for (const b of names)
|
|
87
|
+
add([a, b]);
|
|
88
|
+
return byKey;
|
|
89
|
+
})();
|
|
90
|
+
const AXIS_OF_FACE = { U: 0, D: 0, R: 1, L: 1, F: 2, B: 2 };
|
|
91
|
+
/** Segment boundaries (maximal same-axis runs) of a sequence: 0, ..., n. */
|
|
92
|
+
function runBoundaries(moves) {
|
|
93
|
+
const bounds = [0];
|
|
94
|
+
for (let i = 1; i < moves.length; i++) {
|
|
95
|
+
if (AXIS_OF_FACE[moves[i][0]] !== AXIS_OF_FACE[moves[i - 1][0]])
|
|
96
|
+
bounds.push(i);
|
|
97
|
+
}
|
|
98
|
+
if (moves.length > 0)
|
|
99
|
+
bounds.push(moves.length);
|
|
100
|
+
return bounds;
|
|
101
|
+
}
|
|
102
|
+
/** Moves saved by simplifying across one inserted word, judged on a window of 2 runs per side. */
|
|
103
|
+
function junctionSaving(moves, bounds, b, word, leftMap, rightMap) {
|
|
104
|
+
const lo = bounds[Math.max(0, b - 2)];
|
|
105
|
+
const hi = bounds[Math.min(bounds.length - 1, b + 2)];
|
|
106
|
+
const at = bounds[b];
|
|
107
|
+
const left = moves.slice(lo, at);
|
|
108
|
+
const window = [...(leftMap ? remap(left, leftMap) : left), ...word, ...remap(moves.slice(at, hi), rightMap)];
|
|
109
|
+
return window.length - (0, moves_js_1.simplifyCube4Algorithm)(window).length;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Shortest simplified solution equivalent to `prefix ++ W(rotation) ++
|
|
113
|
+
* suffix` (same effect on every state), over every run-boundary insertion
|
|
114
|
+
* point of the fix and every minimal factorization of the rotation. Only
|
|
115
|
+
* run boundaries matter: the fix can only merge with runs on its own axis,
|
|
116
|
+
* and re-mapping preserves the run structure of what follows it.
|
|
117
|
+
*/
|
|
118
|
+
function placeRotationFix(prefix, rotation, suffix) {
|
|
119
|
+
const fixed = (0, moves_js_1.simplifyCube4Algorithm)([
|
|
120
|
+
...prefix,
|
|
121
|
+
...rotation.flatMap((r) => exports.ROTATION_WORDS[r]),
|
|
122
|
+
...suffix
|
|
123
|
+
]);
|
|
124
|
+
if (rotation.length === 0)
|
|
125
|
+
return fixed;
|
|
126
|
+
let best = fixed;
|
|
127
|
+
const consider = (candidate) => {
|
|
128
|
+
const simplified = (0, moves_js_1.simplifyCube4Algorithm)(candidate);
|
|
129
|
+
if (simplified.length < best.length)
|
|
130
|
+
best = simplified;
|
|
131
|
+
};
|
|
132
|
+
// A = prefix ++ Q' with W(R) ++ suffix ≡ Q' ++ W(R): Q' = remap(suffix, R⁻¹).
|
|
133
|
+
const forward = faceMapOf(rotation);
|
|
134
|
+
const inverseMap = {};
|
|
135
|
+
for (const face of FACES)
|
|
136
|
+
inverseMap[forward[face]] = face;
|
|
137
|
+
const all = (0, moves_js_1.simplifyCube4Algorithm)([...prefix, ...remap(suffix, inverseMap)]);
|
|
138
|
+
const bounds = runBoundaries(all);
|
|
139
|
+
const m = bounds.length;
|
|
140
|
+
const identity = faceMapOf([]);
|
|
141
|
+
for (const factors of FACTORIZATIONS.get(rotationKey(rotation)) ?? [rotation]) {
|
|
142
|
+
if (factors.length === 1) {
|
|
143
|
+
const map = faceMapOf(factors);
|
|
144
|
+
const word = exports.ROTATION_WORDS[factors[0]];
|
|
145
|
+
let bestB = -1;
|
|
146
|
+
let bestSaving = 0;
|
|
147
|
+
for (let b = 0; b < m; b++) {
|
|
148
|
+
const saving = junctionSaving(all, bounds, b, word, null, map);
|
|
149
|
+
if (saving > bestSaving) {
|
|
150
|
+
bestSaving = saving;
|
|
151
|
+
bestB = b;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (bestB >= 0) {
|
|
155
|
+
const k = bounds[bestB];
|
|
156
|
+
consider([...all.slice(0, k), ...word, ...remap(all.slice(k), map)]);
|
|
157
|
+
}
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const map1 = faceMapOf([factors[0]]);
|
|
161
|
+
const map12 = faceMapOf(factors);
|
|
162
|
+
const word1 = exports.ROTATION_WORDS[factors[0]];
|
|
163
|
+
const word2 = exports.ROTATION_WORDS[factors[1]];
|
|
164
|
+
const build = (b1, b2) => {
|
|
165
|
+
const k1 = bounds[b1];
|
|
166
|
+
const k2 = bounds[b2];
|
|
167
|
+
return [
|
|
168
|
+
...all.slice(0, k1),
|
|
169
|
+
...word1,
|
|
170
|
+
...remap(all.slice(k1, k2), map1),
|
|
171
|
+
...word2,
|
|
172
|
+
...remap(all.slice(k2), map12)
|
|
173
|
+
];
|
|
174
|
+
};
|
|
175
|
+
// Far-apart junctions save independently: s1 (unmapped | map1) at b1,
|
|
176
|
+
// s2 (map1 | map12) at b2 >= b1 + 3, combined with a suffix maximum.
|
|
177
|
+
// Both words at one point (b1 == b2) is a single junction (s12); nearby
|
|
178
|
+
// pairs interact, so the best few estimates are re-scored exactly.
|
|
179
|
+
const s1 = new Int32Array(m);
|
|
180
|
+
const s2 = new Int32Array(m);
|
|
181
|
+
const word12 = [...word1, ...word2];
|
|
182
|
+
const shortlist = [];
|
|
183
|
+
for (let b = 0; b < m; b++) {
|
|
184
|
+
s1[b] = junctionSaving(all, bounds, b, word1, identity, map1);
|
|
185
|
+
s2[b] = junctionSaving(all, bounds, b, word2, map1, map12);
|
|
186
|
+
const s12 = junctionSaving(all, bounds, b, word12, identity, map12);
|
|
187
|
+
if (s12 > 0)
|
|
188
|
+
shortlist.push([s12, b, b]);
|
|
189
|
+
}
|
|
190
|
+
let suffixBest = -1;
|
|
191
|
+
for (let b1 = m - 4; b1 >= 0; b1--) {
|
|
192
|
+
const b2Candidate = b1 + 3;
|
|
193
|
+
if (suffixBest < 0 || s2[b2Candidate] > s2[suffixBest])
|
|
194
|
+
suffixBest = b2Candidate;
|
|
195
|
+
const saving = s1[b1] + s2[suffixBest];
|
|
196
|
+
if (saving > 0)
|
|
197
|
+
shortlist.push([saving, b1, suffixBest]);
|
|
198
|
+
for (let b2 = b1 + 1; b2 < Math.min(m, b1 + 3); b2++) {
|
|
199
|
+
if (s1[b1] + s2[b2] > 0)
|
|
200
|
+
shortlist.push([s1[b1] + s2[b2], b1, b2]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
shortlist.sort((a, b) => b[0] - a[0] || a[1] - b[1] || a[2] - b[2]);
|
|
204
|
+
const seen = new Set();
|
|
205
|
+
for (const [, b1, b2] of shortlist) {
|
|
206
|
+
if (seen.size >= 4)
|
|
207
|
+
break;
|
|
208
|
+
const key = b1 * 256 + b2;
|
|
209
|
+
if (seen.has(key))
|
|
210
|
+
continue;
|
|
211
|
+
seen.add(key);
|
|
212
|
+
consider(build(b1, b2));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return best;
|
|
216
|
+
}
|