@cubingcenter/scrambler 0.6.3 → 0.7.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 +2 -0
- package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/search.js +3 -3
- package/dist/puzzles/cube2/solver/tables.d.ts +6 -0
- package/dist/puzzles/cube2/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/tables.js +16 -2
- package/dist/puzzles/cube3/index.d.ts +1 -0
- package/dist/puzzles/cube3/index.d.ts.map +1 -1
- package/dist/puzzles/cube3/moves.d.ts.map +1 -1
- package/dist/puzzles/cube3/moves.js +104 -18
- package/dist/puzzles/cube3/scrambler.d.ts +16 -1
- package/dist/puzzles/cube3/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube3/scrambler.js +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.js +6 -2
- package/dist/puzzles/cube3/solver/index.d.ts +5 -3
- package/dist/puzzles/cube3/solver/index.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/index.js +2 -1
- package/dist/puzzles/cube3/solver/node-loader.js +9 -2
- package/dist/puzzles/cube3/solver/phase1.d.ts +18 -0
- package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase1.js +132 -14
- package/dist/puzzles/cube3/solver/phase2.d.ts +47 -0
- package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase2.js +236 -66
- package/dist/puzzles/cube3/solver/search-utils.d.ts +1 -1
- package/dist/puzzles/cube3/solver/search-utils.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/symmetry.d.ts +24 -0
- package/dist/puzzles/cube3/solver/symmetry.d.ts.map +1 -0
- package/dist/puzzles/cube3/solver/symmetry.js +74 -0
- package/dist/puzzles/cube3/solver/tables.d.ts +6 -1
- package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube3/validation.d.ts.map +1 -1
- package/dist/puzzles/cube3/validation.js +15 -7
- package/dist/puzzles/cube4/index.d.ts +3 -2
- package/dist/puzzles/cube4/index.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.js +2 -2
- package/dist/puzzles/cube4/moves.d.ts +5 -0
- package/dist/puzzles/cube4/moves.d.ts.map +1 -1
- package/dist/puzzles/cube4/moves.js +120 -11
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts +3 -0
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/browser-loader.js +34 -3
- package/dist/puzzles/cube4/reduction/center2.d.ts +20 -3
- package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/center2.js +53 -9
- package/dist/puzzles/cube4/reduction/edge3.d.ts +4 -0
- package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/edge3.js +23 -3
- package/dist/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
- package/dist/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
- package/dist/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts +50 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/hc-pdb.js +202 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts +5 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/node-loader.js +48 -8
- package/dist/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts +111 -5
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/phase3-search.js +341 -22
- package/dist/puzzles/cube4/reduction/solve.d.ts +112 -1
- package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -1
- package/dist/puzzles/cube4/reduction/solve.js +920 -181
- package/dist/puzzles/cube4/scrambler.d.ts +105 -4
- package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube4/scrambler.js +216 -166
- package/dist/puzzles/cube4/state.d.ts.map +1 -1
- package/dist/puzzles/cube4/state.js +4 -1
- package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/search.js +3 -6
- package/dist/puzzles/pyraminx/solver/tables.d.ts +6 -0
- package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/solver/tables.js +17 -0
- package/dist/puzzles/skewb/solver/search.js +3 -3
- package/dist/puzzles/skewb/solver/tables.d.ts +6 -0
- package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/tables.js +17 -0
- package/dist-cjs/puzzles/cube2/solver/search.js +2 -2
- package/dist-cjs/puzzles/cube2/solver/tables.js +17 -3
- package/dist-cjs/puzzles/cube3/moves.js +104 -18
- package/dist-cjs/puzzles/cube3/scrambler.js +1 -1
- package/dist-cjs/puzzles/cube3/solver/browser-loader.js +6 -2
- package/dist-cjs/puzzles/cube3/solver/index.js +8 -1
- package/dist-cjs/puzzles/cube3/solver/node-loader.js +9 -2
- package/dist-cjs/puzzles/cube3/solver/phase1.js +133 -14
- package/dist-cjs/puzzles/cube3/solver/phase2.js +233 -63
- package/dist-cjs/puzzles/cube3/solver/symmetry.js +80 -0
- package/dist-cjs/puzzles/cube3/validation.js +15 -7
- package/dist-cjs/puzzles/cube4/index.js +3 -1
- package/dist-cjs/puzzles/cube4/moves.js +121 -11
- package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +34 -3
- package/dist-cjs/puzzles/cube4/reduction/center2.js +54 -9
- package/dist-cjs/puzzles/cube4/reduction/edge3.js +24 -3
- package/dist-cjs/puzzles/cube4/reduction/generated/c3_pair_dist.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +36 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning-wide.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-distances.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-manifest.json +38 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/hc-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/hc-pdb.js +213 -0
- package/dist-cjs/puzzles/cube4/reduction/node-loader.js +48 -8
- package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +5 -5
- package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +343 -23
- package/dist-cjs/puzzles/cube4/reduction/solve.js +918 -173
- package/dist-cjs/puzzles/cube4/scrambler.js +214 -163
- package/dist-cjs/puzzles/cube4/state.js +4 -1
- package/dist-cjs/puzzles/pyraminx/solver/search.js +2 -5
- package/dist-cjs/puzzles/pyraminx/solver/tables.js +18 -1
- package/dist-cjs/puzzles/skewb/solver/search.js +2 -2
- package/dist-cjs/puzzles/skewb/solver/tables.js +18 -1
- package/package.json +14 -5
|
@@ -9,6 +9,7 @@ exports.clearCachedCube4Tables = clearCachedCube4Tables;
|
|
|
9
9
|
exports.loadCube4ReductionTablesBrowser = loadCube4ReductionTablesBrowser;
|
|
10
10
|
const edge3_js_1 = require("./edge3.js");
|
|
11
11
|
const compressed_fetch_js_1 = require("../../shared/compressed-fetch.js");
|
|
12
|
+
const hc_pdb_js_1 = require("./hc-pdb.js");
|
|
12
13
|
const GENERATED_DIRECTORY = "puzzles/cube4/reduction/generated";
|
|
13
14
|
const CACHE_NAME = "cubingcenter-scrambler-tables-v1";
|
|
14
15
|
let cachedTables;
|
|
@@ -36,13 +37,16 @@ async function loadCube4ReductionTablesBrowser(baseUrl) {
|
|
|
36
37
|
return cachedTables;
|
|
37
38
|
}
|
|
38
39
|
const resolved = resolveBaseUrl(baseUrl);
|
|
39
|
-
const [center1, center2, center3, edge3] = await Promise.all([
|
|
40
|
+
const [center1, center2, center3, edge3, hc] = await Promise.all([
|
|
40
41
|
loadCenter1(resolved),
|
|
41
42
|
loadCenter2(resolved),
|
|
42
43
|
loadCenter3(resolved),
|
|
43
|
-
loadEdge3(resolved)
|
|
44
|
+
loadEdge3(resolved),
|
|
45
|
+
loadHc(resolved)
|
|
44
46
|
]);
|
|
45
47
|
cachedTables = { center1, center2, center3, edge3 };
|
|
48
|
+
if (hc)
|
|
49
|
+
cachedTables.hc = hc;
|
|
46
50
|
return cachedTables;
|
|
47
51
|
}
|
|
48
52
|
async function fetchJson(baseUrl, file) {
|
|
@@ -79,7 +83,18 @@ async function loadCenter2(baseUrl) {
|
|
|
79
83
|
const byte = pruningPacked[i >> 1];
|
|
80
84
|
pruning[i] = (i & 1) === 0 ? byte & 0x0f : byte >> 4;
|
|
81
85
|
}
|
|
82
|
-
|
|
86
|
+
const tables = { ctMove, rlMove, pruning };
|
|
87
|
+
if (manifest.pruningWideTable) {
|
|
88
|
+
const wideBuffer = await (0, compressed_fetch_js_1.fetchTableBuffer)(baseUrl, GENERATED_DIRECTORY, manifest.pruningWideTable.file, { cacheName: CACHE_NAME, compressed: manifest.pruningWideTable.compressed !== false });
|
|
89
|
+
const widePacked = new Uint8Array(wideBuffer);
|
|
90
|
+
const pruningWide = new Uint8Array(450450);
|
|
91
|
+
for (let i = 0; i < 450450; i++) {
|
|
92
|
+
const byte = widePacked[i >> 1];
|
|
93
|
+
pruningWide[i] = (i & 1) === 0 ? byte & 0x0f : byte >> 4;
|
|
94
|
+
}
|
|
95
|
+
tables.pruningWide = pruningWide;
|
|
96
|
+
}
|
|
97
|
+
return tables;
|
|
83
98
|
}
|
|
84
99
|
async function loadCenter3(baseUrl) {
|
|
85
100
|
const manifest = await fetchJson(baseUrl, "center3-manifest.json");
|
|
@@ -95,6 +110,22 @@ async function loadCenter3(baseUrl) {
|
|
|
95
110
|
async function loadEdge3(baseUrl) {
|
|
96
111
|
const manifest = await fetchJson(baseUrl, "edge3-manifest.json");
|
|
97
112
|
const distancesBuffer = await (0, compressed_fetch_js_1.fetchTableBuffer)(baseUrl, GENERATED_DIRECTORY, manifest.distances.file, { cacheName: CACHE_NAME, compressed: manifest.distances.compressed !== false });
|
|
113
|
+
// Keep nibble-packed (see node-loader.ts): all readers handle both formats.
|
|
98
114
|
const distances = new Uint8Array(distancesBuffer);
|
|
99
115
|
return { distances, distanceOfEdge: (0, edge3_js_1.edge3DistanceLookup)(distances) };
|
|
100
116
|
}
|
|
117
|
+
async function loadHc(baseUrl) {
|
|
118
|
+
try {
|
|
119
|
+
const manifest = await fetchJson(baseUrl, "hc-manifest.json");
|
|
120
|
+
const distancesBuffer = await (0, compressed_fetch_js_1.fetchTableBuffer)(baseUrl, GENERATED_DIRECTORY, manifest.distances.file, { cacheName: CACHE_NAME, compressed: manifest.distances.compressed !== false });
|
|
121
|
+
const dense = (0, hc_pdb_js_1.buildHcDense)(new Uint8Array(distancesBuffer));
|
|
122
|
+
if (manifest.moveTable) {
|
|
123
|
+
const moveBuffer = await (0, compressed_fetch_js_1.fetchTableBuffer)(baseUrl, GENERATED_DIRECTORY, manifest.moveTable.file, { cacheName: CACHE_NAME, compressed: manifest.moveTable.compressed !== false });
|
|
124
|
+
dense.moves = new Int32Array(moveBuffer);
|
|
125
|
+
}
|
|
126
|
+
return dense;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
* - goal: ct == 0 and rl in the 6 reference goal patterns (even parity);
|
|
14
14
|
* - the 28-move set keeps the ct and rl position sets separate, so the move
|
|
15
15
|
* tables factor: ctmv (6,435×28) and rlmv (70×28);
|
|
16
|
-
* - the search explores the first 23 moves (face moves + Uw2/Rw/Rw2/Rw')
|
|
16
|
+
* - the search explores the first 23 moves (face moves + Uw2/Rw/Rw2/Rw')
|
|
17
|
+
* by default; the wide set (`CENTER2_SEARCH_MOVES_WIDE`, all 28, with
|
|
18
|
+
* the `pruningWide` table) additionally tries Dw2/Lw/Lw2/Lw'/Bw2.
|
|
17
19
|
*
|
|
18
20
|
* The phase-1 → phase-2 bridge (alignment + encode) is in `reduction.ts`.
|
|
19
21
|
*/
|
|
20
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.CENTER2_STATES = exports.CENTER2_RL_STATES = exports.CENTER2_CT_STATES = exports.CENTER2_GOAL_RL = exports.CENTER2_SEARCH_MOVES = exports.CENTER2_MOVES = void 0;
|
|
23
|
+
exports.ALIGNMENT_ROTATIONS = exports.CENTER2_STATES = exports.CENTER2_RL_STATES = exports.CENTER2_CT_STATES = exports.CENTER2_GOAL_RL = exports.CENTER2_SEARCH_MOVES_WIDE = exports.CENTER2_SEARCH_MOVES = exports.CENTER2_MOVES = void 0;
|
|
22
24
|
exports.wingPermutationParity = wingPermutationParity;
|
|
23
25
|
exports.encodeCenter2 = encodeCenter2;
|
|
24
26
|
exports.isCenter2Goal = isCenter2Goal;
|
|
@@ -26,6 +28,7 @@ exports.center2Bridge = center2Bridge;
|
|
|
26
28
|
exports.generateCenter2Tables = generateCenter2Tables;
|
|
27
29
|
exports.solveCenter2 = solveCenter2;
|
|
28
30
|
exports.solveCenter2All = solveCenter2All;
|
|
31
|
+
exports.getWingMoveMaps = getWingMoveMaps;
|
|
29
32
|
exports.solveCenter2GatedLength = solveCenter2GatedLength;
|
|
30
33
|
exports.solveCenter2Gated = solveCenter2Gated;
|
|
31
34
|
exports.verifyCenter2 = verifyCenter2;
|
|
@@ -41,6 +44,12 @@ exports.CENTER2_MOVES = [
|
|
|
41
44
|
];
|
|
42
45
|
/** The search's exploration set (the first 23 of CENTER2_MOVES). */
|
|
43
46
|
exports.CENTER2_SEARCH_MOVES = exports.CENTER2_MOVES.slice(0, 23);
|
|
47
|
+
/**
|
|
48
|
+
* The wide exploration set: all 28 moves (adds Dw2/Lw/Lw2/Lw'/Bw2).
|
|
49
|
+
* Searches over this set must use the `pruningWide` table — the
|
|
50
|
+
* 23-move pruning distances are inadmissible here (they overestimate).
|
|
51
|
+
*/
|
|
52
|
+
exports.CENTER2_SEARCH_MOVES_WIDE = exports.CENTER2_MOVES;
|
|
44
53
|
/** The 6 reference goal rl patterns (full 70-space values, even parity). */
|
|
45
54
|
exports.CENTER2_GOAL_RL = [0, 18, 28, 46, 54, 56];
|
|
46
55
|
exports.CENTER2_CT_STATES = 6435;
|
|
@@ -125,6 +134,11 @@ const ALIGNMENT_CANDIDATES = [
|
|
|
125
134
|
["Uw", "Dw'"]
|
|
126
135
|
];
|
|
127
136
|
function center2InvariantDiffs(centers) {
|
|
137
|
+
const rlAxis = centers[RL_POS[7]] % 3;
|
|
138
|
+
for (let i = 0; i < 7; i++) {
|
|
139
|
+
if (centers[RL_POS[i]] % 3 !== rlAxis)
|
|
140
|
+
return { ctDiff: -1, rlDiff: -1 };
|
|
141
|
+
}
|
|
128
142
|
let ctDiff = 0;
|
|
129
143
|
let rlDiff = 0;
|
|
130
144
|
for (let i = 0; i < 15; i++) {
|
|
@@ -137,12 +151,18 @@ function center2InvariantDiffs(centers) {
|
|
|
137
151
|
}
|
|
138
152
|
return { ctDiff, rlDiff };
|
|
139
153
|
}
|
|
154
|
+
exports.ALIGNMENT_ROTATIONS = [
|
|
155
|
+
[],
|
|
156
|
+
["z"],
|
|
157
|
+
["y"]
|
|
158
|
+
];
|
|
140
159
|
/**
|
|
141
160
|
* Phase-1 → phase-2 bridge: apply the shortest alignment candidate that
|
|
142
161
|
* makes the state coordinate-invariant, then encode.
|
|
143
162
|
*/
|
|
144
163
|
function center2Bridge(state) {
|
|
145
|
-
for (
|
|
164
|
+
for (let idx = 0; idx < ALIGNMENT_CANDIDATES.length; idx++) {
|
|
165
|
+
const alignment = ALIGNMENT_CANDIDATES[idx];
|
|
146
166
|
const aligned = alignment.length === 0
|
|
147
167
|
? state
|
|
148
168
|
: (0, moves_js_1.applyCube4Algorithm)(state, alignment);
|
|
@@ -150,6 +170,7 @@ function center2Bridge(state) {
|
|
|
150
170
|
if (ctDiff === 8 && rlDiff === 4) {
|
|
151
171
|
return {
|
|
152
172
|
alignment: [...alignment],
|
|
173
|
+
rotation: [...exports.ALIGNMENT_ROTATIONS[idx]],
|
|
153
174
|
state: aligned,
|
|
154
175
|
encoded: encodeCenter2(aligned)
|
|
155
176
|
};
|
|
@@ -259,7 +280,31 @@ function generateCenter2Tables() {
|
|
|
259
280
|
}
|
|
260
281
|
}
|
|
261
282
|
}
|
|
262
|
-
|
|
283
|
+
// Wide pruning BFS: same goals, all 28 moves (exact distances for the
|
|
284
|
+
// wide search; the 23-move table overestimates there).
|
|
285
|
+
const pruningWide = new Uint8Array(exports.CENTER2_STATES).fill(0xff);
|
|
286
|
+
const wideQueue = [];
|
|
287
|
+
for (const rl of exports.CENTER2_GOAL_RL) {
|
|
288
|
+
pruningWide[rl] = 0;
|
|
289
|
+
wideQueue.push(rl);
|
|
290
|
+
}
|
|
291
|
+
let wideHead = 0;
|
|
292
|
+
while (wideHead < wideQueue.length) {
|
|
293
|
+
const idx = wideQueue[wideHead++];
|
|
294
|
+
const ct = Math.floor(idx / exports.CENTER2_RL_STATES);
|
|
295
|
+
const rl = idx % exports.CENTER2_RL_STATES;
|
|
296
|
+
const d = pruningWide[idx];
|
|
297
|
+
for (let m = 0; m < exports.CENTER2_SEARCH_MOVES_WIDE.length; m++) {
|
|
298
|
+
const nextCt = ctMove[ct * exports.CENTER2_MOVES.length + m];
|
|
299
|
+
const nextRl = rlMove[rl * exports.CENTER2_MOVES.length + m];
|
|
300
|
+
const next = nextCt * exports.CENTER2_RL_STATES + nextRl;
|
|
301
|
+
if (pruningWide[next] === 0xff) {
|
|
302
|
+
pruningWide[next] = d + 1;
|
|
303
|
+
wideQueue.push(next);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { ctMove, rlMove, pruning, pruningWide };
|
|
263
308
|
}
|
|
264
309
|
// The reference's cancellation rule (ckmv over move2std): skip the same base
|
|
265
310
|
// move, or the same axis-class when the previous move's standard index is
|
|
@@ -434,24 +479,24 @@ function buildWingMoveMaps() {
|
|
|
434
479
|
// ---------------------------------------------------------------------------
|
|
435
480
|
// Verification gates
|
|
436
481
|
// ---------------------------------------------------------------------------
|
|
437
|
-
function verifyCenter2(tables) {
|
|
482
|
+
function verifyCenter2(tables, pruning = tables.pruning, moves = exports.CENTER2_SEARCH_MOVES) {
|
|
438
483
|
const errors = [];
|
|
439
484
|
for (const rl of exports.CENTER2_GOAL_RL) {
|
|
440
|
-
if (
|
|
485
|
+
if (pruning[rl] !== 0) {
|
|
441
486
|
errors.push(`Goal rl ${rl} must have pruning 0.`);
|
|
442
487
|
}
|
|
443
488
|
}
|
|
444
489
|
let maxDepth = 0;
|
|
445
490
|
for (let idx = 0; idx < exports.CENTER2_STATES; idx++) {
|
|
446
|
-
const d =
|
|
491
|
+
const d = pruning[idx];
|
|
447
492
|
if (d > maxDepth)
|
|
448
493
|
maxDepth = d;
|
|
449
494
|
const ct = Math.floor(idx / exports.CENTER2_RL_STATES);
|
|
450
495
|
const rl = idx % exports.CENTER2_RL_STATES;
|
|
451
|
-
for (let m = 0; m <
|
|
496
|
+
for (let m = 0; m < moves.length; m++) {
|
|
452
497
|
const nc = tables.ctMove[ct * exports.CENTER2_MOVES.length + m];
|
|
453
498
|
const nr = tables.rlMove[rl * exports.CENTER2_MOVES.length + m];
|
|
454
|
-
const nd =
|
|
499
|
+
const nd = pruning[nc * exports.CENTER2_RL_STATES + nr];
|
|
455
500
|
if (nd < d - 1 || nd > d + 1) {
|
|
456
501
|
errors.push(`Pruning inconsistency at ${idx} move ${exports.CENTER2_MOVES[m]}: ${d} -> ${nd}.`);
|
|
457
502
|
break;
|
|
@@ -28,6 +28,7 @@ exports.getSymTables = getSymTables;
|
|
|
28
28
|
exports.buildSymTables = buildSymTables;
|
|
29
29
|
exports.getMvSymFrom = getMvSymFrom;
|
|
30
30
|
exports.generateEdge3Tables = generateEdge3Tables;
|
|
31
|
+
exports.unpackEdge3Distances = unpackEdge3Distances;
|
|
31
32
|
exports.edge3DistanceLookup = edge3DistanceLookup;
|
|
32
33
|
exports.__edge3TestHooks = __edge3TestHooks;
|
|
33
34
|
exports.verifyEdge3 = verifyEdge3;
|
|
@@ -479,8 +480,23 @@ function generateEdge3Tables(maxDepthCap = -1) {
|
|
|
479
480
|
frontier = next;
|
|
480
481
|
depth++;
|
|
481
482
|
}
|
|
482
|
-
const
|
|
483
|
-
|
|
483
|
+
const unpacked = unpackEdge3Distances(distances);
|
|
484
|
+
const distanceOfEdge = edge3DistanceLookup(unpacked);
|
|
485
|
+
return { distances: unpacked, distanceOfEdge };
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Unpack 4-bit nibble-packed distances into a byte-expanded Uint8Array (1 byte per state).
|
|
489
|
+
*/
|
|
490
|
+
function unpackEdge3Distances(packed) {
|
|
491
|
+
if (packed.length >= exports.EDGE3_TOTAL)
|
|
492
|
+
return packed;
|
|
493
|
+
const unpacked = new Uint8Array(exports.EDGE3_TOTAL);
|
|
494
|
+
for (let i = 0; i < packed.length; i++) {
|
|
495
|
+
const b = packed[i];
|
|
496
|
+
unpacked[i << 1] = b & 0x0f;
|
|
497
|
+
unpacked[(i << 1) | 1] = b >> 4;
|
|
498
|
+
}
|
|
499
|
+
return unpacked;
|
|
484
500
|
}
|
|
485
501
|
/**
|
|
486
502
|
* The distance lookup over a loaded distances buffer: builds the sym
|
|
@@ -491,9 +507,12 @@ function edge3DistanceLookup(distances) {
|
|
|
491
507
|
const t = symTables ?? buildSymTables();
|
|
492
508
|
const { sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto } = t;
|
|
493
509
|
const identity = Uint8Array.from({ length: 12 }, (_, i) => i);
|
|
510
|
+
const isUnpacked = distances.length >= exports.EDGE3_TOTAL;
|
|
494
511
|
return (e) => {
|
|
495
512
|
const std = (0, pairing_coordinate_js_1.normalizePairingState)(e, identity).edge;
|
|
496
513
|
const idx = getMvSymFrom(std, identity, 20, sym2Raw, sym2Mask, raw2Sym, mvrot, mvroto) >> 3;
|
|
514
|
+
if (isUnpacked)
|
|
515
|
+
return distances[idx];
|
|
497
516
|
return (distances[idx >> 1] >> ((idx & 1) * 4)) & 0x0f;
|
|
498
517
|
};
|
|
499
518
|
}
|
|
@@ -511,8 +530,10 @@ function verifyEdge3(tables) {
|
|
|
511
530
|
errors.push("Solved state must have distance 0.");
|
|
512
531
|
}
|
|
513
532
|
let seen = 0;
|
|
533
|
+
const isUnpacked = tables.distances.length >= exports.EDGE3_TOTAL;
|
|
514
534
|
for (let i = 0; i < exports.EDGE3_TOTAL; i++) {
|
|
515
|
-
|
|
535
|
+
const d = isUnpacked ? tables.distances[i] : ((tables.distances[i >> 1] >> ((i & 1) * 4)) & 0x0f);
|
|
536
|
+
if (d !== 0x0f)
|
|
516
537
|
seen++;
|
|
517
538
|
}
|
|
518
539
|
if (seen !== exports.EDGE3_TOTAL) {
|