@cubingcenter/scrambler 0.5.3 → 0.6.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 +24 -9
- package/dist/cli/index.js +0 -0
- package/dist/core/api.d.ts.map +1 -1
- package/dist/core/api.js +11 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.d.ts +4 -2
- package/dist/puzzles/cube4/index.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.js +3 -1
- package/dist/puzzles/cube4/random-state.d.ts +16 -0
- package/dist/puzzles/cube4/random-state.d.ts.map +1 -0
- package/dist/puzzles/cube4/random-state.js +76 -0
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts +18 -0
- package/dist/puzzles/cube4/reduction/browser-loader.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/browser-loader.js +95 -0
- package/dist/puzzles/cube4/reduction/center1.d.ts +65 -0
- package/dist/puzzles/cube4/reduction/center1.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/center1.js +245 -0
- package/dist/puzzles/cube4/reduction/center2.d.ts +91 -0
- package/dist/puzzles/cube4/reduction/center2.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/center2.js +449 -0
- package/dist/puzzles/cube4/reduction/center3.d.ts +47 -0
- package/dist/puzzles/cube4/reduction/center3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/center3.js +278 -0
- package/dist/puzzles/cube4/reduction/edge3.d.ts +100 -0
- package/dist/puzzles/cube4/reduction/edge3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/edge3.js +511 -0
- package/dist/puzzles/cube4/reduction/generated/center1-distance.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/center1-manifest.json +46 -0
- package/dist/puzzles/cube4/reduction/generated/center1-move-maps.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center2-ct-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center2-manifest.json +87 -0
- package/dist/puzzles/cube4/reduction/generated/center2-pruning.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/center2-rl-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center3-manifest.json +40 -0
- package/dist/puzzles/cube4/reduction/generated/center3-move.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/center3-pruning.bin +0 -0
- package/dist/puzzles/cube4/reduction/generated/edge3-distances.bin +1 -0
- package/dist/puzzles/cube4/reduction/generated/edge3-manifest.json +12 -0
- package/dist/puzzles/cube4/reduction/geometry.d.ts +33 -0
- package/dist/puzzles/cube4/reduction/geometry.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/geometry.js +302 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts +17 -0
- package/dist/puzzles/cube4/reduction/node-loader.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/node-loader.js +98 -0
- package/dist/puzzles/cube4/reduction/pairing-coordinate.d.ts +130 -0
- package/dist/puzzles/cube4/reduction/pairing-coordinate.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/pairing-coordinate.js +281 -0
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts +42 -0
- package/dist/puzzles/cube4/reduction/phase3-search.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/phase3-search.js +133 -0
- package/dist/puzzles/cube4/reduction/phase3.d.ts +34 -0
- package/dist/puzzles/cube4/reduction/phase3.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/phase3.js +83 -0
- package/dist/puzzles/cube4/reduction/phase4.d.ts +35 -0
- package/dist/puzzles/cube4/reduction/phase4.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/phase4.js +82 -0
- package/dist/puzzles/cube4/reduction/solve.d.ts +31 -0
- package/dist/puzzles/cube4/reduction/solve.d.ts.map +1 -0
- package/dist/puzzles/cube4/reduction/solve.js +311 -0
- package/dist/puzzles/cube4/scrambler.d.ts +9 -1
- package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube4/scrambler.js +123 -81
- package/dist/puzzles/cube4/types.d.ts +6 -0
- package/dist/puzzles/cube4/types.d.ts.map +1 -1
- package/dist/puzzles/cube4/validation.d.ts +6 -0
- package/dist/puzzles/cube4/validation.d.ts.map +1 -0
- package/dist/puzzles/cube4/validation.js +91 -0
- package/dist/puzzles/fto/coordinates.d.ts +53 -0
- package/dist/puzzles/fto/coordinates.d.ts.map +1 -0
- package/dist/puzzles/fto/coordinates.js +228 -0
- package/dist/puzzles/fto/facelets.d.ts +6 -0
- package/dist/puzzles/fto/facelets.d.ts.map +1 -0
- package/dist/puzzles/fto/facelets.js +99 -0
- package/dist/puzzles/fto/index.d.ts +12 -0
- package/dist/puzzles/fto/index.d.ts.map +1 -0
- package/dist/puzzles/fto/index.js +13 -0
- package/dist/puzzles/fto/moves.d.ts +12 -0
- package/dist/puzzles/fto/moves.d.ts.map +1 -0
- package/dist/puzzles/fto/moves.js +115 -0
- package/dist/puzzles/fto/random-state.d.ts +17 -0
- package/dist/puzzles/fto/random-state.d.ts.map +1 -0
- package/dist/puzzles/fto/random-state.js +40 -0
- package/dist/puzzles/fto/scrambler.d.ts +6 -0
- package/dist/puzzles/fto/scrambler.d.ts.map +1 -0
- package/dist/puzzles/fto/scrambler.js +49 -0
- package/dist/puzzles/fto/solver/engine.d.ts +18 -0
- package/dist/puzzles/fto/solver/engine.d.ts.map +1 -0
- package/dist/puzzles/fto/solver/engine.js +1168 -0
- package/dist/puzzles/fto/solver/index.d.ts +2 -0
- package/dist/puzzles/fto/solver/index.d.ts.map +1 -0
- package/dist/puzzles/fto/solver/index.js +1 -0
- package/dist/puzzles/fto/state.d.ts +16 -0
- package/dist/puzzles/fto/state.d.ts.map +1 -0
- package/dist/puzzles/fto/state.js +61 -0
- package/dist/puzzles/fto/types.d.ts +32 -0
- package/dist/puzzles/fto/types.d.ts.map +1 -0
- package/dist/puzzles/fto/types.js +46 -0
- package/dist/puzzles/fto/validation.d.ts +19 -0
- package/dist/puzzles/fto/validation.d.ts.map +1 -0
- package/dist/puzzles/fto/validation.js +143 -0
- package/dist/puzzles/index.d.ts +2 -0
- package/dist/puzzles/index.d.ts.map +1 -1
- package/dist/puzzles/index.js +6 -0
- package/dist/puzzles/skewb/index.d.ts +1 -1
- package/dist/puzzles/skewb/index.d.ts.map +1 -1
- package/dist/puzzles/skewb/index.js +1 -1
- package/dist/puzzles/skewb/random-state.d.ts.map +1 -1
- package/dist/puzzles/skewb/random-state.js +4 -1
- package/dist/puzzles/sq1/facelets.d.ts +12 -0
- package/dist/puzzles/sq1/facelets.d.ts.map +1 -0
- package/dist/puzzles/sq1/facelets.js +26 -0
- package/dist/puzzles/sq1/index.d.ts +10 -0
- package/dist/puzzles/sq1/index.d.ts.map +1 -0
- package/dist/puzzles/sq1/index.js +11 -0
- package/dist/puzzles/sq1/moves.d.ts +55 -0
- package/dist/puzzles/sq1/moves.d.ts.map +1 -0
- package/dist/puzzles/sq1/moves.js +220 -0
- package/dist/puzzles/sq1/random-state.d.ts +6 -0
- package/dist/puzzles/sq1/random-state.d.ts.map +1 -0
- package/dist/puzzles/sq1/random-state.js +49 -0
- package/dist/puzzles/sq1/scrambler.d.ts +10 -0
- package/dist/puzzles/sq1/scrambler.d.ts.map +1 -0
- package/dist/puzzles/sq1/scrambler.js +90 -0
- package/dist/puzzles/sq1/solver/browser-loader.d.ts +5 -0
- package/dist/puzzles/sq1/solver/browser-loader.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/browser-loader.js +92 -0
- package/dist/puzzles/sq1/solver/full-cube.d.ts +53 -0
- package/dist/puzzles/sq1/solver/full-cube.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/full-cube.js +281 -0
- package/dist/puzzles/sq1/solver/generated/manifest.json +50 -0
- package/dist/puzzles/sq1/solver/generated/shape-bottom-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-idx.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-prun.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-top-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/shape-twist-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-bottom-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-prun.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-top-move.bin +0 -0
- package/dist/puzzles/sq1/solver/generated/square-twist-move.bin +0 -0
- package/dist/puzzles/sq1/solver/index.d.ts +5 -0
- package/dist/puzzles/sq1/solver/index.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/index.js +4 -0
- package/dist/puzzles/sq1/solver/node-loader.d.ts +4 -0
- package/dist/puzzles/sq1/solver/node-loader.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/node-loader.js +113 -0
- package/dist/puzzles/sq1/solver/search.d.ts +27 -0
- package/dist/puzzles/sq1/solver/search.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/search.js +225 -0
- package/dist/puzzles/sq1/solver/shape.d.ts +22 -0
- package/dist/puzzles/sq1/solver/shape.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/shape.js +185 -0
- package/dist/puzzles/sq1/solver/square.d.ts +10 -0
- package/dist/puzzles/sq1/solver/square.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/square.js +90 -0
- package/dist/puzzles/sq1/solver/table-metadata.d.ts +48 -0
- package/dist/puzzles/sq1/solver/table-metadata.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/table-metadata.js +47 -0
- package/dist/puzzles/sq1/solver/tables.d.ts +17 -0
- package/dist/puzzles/sq1/solver/tables.d.ts.map +1 -0
- package/dist/puzzles/sq1/solver/tables.js +66 -0
- package/dist/puzzles/sq1/state.d.ts +10 -0
- package/dist/puzzles/sq1/state.d.ts.map +1 -0
- package/dist/puzzles/sq1/state.js +74 -0
- package/dist/puzzles/sq1/types.d.ts +32 -0
- package/dist/puzzles/sq1/types.d.ts.map +1 -0
- package/dist/puzzles/sq1/types.js +1 -0
- package/dist/puzzles/sq1/validation.d.ts +7 -0
- package/dist/puzzles/sq1/validation.d.ts.map +1 -0
- package/dist/puzzles/sq1/validation.js +64 -0
- package/dist/random/prng.d.ts.map +1 -1
- package/dist/random/prng.js +9 -4
- package/dist-cjs/core/api.js +11 -1
- package/dist-cjs/puzzles/cube4/index.js +11 -4
- package/dist-cjs/puzzles/cube4/random-state.js +79 -0
- package/dist-cjs/puzzles/cube4/reduction/browser-loader.js +100 -0
- package/dist-cjs/puzzles/cube4/reduction/center1.js +258 -0
- package/dist-cjs/puzzles/cube4/reduction/center2.js +462 -0
- package/dist-cjs/puzzles/cube4/reduction/center3.js +284 -0
- package/dist-cjs/puzzles/cube4/reduction/edge3.js +522 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center1-distance.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center1-manifest.json +46 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center1-move-maps.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-ct-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-manifest.json +87 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-pruning.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center2-rl-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center3-manifest.json +40 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center3-move.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/center3-pruning.bin +0 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/edge3-distances.bin +1 -0
- package/dist-cjs/puzzles/cube4/reduction/generated/edge3-manifest.json +12 -0
- package/dist-cjs/puzzles/cube4/reduction/geometry.js +308 -0
- package/dist-cjs/puzzles/cube4/reduction/node-loader.js +104 -0
- package/dist-cjs/puzzles/cube4/reduction/pairing-coordinate.js +294 -0
- package/dist-cjs/puzzles/cube4/reduction/phase3-search.js +138 -0
- package/dist-cjs/puzzles/cube4/reduction/phase3.js +86 -0
- package/dist-cjs/puzzles/cube4/reduction/phase4.js +87 -0
- package/dist-cjs/puzzles/cube4/reduction/solve.js +314 -0
- package/dist-cjs/puzzles/cube4/scrambler.js +122 -79
- package/dist-cjs/puzzles/cube4/validation.js +97 -0
- package/dist-cjs/puzzles/fto/coordinates.js +240 -0
- package/dist-cjs/puzzles/fto/facelets.js +104 -0
- package/dist-cjs/puzzles/fto/index.js +68 -0
- package/dist-cjs/puzzles/fto/moves.js +126 -0
- package/dist-cjs/puzzles/fto/random-state.js +43 -0
- package/dist-cjs/puzzles/fto/scrambler.js +53 -0
- package/dist-cjs/puzzles/fto/solver/engine.js +1175 -0
- package/dist-cjs/puzzles/fto/solver/index.js +9 -0
- package/dist-cjs/puzzles/fto/state.js +69 -0
- package/dist-cjs/puzzles/fto/types.js +49 -0
- package/dist-cjs/puzzles/fto/validation.js +147 -0
- package/dist-cjs/puzzles/index.js +7 -1
- package/dist-cjs/puzzles/skewb/index.js +2 -1
- package/dist-cjs/puzzles/skewb/random-state.js +4 -1
- package/dist-cjs/puzzles/sq1/facelets.js +30 -0
- package/dist-cjs/puzzles/sq1/index.js +52 -0
- package/dist-cjs/puzzles/sq1/moves.js +234 -0
- package/dist-cjs/puzzles/sq1/random-state.js +52 -0
- package/dist-cjs/puzzles/sq1/scrambler.js +95 -0
- package/dist-cjs/puzzles/sq1/solver/browser-loader.js +97 -0
- package/dist-cjs/puzzles/sq1/solver/full-cube.js +289 -0
- package/dist-cjs/puzzles/sq1/solver/generated/manifest.json +50 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-bottom-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-idx.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-prun.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-top-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/shape-twist-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-bottom-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-prun.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-top-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/generated/square-twist-move.bin +0 -0
- package/dist-cjs/puzzles/sq1/solver/index.js +18 -0
- package/dist-cjs/puzzles/sq1/solver/node-loader.js +120 -0
- package/dist-cjs/puzzles/sq1/solver/search.js +229 -0
- package/dist-cjs/puzzles/sq1/solver/shape.js +191 -0
- package/dist-cjs/puzzles/sq1/solver/square.js +93 -0
- package/dist-cjs/puzzles/sq1/solver/table-metadata.js +50 -0
- package/dist-cjs/puzzles/sq1/solver/tables.js +106 -0
- package/dist-cjs/puzzles/sq1/state.js +81 -0
- package/dist-cjs/puzzles/sq1/types.js +2 -0
- package/dist-cjs/puzzles/sq1/validation.js +68 -0
- package/dist-cjs/random/prng.js +9 -4
- package/package.json +43 -14
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Center2 (phase 2 of the 4x4 reduction solver): from the phase-1 output
|
|
3
|
+
* (axis colors on a face-pair), reach the phase-2 goal: the U/D/F/B faces
|
|
4
|
+
* uniform in color-class and the R/L faces in one of the 6 goal patterns.
|
|
5
|
+
*
|
|
6
|
+
* Ported from the reference's `Center2` class, adapted to this repo's layout:
|
|
7
|
+
* - ct part: the 16 positions of the U, D, F, B faces, storing color % 3
|
|
8
|
+
* (the color-class), ranked as C(15,8) vs ct[15] = 6,435 states;
|
|
9
|
+
* - rl part: the 8 positions of the R, L faces, storing the actual colors,
|
|
10
|
+
* ranked as C(7,4) vs rl[7] × 2 + wing-parity = 70 states;
|
|
11
|
+
* - full coordinate: ct × 70 = 450,450;
|
|
12
|
+
* - goal: ct == 0 and rl in the 6 reference goal patterns (even parity);
|
|
13
|
+
* - the 28-move set keeps the ct and rl position sets separate, so the move
|
|
14
|
+
* tables factor: ctmv (6,435×28) and rlmv (70×28);
|
|
15
|
+
* - the search explores the first 23 moves (face moves + Uw2/Rw/Rw2/Rw').
|
|
16
|
+
*
|
|
17
|
+
* The phase-1 → phase-2 bridge (alignment + encode) is in `reduction.ts`.
|
|
18
|
+
*/
|
|
19
|
+
import { FACE_MOVE_EFFECTS, applyCube4Algorithm, parseMove } from "../moves.js";
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Constants
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/** The phase-2 move set (28 real moves + the reference's trailing no-op). */
|
|
24
|
+
export const CENTER2_MOVES = [
|
|
25
|
+
"U", "U2", "U'", "R", "R2", "R'", "F", "F2", "F'", "D", "D2", "D'",
|
|
26
|
+
"L", "L2", "L'", "B", "B2", "B'",
|
|
27
|
+
"Uw2", "Rw", "Rw2", "Rw'", "Fw2", "Dw2", "Lw", "Lw2", "Lw'", "Bw2"
|
|
28
|
+
];
|
|
29
|
+
/** The search's exploration set (the first 23 of CENTER2_MOVES). */
|
|
30
|
+
export const CENTER2_SEARCH_MOVES = CENTER2_MOVES.slice(0, 23);
|
|
31
|
+
/** The 6 reference goal rl patterns (full 70-space values, even parity). */
|
|
32
|
+
export const CENTER2_GOAL_RL = [0, 18, 28, 46, 54, 56];
|
|
33
|
+
export const CENTER2_CT_STATES = 6435;
|
|
34
|
+
export const CENTER2_RL_STATES = 70;
|
|
35
|
+
export const CENTER2_STATES = CENTER2_CT_STATES * CENTER2_RL_STATES;
|
|
36
|
+
// ct positions: U(0-3), D(12-15), F(8-11), B(20-23) — the reference's face
|
|
37
|
+
// order {U, D, F, B}, in this repo's face-major numbering.
|
|
38
|
+
const CT_POS = [0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11, 20, 21, 22, 23];
|
|
39
|
+
// rl positions: R(4-7), L(16-19).
|
|
40
|
+
const RL_POS = [4, 5, 6, 7, 16, 17, 18, 19];
|
|
41
|
+
/** Wide quarter turns flip the wing permutation parity. */
|
|
42
|
+
const PARITY_FLIP = new Set(["Rw", "Rw'", "Lw", "Lw'"]);
|
|
43
|
+
// Cnk table up to n=24.
|
|
44
|
+
const CNK = (() => {
|
|
45
|
+
const table = [];
|
|
46
|
+
for (let n = 0; n <= 24; n++) {
|
|
47
|
+
table[n] = [];
|
|
48
|
+
for (let k = 0; k <= 24; k++) {
|
|
49
|
+
if (k === 0 || k === n)
|
|
50
|
+
table[n][k] = 1;
|
|
51
|
+
else if (k > n)
|
|
52
|
+
table[n][k] = 0;
|
|
53
|
+
else
|
|
54
|
+
table[n][k] = table[n - 1][k - 1] + table[n - 1][k];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return table;
|
|
58
|
+
})();
|
|
59
|
+
function rankVsLast(values, size, ones) {
|
|
60
|
+
const last = values[size - 1];
|
|
61
|
+
let idx = 0;
|
|
62
|
+
let r = ones;
|
|
63
|
+
for (let i = size - 2; i >= 0; i--) {
|
|
64
|
+
if (values[i] !== last)
|
|
65
|
+
idx += CNK[i][r--];
|
|
66
|
+
}
|
|
67
|
+
return idx;
|
|
68
|
+
}
|
|
69
|
+
export function wingPermutationParity(wp) {
|
|
70
|
+
let parity = 0;
|
|
71
|
+
const seen = new Array(24).fill(false);
|
|
72
|
+
for (let start = 0; start < 24; start++) {
|
|
73
|
+
if (seen[start] || wp[start] === start)
|
|
74
|
+
continue;
|
|
75
|
+
let length = 0;
|
|
76
|
+
let current = start;
|
|
77
|
+
while (!seen[current]) {
|
|
78
|
+
seen[current] = true;
|
|
79
|
+
current = wp[current];
|
|
80
|
+
length++;
|
|
81
|
+
}
|
|
82
|
+
parity ^= (length - 1) & 1;
|
|
83
|
+
}
|
|
84
|
+
return parity;
|
|
85
|
+
}
|
|
86
|
+
/** Encode a full 4x4 state to the (ct, rl) coordinate (0..450,449). */
|
|
87
|
+
export function encodeCenter2(state) {
|
|
88
|
+
const ct = new Uint8Array(16);
|
|
89
|
+
const rl = new Uint8Array(8);
|
|
90
|
+
for (let i = 0; i < 16; i++)
|
|
91
|
+
ct[i] = state.centers[CT_POS[i]] % 3;
|
|
92
|
+
for (let i = 0; i < 8; i++)
|
|
93
|
+
rl[i] = state.centers[RL_POS[i]];
|
|
94
|
+
const ctRank = rankVsLast(ct, 16, 8);
|
|
95
|
+
const rlRank = rankVsLast(rl, 8, 4) * 2 + wingPermutationParity(state.wp);
|
|
96
|
+
return { ct: ctRank, rl: rlRank };
|
|
97
|
+
}
|
|
98
|
+
export function isCenter2Goal(ct, rl) {
|
|
99
|
+
return ct === 0 && CENTER2_GOAL_RL.includes(rl);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The phase-2 coordinate is only valid for states where exactly 8 of the
|
|
103
|
+
* first 15 ct entries differ from ct[15] and exactly 4 of the first 7 rl
|
|
104
|
+
* entries differ from rl[7]. Phase-1 outputs don't always satisfy this; the
|
|
105
|
+
* phase-1 → phase-2 bridge applies a short alignment sequence (0-2 moves)
|
|
106
|
+
* that re-categorizes the axis colors onto the R/L face-pair, which is
|
|
107
|
+
* always invariant (verified over random states).
|
|
108
|
+
*/
|
|
109
|
+
const ALIGNMENT_CANDIDATES = [
|
|
110
|
+
[],
|
|
111
|
+
["Fw", "Bw'"],
|
|
112
|
+
["Uw", "Dw'"]
|
|
113
|
+
];
|
|
114
|
+
function center2InvariantDiffs(centers) {
|
|
115
|
+
let ctDiff = 0;
|
|
116
|
+
let rlDiff = 0;
|
|
117
|
+
for (let i = 0; i < 15; i++) {
|
|
118
|
+
if (centers[CT_POS[i]] % 3 !== centers[CT_POS[15]] % 3)
|
|
119
|
+
ctDiff++;
|
|
120
|
+
}
|
|
121
|
+
for (let i = 0; i < 7; i++) {
|
|
122
|
+
if (centers[RL_POS[i]] !== centers[RL_POS[7]])
|
|
123
|
+
rlDiff++;
|
|
124
|
+
}
|
|
125
|
+
return { ctDiff, rlDiff };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Phase-1 → phase-2 bridge: apply the shortest alignment candidate that
|
|
129
|
+
* makes the state coordinate-invariant, then encode.
|
|
130
|
+
*/
|
|
131
|
+
export function center2Bridge(state) {
|
|
132
|
+
for (const alignment of ALIGNMENT_CANDIDATES) {
|
|
133
|
+
const aligned = alignment.length === 0
|
|
134
|
+
? state
|
|
135
|
+
: applyCube4Algorithm(state, alignment);
|
|
136
|
+
const { ctDiff, rlDiff } = center2InvariantDiffs(aligned.centers);
|
|
137
|
+
if (ctDiff === 8 && rlDiff === 4) {
|
|
138
|
+
return {
|
|
139
|
+
alignment: [...alignment],
|
|
140
|
+
state: aligned,
|
|
141
|
+
encoded: encodeCenter2(aligned)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
// Move tables
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
function buildMovePositionMaps() {
|
|
151
|
+
const maps = new Int32Array(CENTER2_MOVES.length * 24);
|
|
152
|
+
for (let m = 0; m < CENTER2_MOVES.length; m++) {
|
|
153
|
+
const { face, turns } = parseMove(CENTER2_MOVES[m]);
|
|
154
|
+
const effect = FACE_MOVE_EFFECTS[face];
|
|
155
|
+
let pos = Array.from({ length: 24 }, (_, i) => i);
|
|
156
|
+
for (let t = 0; t < turns; t++) {
|
|
157
|
+
const next = new Array(24);
|
|
158
|
+
for (let i = 0; i < 24; i++)
|
|
159
|
+
next[i] = pos[effect.ctperm[i]];
|
|
160
|
+
pos = next;
|
|
161
|
+
}
|
|
162
|
+
for (let i = 0; i < 24; i++)
|
|
163
|
+
maps[m * 24 + i] = pos[i];
|
|
164
|
+
}
|
|
165
|
+
return maps;
|
|
166
|
+
}
|
|
167
|
+
function unrankVsLast(idx, size, ones) {
|
|
168
|
+
const values = new Uint8Array(size);
|
|
169
|
+
let r = ones;
|
|
170
|
+
for (let i = size - 2; i >= 0; i--) {
|
|
171
|
+
if (idx >= CNK[i][r]) {
|
|
172
|
+
idx -= CNK[i][r];
|
|
173
|
+
r--;
|
|
174
|
+
values[i] = 1;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return values;
|
|
178
|
+
}
|
|
179
|
+
export function generateCenter2Tables() {
|
|
180
|
+
const moveMaps = buildMovePositionMaps();
|
|
181
|
+
const ctMove = new Int32Array(CENTER2_CT_STATES * CENTER2_MOVES.length);
|
|
182
|
+
const rlMove = new Int32Array(CENTER2_RL_STATES * CENTER2_MOVES.length);
|
|
183
|
+
// canonical full arrangements: ct classes {0,1} (ct[15]=0), rl colors {0,1} (rl[7]=0)
|
|
184
|
+
const full = new Uint8Array(24);
|
|
185
|
+
const moved = new Uint8Array(24);
|
|
186
|
+
for (let ctRank = 0; ctRank < CENTER2_CT_STATES; ctRank++) {
|
|
187
|
+
const pattern = unrankVsLast(ctRank, 16, 8);
|
|
188
|
+
for (let i = 0; i < 24; i++)
|
|
189
|
+
full[i] = 0;
|
|
190
|
+
for (let i = 0; i < 16; i++) {
|
|
191
|
+
if (pattern[i] === 1)
|
|
192
|
+
full[CT_POS[i]] = 1;
|
|
193
|
+
}
|
|
194
|
+
for (let m = 0; m < CENTER2_MOVES.length; m++) {
|
|
195
|
+
const map = moveMaps;
|
|
196
|
+
for (let i = 0; i < 24; i++)
|
|
197
|
+
moved[i] = full[map[m * 24 + i]];
|
|
198
|
+
const ct = new Uint8Array(16);
|
|
199
|
+
for (let i = 0; i < 16; i++)
|
|
200
|
+
ct[i] = moved[CT_POS[i]] % 3;
|
|
201
|
+
ctMove[ctRank * CENTER2_MOVES.length + m] = rankVsLast(ct, 16, 8);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (let rlRankBase = 0; rlRankBase < 35; rlRankBase++) {
|
|
205
|
+
for (const parity of [0, 1]) {
|
|
206
|
+
const rlRank = rlRankBase * 2 + parity;
|
|
207
|
+
const pattern = unrankVsLast(rlRankBase, 8, 4);
|
|
208
|
+
for (let i = 0; i < 24; i++)
|
|
209
|
+
full[i] = 0;
|
|
210
|
+
for (let i = 0; i < 8; i++) {
|
|
211
|
+
if (pattern[i] === 1)
|
|
212
|
+
full[RL_POS[i]] = 1;
|
|
213
|
+
}
|
|
214
|
+
for (let m = 0; m < CENTER2_MOVES.length; m++) {
|
|
215
|
+
const map = moveMaps;
|
|
216
|
+
for (let i = 0; i < 24; i++)
|
|
217
|
+
moved[i] = full[map[m * 24 + i]];
|
|
218
|
+
const rl = new Uint8Array(8);
|
|
219
|
+
for (let i = 0; i < 8; i++)
|
|
220
|
+
rl[i] = moved[RL_POS[i]];
|
|
221
|
+
const nextParity = (parity ^ (PARITY_FLIP.has(CENTER2_MOVES[m]) ? 1 : 0));
|
|
222
|
+
rlMove[rlRank * CENTER2_MOVES.length + m] = rankVsLast(rl, 8, 4) * 2 + nextParity;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// pruning BFS from the 6 goal states, with the 23 exploration moves
|
|
227
|
+
const pruning = new Uint8Array(CENTER2_STATES).fill(0xff);
|
|
228
|
+
const queue = [];
|
|
229
|
+
for (const rl of CENTER2_GOAL_RL) {
|
|
230
|
+
pruning[rl] = 0; // ct == 0 → index == rl
|
|
231
|
+
queue.push(rl);
|
|
232
|
+
}
|
|
233
|
+
let head = 0;
|
|
234
|
+
while (head < queue.length) {
|
|
235
|
+
const idx = queue[head++];
|
|
236
|
+
const ct = Math.floor(idx / CENTER2_RL_STATES);
|
|
237
|
+
const rl = idx % CENTER2_RL_STATES;
|
|
238
|
+
const d = pruning[idx];
|
|
239
|
+
for (let m = 0; m < CENTER2_SEARCH_MOVES.length; m++) {
|
|
240
|
+
const nextCt = ctMove[ct * CENTER2_MOVES.length + m];
|
|
241
|
+
const nextRl = rlMove[rl * CENTER2_MOVES.length + m];
|
|
242
|
+
const next = nextCt * CENTER2_RL_STATES + nextRl;
|
|
243
|
+
if (pruning[next] === 0xff) {
|
|
244
|
+
pruning[next] = d + 1;
|
|
245
|
+
queue.push(next);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return { ctMove, rlMove, pruning };
|
|
250
|
+
}
|
|
251
|
+
// The reference's cancellation rule (ckmv over move2std): skip the same base
|
|
252
|
+
// move, or the same axis-class when the previous move's standard index is
|
|
253
|
+
// larger than the current's.
|
|
254
|
+
const STANDARD_ORDER = [
|
|
255
|
+
"U", "U2", "U'", "R", "R2", "R'", "F", "F2", "F'", "D", "D2", "D'",
|
|
256
|
+
"L", "L2", "L'", "B", "B2", "B'",
|
|
257
|
+
"Uw", "Uw2", "Uw'", "Rw", "Rw2", "Rw'", "Fw", "Fw2", "Fw'",
|
|
258
|
+
"Dw", "Dw2", "Dw'", "Lw", "Lw2", "Lw'", "Bw", "Bw2", "Bw'"
|
|
259
|
+
];
|
|
260
|
+
const STD_INDEX = new Map(STANDARD_ORDER.map((m, i) => [m, i]));
|
|
261
|
+
function baseOf(move) {
|
|
262
|
+
return move.replace(/[2']$/, "");
|
|
263
|
+
}
|
|
264
|
+
function axisClass(base) {
|
|
265
|
+
return { U: 0, D: 0, R: 1, L: 1, F: 2, B: 2 }[base];
|
|
266
|
+
}
|
|
267
|
+
function isCancelled(previous, current) {
|
|
268
|
+
const pb = baseOf(previous);
|
|
269
|
+
const cb = baseOf(current);
|
|
270
|
+
if (pb === cb)
|
|
271
|
+
return true;
|
|
272
|
+
if (axisClass(pb) === axisClass(cb)) {
|
|
273
|
+
return STD_INDEX.get(previous) > STD_INDEX.get(current);
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
export function solveCenter2(startCt, startRl, tables, maxLength = 40) {
|
|
278
|
+
const solutions = solveCenter2All(startCt, startRl, tables, maxLength, 1);
|
|
279
|
+
return solutions.length > 0 ? solutions[0] : null;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Enumerate phase-2 solutions (shortest first). The phase-2 → phase-3 bridge
|
|
283
|
+
* needs multiple candidates: the reference filters them by the pairing gate
|
|
284
|
+
* (transversal + even wing permutation), which most states fail.
|
|
285
|
+
*/
|
|
286
|
+
export function solveCenter2All(startCt, startRl, tables, maxLength = 40, cap = 200) {
|
|
287
|
+
const solutions = [];
|
|
288
|
+
const moveLog = new Array(maxLength);
|
|
289
|
+
for (let length = tables.pruning[startCt * CENTER2_RL_STATES + startRl]; length <= maxLength; length++) {
|
|
290
|
+
if (search(startCt, startRl, length, -1, 0))
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
return solutions;
|
|
294
|
+
function search(c, r, maxl, lm, depth) {
|
|
295
|
+
if (isCenter2Goal(c, r)) {
|
|
296
|
+
if (maxl === 0) {
|
|
297
|
+
solutions.push({
|
|
298
|
+
moves: moveLog.slice(0, depth).map((m) => CENTER2_MOVES[m]),
|
|
299
|
+
ct: c,
|
|
300
|
+
rl: r
|
|
301
|
+
});
|
|
302
|
+
return solutions.length >= cap;
|
|
303
|
+
}
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
for (let m = 0; m < CENTER2_SEARCH_MOVES.length; m++) {
|
|
307
|
+
if (lm >= 0 && isCancelled(CENTER2_SEARCH_MOVES[lm], CENTER2_SEARCH_MOVES[m])) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const nc = tables.ctMove[c * CENTER2_MOVES.length + m];
|
|
311
|
+
const nr = tables.rlMove[r * CENTER2_MOVES.length + m];
|
|
312
|
+
const prun = tables.pruning[nc * CENTER2_RL_STATES + nr];
|
|
313
|
+
if (prun >= maxl)
|
|
314
|
+
continue;
|
|
315
|
+
moveLog[depth] = m;
|
|
316
|
+
if (search(nc, nr, maxl - 1, m, depth + 1))
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
let cachedWingMaps = null;
|
|
323
|
+
function getWingMoveMaps() {
|
|
324
|
+
if (!cachedWingMaps) {
|
|
325
|
+
cachedWingMaps = buildWingMoveMaps();
|
|
326
|
+
}
|
|
327
|
+
return cachedWingMaps;
|
|
328
|
+
}
|
|
329
|
+
const tempWpPool = Array.from({ length: 5 }, () => new Uint8Array(24));
|
|
330
|
+
function replayWp(startWp, moves, depth, wingMaps, outWp) {
|
|
331
|
+
outWp.set(startWp);
|
|
332
|
+
const temp = tempWpPool[0];
|
|
333
|
+
for (let d = 0; d < depth; d++) {
|
|
334
|
+
const m = moves[d];
|
|
335
|
+
temp.set(outWp);
|
|
336
|
+
for (let i = 0; i < 24; i++) {
|
|
337
|
+
outWp[i] = temp[wingMaps[m * 24 + i]];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Solve Center 2 gated for an exact target length.
|
|
343
|
+
*/
|
|
344
|
+
export function solveCenter2GatedLength(startCt, startRl, startWp, tables, isGateEligible, targetLength, moveLog = new Array(targetLength)) {
|
|
345
|
+
const wingMaps = getWingMoveMaps();
|
|
346
|
+
let finalWp = null;
|
|
347
|
+
let finalCt = -1;
|
|
348
|
+
let finalRl = -1;
|
|
349
|
+
if (search(startCt, startRl, targetLength, -1, 0)) {
|
|
350
|
+
return {
|
|
351
|
+
moves: moveLog.slice(0, targetLength).map((m) => CENTER2_MOVES[m]),
|
|
352
|
+
ct: finalCt,
|
|
353
|
+
rl: finalRl,
|
|
354
|
+
wp: finalWp
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
function search(c, r, maxl, lm, depth) {
|
|
359
|
+
if (isCenter2Goal(c, r)) {
|
|
360
|
+
if (maxl === 0) {
|
|
361
|
+
replayWp(startWp, moveLog, depth, wingMaps, tempWpPool[1]);
|
|
362
|
+
if (isGateEligible(tempWpPool[1])) {
|
|
363
|
+
finalWp = tempWpPool[1].slice();
|
|
364
|
+
finalCt = c;
|
|
365
|
+
finalRl = r;
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
if (maxl === 0)
|
|
372
|
+
return false;
|
|
373
|
+
for (let m = 0; m < CENTER2_SEARCH_MOVES.length; m++) {
|
|
374
|
+
if (lm >= 0 && isCancelled(CENTER2_SEARCH_MOVES[lm], CENTER2_SEARCH_MOVES[m])) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const nc = tables.ctMove[c * CENTER2_MOVES.length + m];
|
|
378
|
+
const nr = tables.rlMove[r * CENTER2_MOVES.length + m];
|
|
379
|
+
const prun = tables.pruning[nc * CENTER2_RL_STATES + nr];
|
|
380
|
+
if (prun >= maxl)
|
|
381
|
+
continue;
|
|
382
|
+
moveLog[depth] = m;
|
|
383
|
+
if (search(nc, nr, maxl - 1, m, depth + 1))
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Phase-2 search that tracks the wing permutation alongside the (ct, rl)
|
|
391
|
+
* coordinate and only accepts goal states whose wings satisfy the pairing
|
|
392
|
+
* transversal (the phase-3 entry gate).
|
|
393
|
+
*/
|
|
394
|
+
export function solveCenter2Gated(startCt, startRl, startWp, tables, isGateEligible, maxLength = 40) {
|
|
395
|
+
const moveLog = new Array(maxLength);
|
|
396
|
+
const minLength = tables.pruning[startCt * CENTER2_RL_STATES + startRl];
|
|
397
|
+
for (let length = minLength; length <= maxLength; length++) {
|
|
398
|
+
const result = solveCenter2GatedLength(startCt, startRl, startWp, tables, isGateEligible, length, moveLog);
|
|
399
|
+
if (result)
|
|
400
|
+
return result;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
function buildWingMoveMaps() {
|
|
405
|
+
const maps = new Int32Array(CENTER2_MOVES.length * 24);
|
|
406
|
+
for (let m = 0; m < CENTER2_MOVES.length; m++) {
|
|
407
|
+
const { face, turns } = parseMove(CENTER2_MOVES[m]);
|
|
408
|
+
const effect = FACE_MOVE_EFFECTS[face];
|
|
409
|
+
let pos = Array.from({ length: 24 }, (_, i) => i);
|
|
410
|
+
for (let t = 0; t < turns; t++) {
|
|
411
|
+
const next = new Array(24);
|
|
412
|
+
for (let i = 0; i < 24; i++)
|
|
413
|
+
next[i] = pos[effect.wperm[i]];
|
|
414
|
+
pos = next;
|
|
415
|
+
}
|
|
416
|
+
for (let i = 0; i < 24; i++)
|
|
417
|
+
maps[m * 24 + i] = pos[i];
|
|
418
|
+
}
|
|
419
|
+
return maps;
|
|
420
|
+
}
|
|
421
|
+
// ---------------------------------------------------------------------------
|
|
422
|
+
// Verification gates
|
|
423
|
+
// ---------------------------------------------------------------------------
|
|
424
|
+
export function verifyCenter2(tables) {
|
|
425
|
+
const errors = [];
|
|
426
|
+
for (const rl of CENTER2_GOAL_RL) {
|
|
427
|
+
if (tables.pruning[rl] !== 0) {
|
|
428
|
+
errors.push(`Goal rl ${rl} must have pruning 0.`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
let maxDepth = 0;
|
|
432
|
+
for (let idx = 0; idx < CENTER2_STATES; idx++) {
|
|
433
|
+
const d = tables.pruning[idx];
|
|
434
|
+
if (d > maxDepth)
|
|
435
|
+
maxDepth = d;
|
|
436
|
+
const ct = Math.floor(idx / CENTER2_RL_STATES);
|
|
437
|
+
const rl = idx % CENTER2_RL_STATES;
|
|
438
|
+
for (let m = 0; m < CENTER2_SEARCH_MOVES.length; m++) {
|
|
439
|
+
const nc = tables.ctMove[ct * CENTER2_MOVES.length + m];
|
|
440
|
+
const nr = tables.rlMove[rl * CENTER2_MOVES.length + m];
|
|
441
|
+
const nd = tables.pruning[nc * CENTER2_RL_STATES + nr];
|
|
442
|
+
if (nd < d - 1 || nd > d + 1) {
|
|
443
|
+
errors.push(`Pruning inconsistency at ${idx} move ${CENTER2_MOVES[m]}: ${d} -> ${nd}.`);
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return errors;
|
|
449
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Center3 (the center part of the phase-3 search): track the center
|
|
3
|
+
* arrangement through the phase-3 moves (which disturb the solved centers
|
|
4
|
+
* with the wide doubles) and reach the fully-solved centers.
|
|
5
|
+
*
|
|
6
|
+
* Ported from the reference's `Center3` class, adapted to this repo's
|
|
7
|
+
* layout. The state is three 8-entry arrays of "half-class" bits
|
|
8
|
+
* ((color / 3) ^ 1) per face-pair, plus a parity bit:
|
|
9
|
+
* - ud: the U, D face positions (this repo: U = 0-3, D = 12-15)
|
|
10
|
+
* - fb: the F, B face positions (8-11, 20-23)
|
|
11
|
+
* - rl: the R, L face positions (4-7, 16-19)
|
|
12
|
+
*
|
|
13
|
+
* Coordinate (reference `$getct_0`): C(7,4) ranks of ud and fb vs their 8th
|
|
14
|
+
* entry (35 each), the rl C(8,4) rank reduced to one of 12 standard values,
|
|
15
|
+
* then ×2 + parity = 29,400 × 2. The rank-0 pattern is "the first four
|
|
16
|
+
* entries differ from the last four" — i.e. each face-pair uniform in half
|
|
17
|
+
* — which is exactly the solved-cube arrangement (verified: the solved cube
|
|
18
|
+
* encodes to coordinate 0). The parity bit absorbs the wing-pairing parity
|
|
19
|
+
* XOR the corner parity at the phase-2 → phase-3 bridge and flips on the
|
|
20
|
+
* wide doubles (`pmove`).
|
|
21
|
+
*/
|
|
22
|
+
import type { Cube4State } from "../types.js";
|
|
23
|
+
export declare const CENTER3_MOVES: readonly ["U", "U2", "U'", "R2", "F", "F2", "F'", "D", "D2", "D'", "L2", "B", "B2", "B'", "Uw2", "Rw2", "Fw2", "Dw2", "Lw2", "Bw2"];
|
|
24
|
+
/** The 17-move BFS subset (the reference's pruning loop uses m < 17). */
|
|
25
|
+
export declare const CENTER3_BFS_MOVES: ("U" | "D" | "F" | "B" | "U2" | "U'" | "D2" | "D'" | "R2" | "L2" | "F2" | "F'" | "B2" | "B'" | "Uw2" | "Dw2" | "Rw2" | "Lw2" | "Fw2" | "Bw2")[];
|
|
26
|
+
export declare const CENTER3_STATES = 29400;
|
|
27
|
+
export interface Center3Encoded {
|
|
28
|
+
/** Full coordinate 0..29,399 (parity included). */
|
|
29
|
+
coordinate: number;
|
|
30
|
+
parity: 0 | 1;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Encode a full cube state to the Center3 coordinate.
|
|
34
|
+
*
|
|
35
|
+
* `edgeXorCornerParity` = the $set_6 pairing parity XOR the corner
|
|
36
|
+
* permutation parity, computed at the phase-2 → phase-3 bridge.
|
|
37
|
+
*/
|
|
38
|
+
export declare function encodeCenter3(state: Cube4State, edgeXorCornerParity: 0 | 1): Center3Encoded;
|
|
39
|
+
export interface Center3Tables {
|
|
40
|
+
/** 29400 × 20 — full coordinate (parity included) after each move. */
|
|
41
|
+
moveTable: Int32Array;
|
|
42
|
+
/** 29400 BFS distances. */
|
|
43
|
+
pruning: Uint8Array;
|
|
44
|
+
}
|
|
45
|
+
export declare function generateCenter3Tables(): Center3Tables;
|
|
46
|
+
export declare function verifyCenter3(tables: Center3Tables): string[];
|
|
47
|
+
//# sourceMappingURL=center3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"center3.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/center3.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO9C,eAAO,MAAM,aAAa,qIAGhB,CAAC;AAEX,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,iJAA6B,CAAC;AAa5D,eAAO,MAAM,cAAc,QAAQ,CAAC;AAiDpC,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,EACjB,mBAAmB,EAAE,CAAC,GAAG,CAAC,GACzB,cAAc,CA8BhB;AAsBD,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,SAAS,EAAE,UAAU,CAAC;IACtB,2BAA2B;IAC3B,OAAO,EAAE,UAAU,CAAC;CACrB;AAoDD,wBAAgB,qBAAqB,IAAI,aAAa,CAgErD;AAMD,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAwB7D"}
|