@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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 2,
|
|
3
|
+
"puzzle": "cube4",
|
|
4
|
+
"phase": "hc",
|
|
5
|
+
"moves": [
|
|
6
|
+
"U",
|
|
7
|
+
"U2",
|
|
8
|
+
"U'",
|
|
9
|
+
"R2",
|
|
10
|
+
"F",
|
|
11
|
+
"F2",
|
|
12
|
+
"F'",
|
|
13
|
+
"D",
|
|
14
|
+
"D2",
|
|
15
|
+
"D'",
|
|
16
|
+
"L2",
|
|
17
|
+
"B",
|
|
18
|
+
"B2",
|
|
19
|
+
"B'",
|
|
20
|
+
"Uw2",
|
|
21
|
+
"Rw2",
|
|
22
|
+
"Fw2"
|
|
23
|
+
],
|
|
24
|
+
"states": 2704156,
|
|
25
|
+
"reachableStates": 58800,
|
|
26
|
+
"reachableDense": 58800,
|
|
27
|
+
"maxDepth": 11,
|
|
28
|
+
"distances": {
|
|
29
|
+
"file": "hc-distances.bin",
|
|
30
|
+
"range": 2704156,
|
|
31
|
+
"checksum": "8720ec4a83eca33c3d56ae0ab8709c0b3d847c14d011b6dcc4413b28bd9dfa12"
|
|
32
|
+
},
|
|
33
|
+
"moveTable": {
|
|
34
|
+
"file": "hc-move.bin",
|
|
35
|
+
"range": 999600,
|
|
36
|
+
"checksum": "6bd1d8f36b77e0863425bced1dfb69df7a13dde4fb18ceeaeba00abf14519922"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Half-class exact PDB (Phase-3 center heuristic, Fase 1 pivot).
|
|
4
|
+
*
|
|
5
|
+
* PIVOT NOTE: the original Fase-1 spec (3 exact face-pair color PDBs,
|
|
6
|
+
* C(24,4)xC(20,4) = 51M states each) is unworkable — verified that outer
|
|
7
|
+
* face turns never move centers across faces (only wide doubles do), so
|
|
8
|
+
* the exact-color orbit under the 17 search moves holds ~70 states and
|
|
9
|
+
* the bound would read "unknown" almost everywhere. This table instead
|
|
10
|
+
* tracks the EXACT arrangement of half-class bits ((color/3)^1: 12 ones,
|
|
11
|
+
* 12 zeros), which moves under every search move:
|
|
12
|
+
*
|
|
13
|
+
* states = C(24,12) = 2,704,156, nibble-packed (~1.35 MB)
|
|
14
|
+
*
|
|
15
|
+
* Center3 (29,400 states) is a quotient of this coordinate (rank-7 pair
|
|
16
|
+
* + rl-index + parity), so this PDB dominates it by construction:
|
|
17
|
+
* bound = max(ct3, edge, hc). BFS from solved with the 17 search moves.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.HC_REACHABLE = exports.HC_PDB_STATES = exports.HC_PDB_MOVES = void 0;
|
|
21
|
+
exports.hcRank = hcRank;
|
|
22
|
+
exports.hcUnrank = hcUnrank;
|
|
23
|
+
exports.encodeHcPdb = encodeHcPdb;
|
|
24
|
+
exports.getHcPdbMoveMaps = getHcPdbMoveMaps;
|
|
25
|
+
exports.hcPdbDistance = hcPdbDistance;
|
|
26
|
+
exports.generateHcPdb = generateHcPdb;
|
|
27
|
+
exports.buildHcDense = buildHcDense;
|
|
28
|
+
exports.generateHcDenseMoves = generateHcDenseMoves;
|
|
29
|
+
const center3_js_1 = require("./center3.js");
|
|
30
|
+
const moves_js_1 = require("../moves.js");
|
|
31
|
+
exports.HC_PDB_MOVES = center3_js_1.CENTER3_MOVES.slice(0, 17);
|
|
32
|
+
/** C(24,12) = 2,704,156. */
|
|
33
|
+
exports.HC_PDB_STATES = 2704156;
|
|
34
|
+
const CNK = (() => {
|
|
35
|
+
const table = [];
|
|
36
|
+
for (let n = 0; n <= 24; n++) {
|
|
37
|
+
table[n] = [];
|
|
38
|
+
for (let k = 0; k <= 12; k++) {
|
|
39
|
+
if (k === 0 || k === n)
|
|
40
|
+
table[n][k] = 1;
|
|
41
|
+
else if (k > n)
|
|
42
|
+
table[n][k] = 0;
|
|
43
|
+
else
|
|
44
|
+
table[n][k] = table[n - 1][k - 1] + table[n - 1][k];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return table;
|
|
48
|
+
})();
|
|
49
|
+
function halfClass(color) {
|
|
50
|
+
return (Math.floor(color / 3) ^ 1) & 1;
|
|
51
|
+
}
|
|
52
|
+
/** C(24,12) rank of a 24-bit mask with popcount 12 (bit i = position i holds 1). */
|
|
53
|
+
function hcRank(mask) {
|
|
54
|
+
let rank = 0;
|
|
55
|
+
let k = 1;
|
|
56
|
+
for (let i = 0; i < 24; i++) {
|
|
57
|
+
if (mask & (1 << i)) {
|
|
58
|
+
rank += CNK[i][k];
|
|
59
|
+
k++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return rank;
|
|
63
|
+
}
|
|
64
|
+
/** Inverse of hcRank: mask with popcount 12. */
|
|
65
|
+
function hcUnrank(rank) {
|
|
66
|
+
let mask = 0;
|
|
67
|
+
let r = rank;
|
|
68
|
+
for (let k = 12; k >= 1; k--) {
|
|
69
|
+
for (let v = 23; v >= 0; v--) {
|
|
70
|
+
const c = CNK[v][k];
|
|
71
|
+
if (c <= r) {
|
|
72
|
+
mask |= 1 << v;
|
|
73
|
+
r -= c;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return mask;
|
|
79
|
+
}
|
|
80
|
+
/** Encode center colors to the half-class coordinate. */
|
|
81
|
+
function encodeHcPdb(centers) {
|
|
82
|
+
let mask = 0;
|
|
83
|
+
for (let i = 0; i < 24; i++) {
|
|
84
|
+
if (halfClass(centers[i]) === 1)
|
|
85
|
+
mask |= 1 << i;
|
|
86
|
+
}
|
|
87
|
+
return hcRank(mask);
|
|
88
|
+
}
|
|
89
|
+
/** Position permutation maps for the 17 moves (next[i] = prev[map[i]]). */
|
|
90
|
+
function buildMovePositionMaps() {
|
|
91
|
+
const maps = new Int32Array(exports.HC_PDB_MOVES.length * 24);
|
|
92
|
+
for (let m = 0; m < exports.HC_PDB_MOVES.length; m++) {
|
|
93
|
+
const { face, turns } = (0, moves_js_1.parseMove)(exports.HC_PDB_MOVES[m]);
|
|
94
|
+
const effect = moves_js_1.FACE_MOVE_EFFECTS[face];
|
|
95
|
+
let pos = Array.from({ length: 24 }, (_, i) => i);
|
|
96
|
+
for (let t = 0; t < turns; t++) {
|
|
97
|
+
const next = new Array(24);
|
|
98
|
+
for (let i = 0; i < 24; i++)
|
|
99
|
+
next[i] = pos[effect.ctperm[i]];
|
|
100
|
+
pos = next;
|
|
101
|
+
}
|
|
102
|
+
for (let i = 0; i < 24; i++)
|
|
103
|
+
maps[m * 24 + i] = pos[i];
|
|
104
|
+
}
|
|
105
|
+
return maps;
|
|
106
|
+
}
|
|
107
|
+
let cachedMoveMaps = null;
|
|
108
|
+
function getHcPdbMoveMaps() {
|
|
109
|
+
if (!cachedMoveMaps)
|
|
110
|
+
cachedMoveMaps = buildMovePositionMaps();
|
|
111
|
+
return cachedMoveMaps;
|
|
112
|
+
}
|
|
113
|
+
/** Nibble-packed lookup (high nibble = odd index). */
|
|
114
|
+
function hcPdbDistance(packed, coordinate) {
|
|
115
|
+
const byte = packed[coordinate >> 1];
|
|
116
|
+
return (coordinate & 1) === 0 ? byte & 0x0f : byte >> 4;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* BFS from the solved half-class mask. Returns nibble-packed distances
|
|
120
|
+
* (0x0f = unreachable). ~2.7M states x 17 moves.
|
|
121
|
+
*/
|
|
122
|
+
function generateHcPdb(onProgress) {
|
|
123
|
+
const maps = getHcPdbMoveMaps();
|
|
124
|
+
const packed = new Uint8Array((exports.HC_PDB_STATES + 1) >> 1).fill(0xff);
|
|
125
|
+
const get = (c) => {
|
|
126
|
+
const b = packed[c >> 1];
|
|
127
|
+
return (c & 1) === 0 ? b & 0x0f : b >> 4;
|
|
128
|
+
};
|
|
129
|
+
const set = (c, d) => {
|
|
130
|
+
const i = c >> 1;
|
|
131
|
+
if ((c & 1) === 0)
|
|
132
|
+
packed[i] = (packed[i] & 0xf0) | (d & 0x0f);
|
|
133
|
+
else
|
|
134
|
+
packed[i] = (packed[i] & 0x0f) | ((d & 0x0f) << 4);
|
|
135
|
+
};
|
|
136
|
+
// Solved mask: U/R/F faces hold half-class 1.
|
|
137
|
+
let solvedMask = 0;
|
|
138
|
+
for (const i of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
|
|
139
|
+
solvedMask |= 1 << i;
|
|
140
|
+
const solved = hcRank(solvedMask);
|
|
141
|
+
if (solved !== 0)
|
|
142
|
+
throw new Error(`solved rank != 0 (${solved})`);
|
|
143
|
+
const queue = new Int32Array(exports.HC_PDB_STATES);
|
|
144
|
+
let head = 0;
|
|
145
|
+
let tail = 0;
|
|
146
|
+
set(0, 0);
|
|
147
|
+
queue[tail++] = 0;
|
|
148
|
+
while (head < tail) {
|
|
149
|
+
const coord = queue[head++];
|
|
150
|
+
const d = get(coord);
|
|
151
|
+
const nd = d + 1;
|
|
152
|
+
if (nd > 14)
|
|
153
|
+
continue; // nibble range; 0x0f stays "unknown" (admissible)
|
|
154
|
+
const mask = hcUnrank(coord);
|
|
155
|
+
for (let m = 0; m < exports.HC_PDB_MOVES.length; m++) {
|
|
156
|
+
const base = m * 24;
|
|
157
|
+
let nmask = 0;
|
|
158
|
+
for (let i = 0; i < 24; i++) {
|
|
159
|
+
if (mask & (1 << maps[base + i]))
|
|
160
|
+
nmask |= 1 << i;
|
|
161
|
+
}
|
|
162
|
+
const next = hcRank(nmask);
|
|
163
|
+
if (get(next) === 0x0f) {
|
|
164
|
+
set(next, nd);
|
|
165
|
+
queue[tail++] = next;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (onProgress && (head & 0x7ffff) === 0)
|
|
169
|
+
onProgress(head, exports.HC_PDB_STATES);
|
|
170
|
+
}
|
|
171
|
+
if (onProgress)
|
|
172
|
+
onProgress(tail, exports.HC_PDB_STATES);
|
|
173
|
+
return packed;
|
|
174
|
+
}
|
|
175
|
+
/** Number of reachable states (BFS orbit size). Fixed by the move set. */
|
|
176
|
+
exports.HC_REACHABLE = 58800;
|
|
177
|
+
/** Build the dense index + unpacked distances from nibble-packed BFS output. */
|
|
178
|
+
function buildHcDense(packed) {
|
|
179
|
+
const index = new Int32Array(exports.HC_PDB_STATES).fill(-1);
|
|
180
|
+
let count = 0;
|
|
181
|
+
for (let c = 0; c < exports.HC_PDB_STATES; c++) {
|
|
182
|
+
if (hcPdbDistance(packed, c) !== 0x0f)
|
|
183
|
+
index[c] = count++;
|
|
184
|
+
}
|
|
185
|
+
const distances = new Uint8Array(count).fill(0x0f);
|
|
186
|
+
for (let c = 0; c < exports.HC_PDB_STATES; c++) {
|
|
187
|
+
const di = index[c];
|
|
188
|
+
if (di >= 0)
|
|
189
|
+
distances[di] = hcPdbDistance(packed, c);
|
|
190
|
+
}
|
|
191
|
+
return { index, moves: new Int32Array(0), distances, reachableCount: count };
|
|
192
|
+
}
|
|
193
|
+
/** Dense transition table: for each reachable state and move, dense index (or -1). */
|
|
194
|
+
function generateHcDenseMoves(dense) {
|
|
195
|
+
const maps = getHcPdbMoveMaps();
|
|
196
|
+
const moves = new Int32Array(dense.reachableCount * exports.HC_PDB_MOVES.length).fill(-1);
|
|
197
|
+
for (let c = 0; c < exports.HC_PDB_STATES; c++) {
|
|
198
|
+
const di = dense.index[c];
|
|
199
|
+
if (di < 0)
|
|
200
|
+
continue;
|
|
201
|
+
const mask = hcUnrank(c);
|
|
202
|
+
for (let m = 0; m < exports.HC_PDB_MOVES.length; m++) {
|
|
203
|
+
const base = m * 24;
|
|
204
|
+
let nmask = 0;
|
|
205
|
+
for (let i = 0; i < 24; i++) {
|
|
206
|
+
if (mask & (1 << maps[base + i]))
|
|
207
|
+
nmask |= 1 << i;
|
|
208
|
+
}
|
|
209
|
+
moves[di * exports.HC_PDB_MOVES.length + m] = dense.index[hcRank(nmask)];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return moves;
|
|
213
|
+
}
|
|
@@ -13,6 +13,7 @@ const node_module_1 = require("node:module");
|
|
|
13
13
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
14
|
const node_crypto_1 = require("node:crypto");
|
|
15
15
|
const edge3_js_1 = require("./edge3.js");
|
|
16
|
+
const hc_pdb_js_1 = require("./hc-pdb.js");
|
|
16
17
|
const GENERATED_DIRECTORY = "puzzles/cube4/reduction/generated";
|
|
17
18
|
function resolveGeneratedAssetDirectory() {
|
|
18
19
|
const envDirectory = process.env.CUBINGCENTER_SCRAMBLER_TABLES_DIR;
|
|
@@ -65,17 +66,27 @@ function loadCenter1(assetDirectory) {
|
|
|
65
66
|
}
|
|
66
67
|
function loadCenter2(assetDirectory) {
|
|
67
68
|
const manifest = JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(assetDirectory, "center2-manifest.json"), "utf8"));
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
function unpackPruning(buffer) {
|
|
70
|
+
const pruning = new Uint8Array(450450);
|
|
71
|
+
for (let i = 0; i < 450450; i++) {
|
|
72
|
+
const byte = buffer[i >> 1];
|
|
73
|
+
pruning[i] = (i & 1) === 0 ? byte & 0x0f : byte >> 4;
|
|
74
|
+
}
|
|
75
|
+
return pruning;
|
|
73
76
|
}
|
|
74
|
-
|
|
77
|
+
const pruningBuffer = readChecked(node_path_1.default.join(assetDirectory, manifest.pruningTable.file), manifest.pruningTable.checksum);
|
|
78
|
+
const tables = {
|
|
75
79
|
ctMove: readInt32(readChecked(node_path_1.default.join(assetDirectory, manifest.ctMove.file), manifest.ctMove.checksum)),
|
|
76
80
|
rlMove: readInt32(readChecked(node_path_1.default.join(assetDirectory, manifest.rlMove.file), manifest.rlMove.checksum)),
|
|
77
|
-
pruning
|
|
81
|
+
pruning: unpackPruning(pruningBuffer)
|
|
78
82
|
};
|
|
83
|
+
// Tolerates older assets without the wide table (wide searches throw
|
|
84
|
+
// a clear error only when actually requested).
|
|
85
|
+
if (manifest.pruningWideTable) {
|
|
86
|
+
const wideBuffer = readChecked(node_path_1.default.join(assetDirectory, manifest.pruningWideTable.file), manifest.pruningWideTable.checksum);
|
|
87
|
+
tables.pruningWide = unpackPruning(wideBuffer);
|
|
88
|
+
}
|
|
89
|
+
return tables;
|
|
79
90
|
}
|
|
80
91
|
function loadCenter3(assetDirectory) {
|
|
81
92
|
const manifest = JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(assetDirectory, "center3-manifest.json"), "utf8"));
|
|
@@ -86,19 +97,48 @@ function loadCenter3(assetDirectory) {
|
|
|
86
97
|
}
|
|
87
98
|
function loadEdge3(assetDirectory) {
|
|
88
99
|
const manifest = JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(assetDirectory, "edge3-manifest.json"), "utf8"));
|
|
100
|
+
// Keep the nibble-packed distances as-is (15.5MB instead of 31MB): every
|
|
101
|
+
// reader (phase3 getPrun, solve.ts, edge3DistanceLookup) handles both
|
|
102
|
+
// formats, and the smaller working set halves edge-table DRAM traffic.
|
|
89
103
|
const distances = new Uint8Array(readChecked(node_path_1.default.join(assetDirectory, manifest.distances.file), manifest.distances.checksum));
|
|
90
104
|
return { distances, distanceOfEdge: (0, edge3_js_1.edge3DistanceLookup)(distances) };
|
|
91
105
|
}
|
|
106
|
+
function loadHc(assetDirectory) {
|
|
107
|
+
const manifestPath = node_path_1.default.join(assetDirectory, "hc-manifest.json");
|
|
108
|
+
if (!(0, node_fs_1.existsSync)(manifestPath))
|
|
109
|
+
return undefined;
|
|
110
|
+
const manifest = JSON.parse((0, node_fs_1.readFileSync)(manifestPath, "utf8"));
|
|
111
|
+
const packed = new Uint8Array(readChecked(node_path_1.default.join(assetDirectory, manifest.distances.file), manifest.distances.checksum));
|
|
112
|
+
const dense = (0, hc_pdb_js_1.buildHcDense)(packed);
|
|
113
|
+
if (manifest.moveTable) {
|
|
114
|
+
const moveBuffer = readChecked(node_path_1.default.join(assetDirectory, manifest.moveTable.file), manifest.moveTable.checksum);
|
|
115
|
+
dense.moves = new Int32Array(moveBuffer.buffer.slice(moveBuffer.byteOffset, moveBuffer.byteOffset + moveBuffer.byteLength));
|
|
116
|
+
}
|
|
117
|
+
return dense;
|
|
118
|
+
}
|
|
119
|
+
function loadC3Pair(assetDirectory) {
|
|
120
|
+
const filePath = node_path_1.default.join(assetDirectory, "c3_pair_dist.bin");
|
|
121
|
+
if (!(0, node_fs_1.existsSync)(filePath))
|
|
122
|
+
return undefined;
|
|
123
|
+
return new Uint8Array((0, node_fs_1.readFileSync)(filePath));
|
|
124
|
+
}
|
|
92
125
|
/** Load all cube4 reduction tables (throws if the generated assets are missing). */
|
|
93
126
|
function loadCube4ReductionTables() {
|
|
94
127
|
const assetDirectory = resolveGeneratedAssetDirectory();
|
|
95
128
|
if (!(0, node_fs_1.existsSync)(node_path_1.default.join(assetDirectory, "center1-manifest.json"))) {
|
|
96
129
|
throw new Error("Cube4 reduction tables not generated — run pnpm cube4:center1:tables etc.");
|
|
97
130
|
}
|
|
98
|
-
|
|
131
|
+
const tables = {
|
|
99
132
|
center1: loadCenter1(assetDirectory),
|
|
100
133
|
center2: loadCenter2(assetDirectory),
|
|
101
134
|
center3: loadCenter3(assetDirectory),
|
|
102
135
|
edge3: loadEdge3(assetDirectory)
|
|
103
136
|
};
|
|
137
|
+
const hc = loadHc(assetDirectory);
|
|
138
|
+
if (hc)
|
|
139
|
+
tables.hc = hc;
|
|
140
|
+
const c3Pair = loadC3Pair(assetDirectory);
|
|
141
|
+
if (c3Pair)
|
|
142
|
+
tables.c3PairDist = c3Pair;
|
|
143
|
+
return tables;
|
|
104
144
|
}
|
|
@@ -116,12 +116,12 @@ function applyPairingMoveToArray(arr24, move) {
|
|
|
116
116
|
* and preserved by the phase-3 move set (verified).
|
|
117
117
|
*/
|
|
118
118
|
function hasPairingTransversal(wp) {
|
|
119
|
-
|
|
120
|
-
for (
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
119
|
+
let mask = 0;
|
|
120
|
+
for (let i = 0; i < 12; i++) {
|
|
121
|
+
const bit = 1 << (wp[exports.PAIRING_SECOND_HALVES[i]] >> 1);
|
|
122
|
+
if ((mask & bit) !== 0)
|
|
123
123
|
return false;
|
|
124
|
-
|
|
124
|
+
mask |= bit;
|
|
125
125
|
}
|
|
126
126
|
return true;
|
|
127
127
|
}
|