@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,278 @@
|
|
|
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 { FACE_MOVE_EFFECTS, parseMove } from "../moves.js";
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Constants
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
export const CENTER3_MOVES = [
|
|
27
|
+
"U", "U2", "U'", "R2", "F", "F2", "F'", "D", "D2", "D'",
|
|
28
|
+
"L2", "B", "B2", "B'", "Uw2", "Rw2", "Fw2", "Dw2", "Lw2", "Bw2"
|
|
29
|
+
];
|
|
30
|
+
/** The 17-move BFS subset (the reference's pruning loop uses m < 17). */
|
|
31
|
+
export const CENTER3_BFS_MOVES = CENTER3_MOVES.slice(0, 17);
|
|
32
|
+
/** Wide doubles flip the parity bit. */
|
|
33
|
+
const PARITY_FLIP = new Set(["Uw2", "Rw2", "Fw2", "Dw2", "Lw2", "Bw2"]);
|
|
34
|
+
/** Face-pair positions in this repo's numbering. */
|
|
35
|
+
const UD_POS = [0, 1, 2, 3, 12, 13, 14, 15];
|
|
36
|
+
const FB_POS = [8, 9, 10, 11, 20, 21, 22, 23];
|
|
37
|
+
const RL_POS = [4, 5, 6, 7, 16, 17, 18, 19];
|
|
38
|
+
/** The 12 standard rl ranks (reference rl2std). */
|
|
39
|
+
const RL2STD = [0, 9, 14, 23, 27, 28, 41, 42, 46, 55, 60, 69];
|
|
40
|
+
export const CENTER3_STATES = 29400;
|
|
41
|
+
// Cnk table up to n=24.
|
|
42
|
+
const CNK = (() => {
|
|
43
|
+
const table = [];
|
|
44
|
+
for (let n = 0; n <= 24; n++) {
|
|
45
|
+
table[n] = [];
|
|
46
|
+
for (let k = 0; k <= 24; k++) {
|
|
47
|
+
if (k === 0 || k === n)
|
|
48
|
+
table[n][k] = 1;
|
|
49
|
+
else if (k > n)
|
|
50
|
+
table[n][k] = 0;
|
|
51
|
+
else
|
|
52
|
+
table[n][k] = table[n - 1][k - 1] + table[n - 1][k];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return table;
|
|
56
|
+
})();
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Half-class helpers
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
function halfClass(color) {
|
|
61
|
+
return (Math.floor(color / 3) ^ 1) & 1;
|
|
62
|
+
}
|
|
63
|
+
/** C(7,4) rank of the entries differing from the last one. */
|
|
64
|
+
function rank7(values) {
|
|
65
|
+
const last = values[7];
|
|
66
|
+
let idx = 0;
|
|
67
|
+
let r = 4;
|
|
68
|
+
for (let i = 6; i >= 0; i--) {
|
|
69
|
+
if (values[i] !== last)
|
|
70
|
+
idx += CNK[i][r--];
|
|
71
|
+
}
|
|
72
|
+
return idx;
|
|
73
|
+
}
|
|
74
|
+
/** C(8,4) rank of the entries differing from `check`. */
|
|
75
|
+
function rank8(values, check) {
|
|
76
|
+
let idx = 0;
|
|
77
|
+
let r = 4;
|
|
78
|
+
for (let i = 7; i >= 0; i--) {
|
|
79
|
+
if (values[i] !== check)
|
|
80
|
+
idx += CNK[i][r--];
|
|
81
|
+
}
|
|
82
|
+
return idx;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Encode a full cube state to the Center3 coordinate.
|
|
86
|
+
*
|
|
87
|
+
* `edgeXorCornerParity` = the $set_6 pairing parity XOR the corner
|
|
88
|
+
* permutation parity, computed at the phase-2 → phase-3 bridge.
|
|
89
|
+
*/
|
|
90
|
+
export function encodeCenter3(state, edgeXorCornerParity) {
|
|
91
|
+
const colors = state.centers;
|
|
92
|
+
// reference: parity = (ct[0]%3 > ct[8]%3) ^ (ct[8]%3 > ct[16]%3) ^ (ct[0]%3 > ct[16]%3) ? 0 : 1
|
|
93
|
+
const a = colors[0] % 3;
|
|
94
|
+
const b = colors[8] % 3;
|
|
95
|
+
const c = colors[16] % 3;
|
|
96
|
+
const xored = (a > b ? 1 : 0) ^ (b > c ? 1 : 0) ^ (a > c ? 1 : 0);
|
|
97
|
+
const parity = xored === 0 ? 1 : 0;
|
|
98
|
+
const ud = new Uint8Array(8);
|
|
99
|
+
const fb = new Uint8Array(8);
|
|
100
|
+
const rl = new Uint8Array(8);
|
|
101
|
+
for (let i = 0; i < 8; i++) {
|
|
102
|
+
ud[i] = halfClass(colors[UD_POS[i]]);
|
|
103
|
+
fb[i] = halfClass(colors[FB_POS[i]]);
|
|
104
|
+
rl[i] = halfClass(colors[RL_POS[i]]);
|
|
105
|
+
}
|
|
106
|
+
let idx = rank7(ud);
|
|
107
|
+
idx = idx * 35 + rank7(fb);
|
|
108
|
+
idx *= 12;
|
|
109
|
+
const check = fb[7] ^ ud[7];
|
|
110
|
+
const rlRank = rank8(rl, check);
|
|
111
|
+
const rlIndex = RL2STD.indexOf(rlRank);
|
|
112
|
+
const finalParity = (parity ^ edgeXorCornerParity);
|
|
113
|
+
return {
|
|
114
|
+
coordinate: finalParity + 2 * (idx + rlIndex),
|
|
115
|
+
parity: finalParity
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Move tables + pruning
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
function buildMovePositionMaps() {
|
|
122
|
+
const maps = new Int32Array(CENTER3_MOVES.length * 24);
|
|
123
|
+
for (let m = 0; m < CENTER3_MOVES.length; m++) {
|
|
124
|
+
const { face, turns } = parseMove(CENTER3_MOVES[m]);
|
|
125
|
+
const effect = FACE_MOVE_EFFECTS[face];
|
|
126
|
+
let pos = Array.from({ length: 24 }, (_, i) => i);
|
|
127
|
+
for (let t = 0; t < turns; t++) {
|
|
128
|
+
const next = new Array(24);
|
|
129
|
+
for (let i = 0; i < 24; i++)
|
|
130
|
+
next[i] = pos[effect.ctperm[i]];
|
|
131
|
+
pos = next;
|
|
132
|
+
}
|
|
133
|
+
for (let i = 0; i < 24; i++)
|
|
134
|
+
maps[m * 24 + i] = pos[i];
|
|
135
|
+
}
|
|
136
|
+
return maps;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Decode a coordinate to canonical half-class arrays (for the move tables):
|
|
140
|
+
* the rank-0 pattern is "first four differ from the last four", so the
|
|
141
|
+
* canonical state is ud = [1,1,1,1,0,0,0,0], fb = [1,1,1,1,0,0,0,0],
|
|
142
|
+
* rl = [1,1,1,1,0,0,0,0] for coordinate 0.
|
|
143
|
+
*/
|
|
144
|
+
function decodeCenter3(coordinate) {
|
|
145
|
+
const parity = coordinate & 1;
|
|
146
|
+
let value = coordinate >> 1;
|
|
147
|
+
const rlIndex = value % 12;
|
|
148
|
+
value = Math.floor(value / 12);
|
|
149
|
+
const fbRank = value % 35;
|
|
150
|
+
const udRank = Math.floor(value / 35);
|
|
151
|
+
const ud = new Uint8Array(8);
|
|
152
|
+
const fb = new Uint8Array(8);
|
|
153
|
+
const rl = new Uint8Array(8);
|
|
154
|
+
// unrank C(7,4) patterns
|
|
155
|
+
let idx = udRank;
|
|
156
|
+
let r = 4;
|
|
157
|
+
for (let i = 6; i >= 0; i--) {
|
|
158
|
+
if (idx >= CNK[i][r]) {
|
|
159
|
+
idx -= CNK[i][r];
|
|
160
|
+
r--;
|
|
161
|
+
ud[i] = 1;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
idx = fbRank;
|
|
165
|
+
r = 4;
|
|
166
|
+
for (let i = 6; i >= 0; i--) {
|
|
167
|
+
if (idx >= CNK[i][r]) {
|
|
168
|
+
idx -= CNK[i][r];
|
|
169
|
+
r--;
|
|
170
|
+
fb[i] = 1;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// rl: the standard rank from the index
|
|
174
|
+
const rlRank = RL2STD[rlIndex];
|
|
175
|
+
idx = rlRank;
|
|
176
|
+
r = 4;
|
|
177
|
+
for (let i = 7; i >= 0; i--) {
|
|
178
|
+
if (idx >= CNK[i][r]) {
|
|
179
|
+
idx -= CNK[i][r];
|
|
180
|
+
r--;
|
|
181
|
+
rl[i] = 1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return { ud, fb, rl, parity };
|
|
185
|
+
}
|
|
186
|
+
export function generateCenter3Tables() {
|
|
187
|
+
const moveMaps = buildMovePositionMaps();
|
|
188
|
+
const moveTable = new Int32Array(CENTER3_STATES * CENTER3_MOVES.length).fill(-1);
|
|
189
|
+
// canonical full arrangements: half-class bits at the face-pair positions.
|
|
190
|
+
// The rl array stores the parity-XORed halves, so the decode undoes the XOR
|
|
191
|
+
// to recover the colors; the move evolution re-extracts the RAW halves and
|
|
192
|
+
// evolves the parity bit via pmove only (it is NOT re-derived from the
|
|
193
|
+
// centers, matching the reference's doMoveCenter3).
|
|
194
|
+
const full = new Uint8Array(24);
|
|
195
|
+
const moved = new Uint8Array(24);
|
|
196
|
+
const ud2 = new Uint8Array(8);
|
|
197
|
+
const fb2 = new Uint8Array(8);
|
|
198
|
+
const rl2 = new Uint8Array(8);
|
|
199
|
+
const coordinateOfMoved = (coordinate, m, parity) => {
|
|
200
|
+
const { ud, fb, rl } = decodeCenter3(coordinate);
|
|
201
|
+
// the half-class arrays live at the 24 face-pair positions; a move is a
|
|
202
|
+
// position permutation, so build the 24-array, permute, and re-extract.
|
|
203
|
+
for (let i = 0; i < 24; i++)
|
|
204
|
+
full[i] = 0;
|
|
205
|
+
for (let i = 0; i < 8; i++) {
|
|
206
|
+
full[UD_POS[i]] = ud[i];
|
|
207
|
+
full[FB_POS[i]] = fb[i];
|
|
208
|
+
full[RL_POS[i]] = rl[i];
|
|
209
|
+
}
|
|
210
|
+
const map = moveMaps;
|
|
211
|
+
for (let i = 0; i < 24; i++)
|
|
212
|
+
moved[i] = full[map[m * 24 + i]];
|
|
213
|
+
for (let i = 0; i < 8; i++) {
|
|
214
|
+
ud2[i] = moved[UD_POS[i]];
|
|
215
|
+
fb2[i] = moved[FB_POS[i]];
|
|
216
|
+
rl2[i] = moved[RL_POS[i]];
|
|
217
|
+
}
|
|
218
|
+
let idx = rank7(ud2);
|
|
219
|
+
idx = idx * 35 + rank7(fb2);
|
|
220
|
+
idx *= 12;
|
|
221
|
+
const check = fb2[7] ^ ud2[7];
|
|
222
|
+
const rlRank = rank8(rl2, check);
|
|
223
|
+
const rlIndex = RL2STD.indexOf(rlRank);
|
|
224
|
+
if (rlIndex < 0)
|
|
225
|
+
return -1;
|
|
226
|
+
const nextParity = (parity ^ (PARITY_FLIP.has(CENTER3_MOVES[m]) ? 1 : 0));
|
|
227
|
+
return nextParity + 2 * (idx + rlIndex);
|
|
228
|
+
};
|
|
229
|
+
// BFS from coordinate 0 with the 17 BFS moves, computing the move-table
|
|
230
|
+
// entries on demand (only the reachable states' transitions are needed).
|
|
231
|
+
const pruning = new Uint8Array(CENTER3_STATES).fill(0xff);
|
|
232
|
+
pruning[0] = 0;
|
|
233
|
+
const queue = [0];
|
|
234
|
+
let head = 0;
|
|
235
|
+
while (head < queue.length) {
|
|
236
|
+
const coord = queue[head++];
|
|
237
|
+
const d = pruning[coord];
|
|
238
|
+
for (let m = 0; m < CENTER3_MOVES.length; m++) {
|
|
239
|
+
const next = coordinateOfMoved(coord, m, coord & 1);
|
|
240
|
+
if (next < 0)
|
|
241
|
+
continue;
|
|
242
|
+
moveTable[coord * CENTER3_MOVES.length + m] = next;
|
|
243
|
+
if (m < CENTER3_BFS_MOVES.length && pruning[next] === 0xff) {
|
|
244
|
+
pruning[next] = d + 1;
|
|
245
|
+
queue.push(next);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return { moveTable, pruning };
|
|
250
|
+
}
|
|
251
|
+
// ---------------------------------------------------------------------------
|
|
252
|
+
// Verification gates
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
export function verifyCenter3(tables) {
|
|
255
|
+
const errors = [];
|
|
256
|
+
if (tables.pruning[0] !== 0) {
|
|
257
|
+
errors.push("Goal coordinate must have pruning 0.");
|
|
258
|
+
}
|
|
259
|
+
let maxDepth = 0;
|
|
260
|
+
for (let coord = 0; coord < CENTER3_STATES; coord++) {
|
|
261
|
+
const d = tables.pruning[coord];
|
|
262
|
+
if (d === 0xff)
|
|
263
|
+
continue; // unreachable coordinates have no entries
|
|
264
|
+
if (d > maxDepth)
|
|
265
|
+
maxDepth = d;
|
|
266
|
+
for (let m = 0; m < CENTER3_MOVES.length; m++) {
|
|
267
|
+
const next = tables.moveTable[coord * CENTER3_MOVES.length + m];
|
|
268
|
+
if (next < 0)
|
|
269
|
+
continue;
|
|
270
|
+
const nd = tables.pruning[next];
|
|
271
|
+
if (nd === 0xff || nd < d - 1 || nd > d + 1) {
|
|
272
|
+
errors.push(`Pruning inconsistency at ${coord} move ${CENTER3_MOVES[m]}: ${d} -> ${nd}.`);
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return errors;
|
|
278
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge3 (the pairing pruning table for the phase-3 search).
|
|
3
|
+
*
|
|
4
|
+
* The BFS from the solved pairing state over the 17 BFS moves, canonicalized
|
|
5
|
+
* by the 8 rotation symmetries of the reference's Edge3 phase (`$rot_1` /
|
|
6
|
+
* `$rotate_0` decomposition with the `$circlex` / `$swapx` coordinate
|
|
7
|
+
* effects). The pairing state is the relative 12-permutation between the
|
|
8
|
+
* two halves of the edge slots (see `pairing-coordinate.ts`), stored in the
|
|
9
|
+
* reference's `(edge, edgeo)` form with shared labels and `$std`-normalized
|
|
10
|
+
* (second halves hold pairs 0..11 in order).
|
|
11
|
+
*
|
|
12
|
+
* Canonicalization and indexing follow the reference exactly:
|
|
13
|
+
* - the state space is the 12!/2 even edge permutations (parity is
|
|
14
|
+
* invariant under the phase-3 moves), grouped into 1538 first-4
|
|
15
|
+
* "sym" classes under the 8 rotations (the reference's
|
|
16
|
+
* `initEdge3Sym2Raw`);
|
|
17
|
+
* - the canonical sym-index of a state is `symcord1 * 20160 + cord2`,
|
|
18
|
+
* computed by `getMvSym` (the reference's move-conjugated
|
|
19
|
+
* canonicalization with the `mvrot`/`mvroto` tables);
|
|
20
|
+
* - the table stores the exact BFS distance per sym-index (4-bit packed
|
|
21
|
+
* nibbles): 31,006,080 * 4 bits = 15.5 MB, no class-key file needed.
|
|
22
|
+
*/
|
|
23
|
+
/** The sym-index space: 1538 first-4 classes × 20160 remaining. */
|
|
24
|
+
export declare const EDGE3_TOTAL = 31006080;
|
|
25
|
+
export declare const EDGE3_CLASSES = 1538;
|
|
26
|
+
export declare const EDGE3_CORD2 = 20160;
|
|
27
|
+
/** The maximum BFS depth (the reference's prunValues length - 1). */
|
|
28
|
+
export declare const EDGE3_MAX_DEPTH = 13;
|
|
29
|
+
/** The reference's `move3std`: $move_4 case → std3 move id (the % 3 class). */
|
|
30
|
+
export declare const MOVE3_STD: readonly number[];
|
|
31
|
+
export declare function bitCount(v: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* The reference's `$move_4` (cases 0-19) as coordinate effects: the same
|
|
34
|
+
* slot permutations applied to `edge` and `edgeo`. The `circle` direction
|
|
35
|
+
* (the cubing.js `mathlib.circle`: the value at a moves to b) is verified
|
|
36
|
+
* against the physical move tables in `verifyEdge3`.
|
|
37
|
+
*/
|
|
38
|
+
declare function applyMoveCase(edge: Uint8Array, edgeo: Uint8Array, m: number): void;
|
|
39
|
+
/** The reference's `$rotate_0`: rotation r (0..7) via the rot1 decomposition. */
|
|
40
|
+
declare function rotateByIndex(edge: Uint8Array, edgeo: Uint8Array, r: number): void;
|
|
41
|
+
/**
|
|
42
|
+
* The mixed-radix Lehmer encode of the first `end` values (the reference's
|
|
43
|
+
* `get12Perm`): idx = Σ digit_i * (12-i)!-radix, with the digits reduced by
|
|
44
|
+
* the values already seen.
|
|
45
|
+
*/
|
|
46
|
+
declare function get12Perm(arr: Uint8Array, end: number, returnMask?: boolean): number;
|
|
47
|
+
/**
|
|
48
|
+
* Decode a 12-permutation from the mixed-radix index (the reference's
|
|
49
|
+
* `$set_4`): the 11 digits with the parity-corrected last two positions.
|
|
50
|
+
*/
|
|
51
|
+
declare function set4(out: Uint8Array, idx: number): void;
|
|
52
|
+
export interface SymTables {
|
|
53
|
+
mvrot: Uint8Array;
|
|
54
|
+
mvroto: Uint8Array;
|
|
55
|
+
sym2Raw: Uint32Array;
|
|
56
|
+
/** class → the used-values mask of its representative's first 4. */
|
|
57
|
+
sym2Mask: Uint32Array;
|
|
58
|
+
/** first-4 Lehmer → (class << 3 | rotation). */
|
|
59
|
+
raw2Sym: Uint32Array;
|
|
60
|
+
/** class → the bitmask of the rotations mapping the representative to itself. */
|
|
61
|
+
symState: Uint32Array;
|
|
62
|
+
/** (move, class) → the moved state's (class << 3 | rotation) for the %3==1 moves. */
|
|
63
|
+
symMove: Uint16Array;
|
|
64
|
+
}
|
|
65
|
+
export declare function getSymTables(): SymTables;
|
|
66
|
+
export declare function buildSymTables(): SymTables;
|
|
67
|
+
/**
|
|
68
|
+
* The reference's `getMvSym`: the canonical sym-index of the state (edge,
|
|
69
|
+
* edgeo) under the move-conjugated rotation, as `(sym-index << 3 | r)`.
|
|
70
|
+
*/
|
|
71
|
+
export declare function getMvSymFrom(edge: Uint8Array, _edgeo: Uint8Array, mv: number, sym2Raw: Uint32Array, sym2Mask: Uint32Array, raw2Sym: Uint32Array, mvrot: Uint8Array, mvroto: Uint8Array, assumeIdx?: number): number;
|
|
72
|
+
export interface Edge3Tables {
|
|
73
|
+
/** sym-index → BFS distance (packed 4-bit nibbles). */
|
|
74
|
+
distances: Uint8Array;
|
|
75
|
+
/** the distance of a std-form edge (a 12-permutation). */
|
|
76
|
+
distanceOfEdge(edge: Uint8Array): number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Generate the exact BFS distances over the 31,006,080 sym-index space.
|
|
80
|
+
* `maxDepthCap` stops the BFS early (validation only).
|
|
81
|
+
*/
|
|
82
|
+
export declare function generateEdge3Tables(maxDepthCap?: number): Edge3Tables;
|
|
83
|
+
/**
|
|
84
|
+
* The distance lookup over a loaded distances buffer: builds the sym
|
|
85
|
+
* machinery once (cached) and returns a closure from the std-form edge
|
|
86
|
+
* (a 12-permutation) to its BFS distance.
|
|
87
|
+
*/
|
|
88
|
+
export declare function edge3DistanceLookup(distances: Uint8Array): (edge: Uint8Array) => number;
|
|
89
|
+
/** Test-only hooks. */
|
|
90
|
+
export declare function __edge3TestHooks(): {
|
|
91
|
+
buildSymTables: typeof buildSymTables;
|
|
92
|
+
applyMoveCase: typeof applyMoveCase;
|
|
93
|
+
get12Perm: typeof get12Perm;
|
|
94
|
+
set4: typeof set4;
|
|
95
|
+
rotateByIndex: typeof rotateByIndex;
|
|
96
|
+
getMvSymFrom: typeof getMvSymFrom;
|
|
97
|
+
};
|
|
98
|
+
export declare function verifyEdge3(tables: Edge3Tables): string[];
|
|
99
|
+
export {};
|
|
100
|
+
//# sourceMappingURL=edge3.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge3.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube4/reduction/edge3.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAWH,mEAAmE;AACnE,eAAO,MAAM,WAAW,WAAa,CAAC;AACtC,eAAO,MAAM,aAAa,OAAO,CAAC;AAClC,eAAO,MAAM,WAAW,QAAS,CAAC;AAGlC,qEAAqE;AACrE,eAAO,MAAM,eAAe,KAAK,CAAC;AAUlC,+EAA+E;AAC/E,eAAO,MAAM,SAAS,EAAE,SAAS,MAAM,EAEtC,CAAC;AAaF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1C;AAkCD;;;;;GAKG;AACH,iBAAS,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CA2G3E;AAkCD,iFAAiF;AACjF,iBAAS,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAO3E;AAMD;;;;GAIG;AACH,iBAAS,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,UAAQ,GAAG,MAAM,CAS3E;AAED;;;GAGG;AACH,iBAAS,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAmBhD;AAOD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,WAAW,CAAC;IACtB,gDAAgD;IAChD,OAAO,EAAE,WAAW,CAAC;IACrB,iFAAiF;IACjF,QAAQ,EAAE,WAAW,CAAC;IACtB,qFAAqF;IACrF,OAAO,EAAE,WAAW,CAAC;CACtB;AAID,wBAAgB,YAAY,IAAI,SAAS,CAKxC;AAED,wBAAgB,cAAc,IAAI,SAAS,CAoE1C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CA6BR;AAMD,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,SAAS,EAAE,UAAU,CAAC;IACtB,0DAA0D;IAC1D,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,SAAK,GAAG,WAAW,CAkEjE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,UAAU,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CASvF;AAMD,uBAAuB;AACvB,wBAAgB,gBAAgB;;;;;;;EAE/B;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAgBzD"}
|