@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,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Combinatorics and coordinate packing/unpacking for FTO (Face-Turning Octahedron).
|
|
4
|
+
*
|
|
5
|
+
* Implements exact bijections for:
|
|
6
|
+
* - Even corner permutations (A_6, 360 states)
|
|
7
|
+
* - Corner orientations (Z_2^5 with even sum, 32 states)
|
|
8
|
+
* - Even edge permutations (A_12, 239,500,800 states)
|
|
9
|
+
* - Center orbit arrangements (C(12,3)*C(9,3)*C(6,3) = 369,600 states per orbit)
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.nCr = nCr;
|
|
13
|
+
exports.getPermutationParity = getPermutationParity;
|
|
14
|
+
exports.packSubset = packSubset;
|
|
15
|
+
exports.unpackSubset = unpackSubset;
|
|
16
|
+
exports.packEvenPerm = packEvenPerm;
|
|
17
|
+
exports.unpackEvenPerm = unpackEvenPerm;
|
|
18
|
+
exports.packCornerOrientation = packCornerOrientation;
|
|
19
|
+
exports.unpackCornerOrientation = unpackCornerOrientation;
|
|
20
|
+
exports.packCenterOrbit = packCenterOrbit;
|
|
21
|
+
exports.unpackCenterOrbit = unpackCenterOrbit;
|
|
22
|
+
const types_js_1 = require("./types.js");
|
|
23
|
+
const FACTORIAL = [
|
|
24
|
+
1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Binomial coefficient nCr = n! / (k! * (n-k)!).
|
|
28
|
+
*/
|
|
29
|
+
function nCr(n, k) {
|
|
30
|
+
if (k < 0 || k > n)
|
|
31
|
+
return 0;
|
|
32
|
+
if (k === 0 || k === n)
|
|
33
|
+
return 1;
|
|
34
|
+
if (k > n - k)
|
|
35
|
+
k = n - k;
|
|
36
|
+
let res = 1;
|
|
37
|
+
for (let i = 1; i <= k; i++) {
|
|
38
|
+
res = (res * (n - i + 1)) / i;
|
|
39
|
+
}
|
|
40
|
+
return res;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Compute the permutation parity (number of inversions mod 2).
|
|
44
|
+
* Returns true if odd, false if even.
|
|
45
|
+
*/
|
|
46
|
+
function getPermutationParity(perm) {
|
|
47
|
+
let inversions = 0;
|
|
48
|
+
const n = perm.length;
|
|
49
|
+
for (let i = 0; i < n; i++) {
|
|
50
|
+
for (let j = i + 1; j < n; j++) {
|
|
51
|
+
if (perm[i] > perm[j]) {
|
|
52
|
+
inversions++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return (inversions & 1) === 1;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Pack a sorted k-subset of {0, ..., n-1} into an integer in [0, nCr(n, k) - 1].
|
|
60
|
+
* Uses standard combinatorial number system ranking: sum_{i=0}^{k-1} nCr(s_i, i + 1).
|
|
61
|
+
*/
|
|
62
|
+
function packSubset(subset) {
|
|
63
|
+
let index = 0;
|
|
64
|
+
for (let i = subset.length - 1; i >= 0; i--) {
|
|
65
|
+
index += nCr(subset[i], i + 1);
|
|
66
|
+
}
|
|
67
|
+
return index;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Unpack an integer index in [0, nCr(n, k) - 1] into a sorted k-subset.
|
|
71
|
+
*/
|
|
72
|
+
function unpackSubset(target, k, index) {
|
|
73
|
+
target.length = k;
|
|
74
|
+
let remaining = index;
|
|
75
|
+
let currentK = k;
|
|
76
|
+
for (let pos = 0; pos < k; pos++) {
|
|
77
|
+
let c = currentK - 1;
|
|
78
|
+
while (nCr(c + 1, currentK) <= remaining) {
|
|
79
|
+
c++;
|
|
80
|
+
}
|
|
81
|
+
target[k - 1 - pos] = c;
|
|
82
|
+
remaining -= nCr(c, currentK);
|
|
83
|
+
currentK--;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Pack an even permutation of length n into its rank in A_n: [0, n!/2 - 1].
|
|
88
|
+
*/
|
|
89
|
+
function packEvenPerm(perm) {
|
|
90
|
+
const n = perm.length;
|
|
91
|
+
let rank = 0;
|
|
92
|
+
let used = 0;
|
|
93
|
+
for (let i = 0; i < n - 2; i++) {
|
|
94
|
+
const val = perm[i];
|
|
95
|
+
// Count how many smaller values haven't been used yet
|
|
96
|
+
let digit = 0;
|
|
97
|
+
for (let v = 0; v < val; v++) {
|
|
98
|
+
if ((used & (1 << v)) === 0) {
|
|
99
|
+
digit++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
used |= 1 << val;
|
|
103
|
+
const factor = FACTORIAL[n - 1 - i] / 2;
|
|
104
|
+
rank += digit * factor;
|
|
105
|
+
}
|
|
106
|
+
return rank;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Unpack an integer rank in [0, n!/2 - 1] into an even permutation of length n.
|
|
110
|
+
*/
|
|
111
|
+
function unpackEvenPerm(n, rank, target) {
|
|
112
|
+
const perm = target ? target : new Array(n);
|
|
113
|
+
perm.length = n;
|
|
114
|
+
const lehmer = new Array(n);
|
|
115
|
+
let remaining = rank;
|
|
116
|
+
let sumLehmer = 0;
|
|
117
|
+
for (let i = 0; i < n - 2; i++) {
|
|
118
|
+
const factor = FACTORIAL[n - 1 - i] / 2;
|
|
119
|
+
const digit = Math.floor(remaining / factor);
|
|
120
|
+
remaining %= factor;
|
|
121
|
+
lehmer[i] = digit;
|
|
122
|
+
sumLehmer += digit;
|
|
123
|
+
}
|
|
124
|
+
// The (n-2)-th digit is fixed by even-parity constraint:
|
|
125
|
+
lehmer[n - 2] = sumLehmer & 1;
|
|
126
|
+
lehmer[n - 1] = 0;
|
|
127
|
+
// Reconstruct permutation from Lehmer code
|
|
128
|
+
const available = new Array(n);
|
|
129
|
+
for (let i = 0; i < n; i++)
|
|
130
|
+
available[i] = i;
|
|
131
|
+
for (let i = 0; i < n; i++) {
|
|
132
|
+
const choice = lehmer[i];
|
|
133
|
+
perm[i] = available[choice];
|
|
134
|
+
available.splice(choice, 1);
|
|
135
|
+
}
|
|
136
|
+
return perm;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Pack 6 corner orientations (each in {0, 1} with even sum) into [0, 31].
|
|
140
|
+
*/
|
|
141
|
+
function packCornerOrientation(co) {
|
|
142
|
+
let rank = 0;
|
|
143
|
+
for (let i = 0; i < types_js_1.FTO_CORNER_COUNT - 1; i++) {
|
|
144
|
+
rank |= (co[i] & 1) << i;
|
|
145
|
+
}
|
|
146
|
+
return rank;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Unpack an orientation rank in [0, 31] into 6 corner orientations with sum = 0 mod 2.
|
|
150
|
+
*/
|
|
151
|
+
function unpackCornerOrientation(rank, target) {
|
|
152
|
+
const co = target ? target : new Array(types_js_1.FTO_CORNER_COUNT);
|
|
153
|
+
co.length = types_js_1.FTO_CORNER_COUNT;
|
|
154
|
+
let sum = 0;
|
|
155
|
+
for (let i = 0; i < types_js_1.FTO_CORNER_COUNT - 1; i++) {
|
|
156
|
+
const val = (rank >> i) & 1;
|
|
157
|
+
co[i] = val;
|
|
158
|
+
sum += val;
|
|
159
|
+
}
|
|
160
|
+
co[types_js_1.FTO_CORNER_COUNT - 1] = sum & 1;
|
|
161
|
+
return co;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Pack a center orbit (12 pieces, 3 of each of 4 colors) into [0, 369599].
|
|
165
|
+
* Pieces 0..2 are color 0, 3..5 are color 1, 6..8 are color 2, 9..11 are color 3.
|
|
166
|
+
*/
|
|
167
|
+
function packCenterOrbit(centers) {
|
|
168
|
+
const positions = [[], [], [], []];
|
|
169
|
+
for (let i = 0; i < 12; i++) {
|
|
170
|
+
const color = Math.floor(centers[i] / 3);
|
|
171
|
+
positions[color].push(i);
|
|
172
|
+
}
|
|
173
|
+
// 1. Color 0 positions in 0..11 (size 3)
|
|
174
|
+
const d0 = packSubset(positions[0]);
|
|
175
|
+
// Remaining 9 positions
|
|
176
|
+
const p1 = [];
|
|
177
|
+
const used0 = new Set(positions[0]);
|
|
178
|
+
for (let i = 0; i < 12; i++) {
|
|
179
|
+
if (!used0.has(i))
|
|
180
|
+
p1.push(i);
|
|
181
|
+
}
|
|
182
|
+
// 2. Color 1 positions mapped into p1 index space (0..8)
|
|
183
|
+
const s1 = positions[1].map((pos) => p1.indexOf(pos)).sort((a, b) => a - b);
|
|
184
|
+
const d1 = packSubset(s1);
|
|
185
|
+
// Remaining 6 positions
|
|
186
|
+
const p2 = [];
|
|
187
|
+
const used1 = new Set(positions[1]);
|
|
188
|
+
for (let i = 0; i < p1.length; i++) {
|
|
189
|
+
if (!used1.has(p1[i]))
|
|
190
|
+
p2.push(p1[i]);
|
|
191
|
+
}
|
|
192
|
+
// 3. Color 2 positions mapped into p2 index space (0..5)
|
|
193
|
+
const s2 = positions[2].map((pos) => p2.indexOf(pos)).sort((a, b) => a - b);
|
|
194
|
+
const d2 = packSubset(s2);
|
|
195
|
+
return d0 * (nCr(9, 3) * nCr(6, 3)) + d1 * nCr(6, 3) + d2;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Unpack a center orbit rank in [0, 369599] into 12 piece indices (0..11).
|
|
199
|
+
*/
|
|
200
|
+
function unpackCenterOrbit(rank, target) {
|
|
201
|
+
const centers = target ? target : new Array(12);
|
|
202
|
+
centers.length = 12;
|
|
203
|
+
const C93_C63 = nCr(9, 3) * nCr(6, 3); // 84 * 20 = 1680
|
|
204
|
+
const C63 = nCr(6, 3); // 20
|
|
205
|
+
const d0 = Math.floor(rank / C93_C63);
|
|
206
|
+
let rem = rank % C93_C63;
|
|
207
|
+
const d1 = Math.floor(rem / C63);
|
|
208
|
+
const d2 = rem % C63;
|
|
209
|
+
const s0 = [];
|
|
210
|
+
unpackSubset(s0, 3, d0);
|
|
211
|
+
const s1 = [];
|
|
212
|
+
unpackSubset(s1, 3, d1);
|
|
213
|
+
const s2 = [];
|
|
214
|
+
unpackSubset(s2, 3, d2);
|
|
215
|
+
// Available positions pool
|
|
216
|
+
const pool = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
|
217
|
+
// Assign color 0 (piece indices 0, 1, 2)
|
|
218
|
+
for (let i = 0; i < 3; i++) {
|
|
219
|
+
const pos = s0[i];
|
|
220
|
+
centers[pos] = i; // 0, 1, 2
|
|
221
|
+
}
|
|
222
|
+
const remaining1 = pool.filter((p) => !s0.includes(p));
|
|
223
|
+
// Assign color 1 (piece indices 3, 4, 5)
|
|
224
|
+
const pos1 = s1.map((idx) => remaining1[idx]);
|
|
225
|
+
for (let i = 0; i < 3; i++) {
|
|
226
|
+
centers[pos1[i]] = 3 + i; // 3, 4, 5
|
|
227
|
+
}
|
|
228
|
+
const remaining2 = remaining1.filter((p) => !pos1.includes(p));
|
|
229
|
+
// Assign color 2 (piece indices 6, 7, 8)
|
|
230
|
+
const pos2 = s2.map((idx) => remaining2[idx]);
|
|
231
|
+
for (let i = 0; i < 3; i++) {
|
|
232
|
+
centers[pos2[i]] = 6 + i; // 6, 7, 8
|
|
233
|
+
}
|
|
234
|
+
const remaining3 = remaining2.filter((p) => !pos2.includes(p));
|
|
235
|
+
// Assign color 3 (piece indices 9, 10, 11)
|
|
236
|
+
for (let i = 0; i < 3; i++) {
|
|
237
|
+
centers[remaining3[i]] = 9 + i; // 9, 10, 11
|
|
238
|
+
}
|
|
239
|
+
return centers;
|
|
240
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toFaceCubeArray = toFaceCubeArray;
|
|
4
|
+
exports.toFtoFacelets = toFtoFacelets;
|
|
5
|
+
exports.formatFtoFacelets = formatFtoFacelets;
|
|
6
|
+
const FACE_NAMES = ["U", "F", "BR", "BL", "D", "B", "R", "L"];
|
|
7
|
+
const U = 0, F = 9, r = 18, l = 27, D = 36, B = 45, R = 54, L = 63;
|
|
8
|
+
const cornFacelets = [
|
|
9
|
+
[U + 0, R + 0, F + 0, L + 0],
|
|
10
|
+
[U + 4, B + 8, r + 4, R + 8],
|
|
11
|
+
[U + 8, L + 4, l + 8, B + 4],
|
|
12
|
+
[l + 0, D + 0, r + 0, B + 0],
|
|
13
|
+
[F + 4, D + 8, l + 4, L + 8],
|
|
14
|
+
[r + 8, D + 4, F + 8, R + 4]
|
|
15
|
+
];
|
|
16
|
+
const edgeFacelets = [
|
|
17
|
+
[U + 1, R + 3],
|
|
18
|
+
[U + 3, L + 1],
|
|
19
|
+
[U + 6, B + 6],
|
|
20
|
+
[l + 1, D + 3],
|
|
21
|
+
[r + 3, D + 1],
|
|
22
|
+
[F + 6, D + 6],
|
|
23
|
+
[F + 3, R + 1],
|
|
24
|
+
[F + 1, L + 3],
|
|
25
|
+
[l + 6, L + 6],
|
|
26
|
+
[l + 3, B + 1],
|
|
27
|
+
[r + 1, B + 3],
|
|
28
|
+
[r + 6, R + 6]
|
|
29
|
+
];
|
|
30
|
+
const ctufFacelets = [
|
|
31
|
+
U + 2, U + 5, U + 7,
|
|
32
|
+
F + 2, F + 5, F + 7,
|
|
33
|
+
r + 2, r + 5, r + 7,
|
|
34
|
+
l + 2, l + 5, l + 7
|
|
35
|
+
];
|
|
36
|
+
const ctrlFacelets = [
|
|
37
|
+
D + 2, D + 5, D + 7,
|
|
38
|
+
B + 2, B + 5, B + 7,
|
|
39
|
+
L + 2, L + 5, L + 7,
|
|
40
|
+
R + 2, R + 5, R + 7
|
|
41
|
+
];
|
|
42
|
+
function fillFacelet(faceletMap, f, perm, ori, divcol) {
|
|
43
|
+
for (let i = 0; i < faceletMap.length; i++) {
|
|
44
|
+
const cubie = faceletMap[i];
|
|
45
|
+
const p = perm[i] === undefined ? i : perm[i];
|
|
46
|
+
if (typeof cubie === "number") {
|
|
47
|
+
const src = faceletMap[p];
|
|
48
|
+
f[cubie] = Math.floor((typeof src === "number" ? src : src[0]) / divcol);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const o = ori ? (ori[i] || 0) : 0;
|
|
52
|
+
const src = faceletMap[p];
|
|
53
|
+
for (let j = 0; j < cubie.length; j++) {
|
|
54
|
+
const destIndex = cubie[(j + o) % cubie.length];
|
|
55
|
+
const srcIndex = typeof src === "number" ? src : src[j];
|
|
56
|
+
f[destIndex] = Math.floor(srcIndex / divcol);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function toFaceCubeArray(state) {
|
|
61
|
+
const f = new Array(72);
|
|
62
|
+
const co = new Array(6);
|
|
63
|
+
for (let i = 0; i < 6; i++) {
|
|
64
|
+
co[i] = state.co[i] * 2;
|
|
65
|
+
}
|
|
66
|
+
fillFacelet(cornFacelets, f, state.cp, co, 9);
|
|
67
|
+
fillFacelet(edgeFacelets, f, state.ep, null, 9);
|
|
68
|
+
fillFacelet(ctufFacelets, f, state.uf, null, 9);
|
|
69
|
+
fillFacelet(ctrlFacelets, f, state.rl, null, 9);
|
|
70
|
+
return f;
|
|
71
|
+
}
|
|
72
|
+
function toFtoFacelets(state) {
|
|
73
|
+
const faceArray = toFaceCubeArray(state);
|
|
74
|
+
const getFaceStickers = (offset) => {
|
|
75
|
+
const stickers = new Array(9);
|
|
76
|
+
for (let i = 0; i < 9; i++) {
|
|
77
|
+
const colorVal = faceArray[offset + i];
|
|
78
|
+
stickers[i] = FACE_NAMES[colorVal] ?? "U";
|
|
79
|
+
}
|
|
80
|
+
return stickers;
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
U: getFaceStickers(U),
|
|
84
|
+
F: getFaceStickers(F),
|
|
85
|
+
BR: getFaceStickers(r),
|
|
86
|
+
BL: getFaceStickers(l),
|
|
87
|
+
D: getFaceStickers(D),
|
|
88
|
+
B: getFaceStickers(B),
|
|
89
|
+
R: getFaceStickers(R),
|
|
90
|
+
L: getFaceStickers(L)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function formatFtoFacelets(facelets) {
|
|
94
|
+
return [
|
|
95
|
+
facelets.U.join(""),
|
|
96
|
+
facelets.D.join(""),
|
|
97
|
+
facelets.F.join(""),
|
|
98
|
+
facelets.B.join(""),
|
|
99
|
+
facelets.L.join(""),
|
|
100
|
+
facelets.BR.join(""),
|
|
101
|
+
facelets.R.join(""),
|
|
102
|
+
facelets.BL.join("")
|
|
103
|
+
].join(" ");
|
|
104
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSupportedEvents = exports.getEventInfo = exports.generateScrambles = exports.generateScramble = exports.generateFtoScramble = exports.ftoScrambleGenerator = exports.isFtoSolverInitialized = exports.initFtoSolver = exports.solveFto = exports.generateRandomFtoState = exports.isTrivialFtoState = exports.validateFtoState = exports.unpackCenterOrbit = exports.packCenterOrbit = exports.unpackCornerOrientation = exports.packCornerOrientation = exports.unpackEvenPerm = exports.packEvenPerm = exports.unpackSubset = exports.packSubset = exports.getPermutationParity = exports.nCr = exports.formatFtoFacelets = exports.toFtoFacelets = exports.toFaceCubeArray = exports.isRedundantFtoMove = exports.applyFtoAlgorithm = exports.applyFtoMove = exports.formatFtoAlgorithm = exports.parseFtoAlgorithm = exports.invertFtoAlgorithm = exports.invertFtoMove = exports.getFtoMoveFace = exports.FTO_MOVE_MAP = exports.isSolvedFtoState = exports.statesEqual = exports.cloneFtoState = exports.createSolvedFtoState = exports.FtoCubie = exports.FTO_CENTER_ORBIT_STATES = exports.FTO_EDGE_PERM_STATES = exports.FTO_CORNER_ORI_STATES = exports.FTO_CORNER_PERM_STATES = exports.FTO_CENTER_ORBIT_COUNT = exports.FTO_EDGE_COUNT = exports.FTO_CORNER_COUNT = exports.SCRAMBLE_LENGTH = exports.FTO_AXIS_MAP = exports.FTO_ALL_MOVES = exports.FTO_FACES = void 0;
|
|
4
|
+
exports.initializeScrambler = void 0;
|
|
5
|
+
const index_js_1 = require("../../core/index.js");
|
|
6
|
+
const scrambler_js_1 = require("./scrambler.js");
|
|
7
|
+
(0, index_js_1.registerScrambleGenerator)(scrambler_js_1.ftoScrambleGenerator);
|
|
8
|
+
var types_js_1 = require("./types.js");
|
|
9
|
+
Object.defineProperty(exports, "FTO_FACES", { enumerable: true, get: function () { return types_js_1.FTO_FACES; } });
|
|
10
|
+
Object.defineProperty(exports, "FTO_ALL_MOVES", { enumerable: true, get: function () { return types_js_1.FTO_ALL_MOVES; } });
|
|
11
|
+
Object.defineProperty(exports, "FTO_AXIS_MAP", { enumerable: true, get: function () { return types_js_1.FTO_AXIS_MAP; } });
|
|
12
|
+
Object.defineProperty(exports, "SCRAMBLE_LENGTH", { enumerable: true, get: function () { return types_js_1.SCRAMBLE_LENGTH; } });
|
|
13
|
+
Object.defineProperty(exports, "FTO_CORNER_COUNT", { enumerable: true, get: function () { return types_js_1.FTO_CORNER_COUNT; } });
|
|
14
|
+
Object.defineProperty(exports, "FTO_EDGE_COUNT", { enumerable: true, get: function () { return types_js_1.FTO_EDGE_COUNT; } });
|
|
15
|
+
Object.defineProperty(exports, "FTO_CENTER_ORBIT_COUNT", { enumerable: true, get: function () { return types_js_1.FTO_CENTER_ORBIT_COUNT; } });
|
|
16
|
+
Object.defineProperty(exports, "FTO_CORNER_PERM_STATES", { enumerable: true, get: function () { return types_js_1.FTO_CORNER_PERM_STATES; } });
|
|
17
|
+
Object.defineProperty(exports, "FTO_CORNER_ORI_STATES", { enumerable: true, get: function () { return types_js_1.FTO_CORNER_ORI_STATES; } });
|
|
18
|
+
Object.defineProperty(exports, "FTO_EDGE_PERM_STATES", { enumerable: true, get: function () { return types_js_1.FTO_EDGE_PERM_STATES; } });
|
|
19
|
+
Object.defineProperty(exports, "FTO_CENTER_ORBIT_STATES", { enumerable: true, get: function () { return types_js_1.FTO_CENTER_ORBIT_STATES; } });
|
|
20
|
+
var state_js_1 = require("./state.js");
|
|
21
|
+
Object.defineProperty(exports, "FtoCubie", { enumerable: true, get: function () { return state_js_1.FtoCubie; } });
|
|
22
|
+
Object.defineProperty(exports, "createSolvedFtoState", { enumerable: true, get: function () { return state_js_1.createSolvedFtoState; } });
|
|
23
|
+
Object.defineProperty(exports, "cloneFtoState", { enumerable: true, get: function () { return state_js_1.cloneFtoState; } });
|
|
24
|
+
Object.defineProperty(exports, "statesEqual", { enumerable: true, get: function () { return state_js_1.statesEqual; } });
|
|
25
|
+
Object.defineProperty(exports, "isSolvedFtoState", { enumerable: true, get: function () { return state_js_1.isSolvedFtoState; } });
|
|
26
|
+
var moves_js_1 = require("./moves.js");
|
|
27
|
+
Object.defineProperty(exports, "FTO_MOVE_MAP", { enumerable: true, get: function () { return moves_js_1.FTO_MOVE_MAP; } });
|
|
28
|
+
Object.defineProperty(exports, "getFtoMoveFace", { enumerable: true, get: function () { return moves_js_1.getFtoMoveFace; } });
|
|
29
|
+
Object.defineProperty(exports, "invertFtoMove", { enumerable: true, get: function () { return moves_js_1.invertFtoMove; } });
|
|
30
|
+
Object.defineProperty(exports, "invertFtoAlgorithm", { enumerable: true, get: function () { return moves_js_1.invertFtoAlgorithm; } });
|
|
31
|
+
Object.defineProperty(exports, "parseFtoAlgorithm", { enumerable: true, get: function () { return moves_js_1.parseFtoAlgorithm; } });
|
|
32
|
+
Object.defineProperty(exports, "formatFtoAlgorithm", { enumerable: true, get: function () { return moves_js_1.formatFtoAlgorithm; } });
|
|
33
|
+
Object.defineProperty(exports, "applyFtoMove", { enumerable: true, get: function () { return moves_js_1.applyFtoMove; } });
|
|
34
|
+
Object.defineProperty(exports, "applyFtoAlgorithm", { enumerable: true, get: function () { return moves_js_1.applyFtoAlgorithm; } });
|
|
35
|
+
Object.defineProperty(exports, "isRedundantFtoMove", { enumerable: true, get: function () { return moves_js_1.isRedundantFtoMove; } });
|
|
36
|
+
var facelets_js_1 = require("./facelets.js");
|
|
37
|
+
Object.defineProperty(exports, "toFaceCubeArray", { enumerable: true, get: function () { return facelets_js_1.toFaceCubeArray; } });
|
|
38
|
+
Object.defineProperty(exports, "toFtoFacelets", { enumerable: true, get: function () { return facelets_js_1.toFtoFacelets; } });
|
|
39
|
+
Object.defineProperty(exports, "formatFtoFacelets", { enumerable: true, get: function () { return facelets_js_1.formatFtoFacelets; } });
|
|
40
|
+
var coordinates_js_1 = require("./coordinates.js");
|
|
41
|
+
Object.defineProperty(exports, "nCr", { enumerable: true, get: function () { return coordinates_js_1.nCr; } });
|
|
42
|
+
Object.defineProperty(exports, "getPermutationParity", { enumerable: true, get: function () { return coordinates_js_1.getPermutationParity; } });
|
|
43
|
+
Object.defineProperty(exports, "packSubset", { enumerable: true, get: function () { return coordinates_js_1.packSubset; } });
|
|
44
|
+
Object.defineProperty(exports, "unpackSubset", { enumerable: true, get: function () { return coordinates_js_1.unpackSubset; } });
|
|
45
|
+
Object.defineProperty(exports, "packEvenPerm", { enumerable: true, get: function () { return coordinates_js_1.packEvenPerm; } });
|
|
46
|
+
Object.defineProperty(exports, "unpackEvenPerm", { enumerable: true, get: function () { return coordinates_js_1.unpackEvenPerm; } });
|
|
47
|
+
Object.defineProperty(exports, "packCornerOrientation", { enumerable: true, get: function () { return coordinates_js_1.packCornerOrientation; } });
|
|
48
|
+
Object.defineProperty(exports, "unpackCornerOrientation", { enumerable: true, get: function () { return coordinates_js_1.unpackCornerOrientation; } });
|
|
49
|
+
Object.defineProperty(exports, "packCenterOrbit", { enumerable: true, get: function () { return coordinates_js_1.packCenterOrbit; } });
|
|
50
|
+
Object.defineProperty(exports, "unpackCenterOrbit", { enumerable: true, get: function () { return coordinates_js_1.unpackCenterOrbit; } });
|
|
51
|
+
var validation_js_1 = require("./validation.js");
|
|
52
|
+
Object.defineProperty(exports, "validateFtoState", { enumerable: true, get: function () { return validation_js_1.validateFtoState; } });
|
|
53
|
+
Object.defineProperty(exports, "isTrivialFtoState", { enumerable: true, get: function () { return validation_js_1.isTrivialFtoState; } });
|
|
54
|
+
var random_state_js_1 = require("./random-state.js");
|
|
55
|
+
Object.defineProperty(exports, "generateRandomFtoState", { enumerable: true, get: function () { return random_state_js_1.generateRandomFtoState; } });
|
|
56
|
+
var index_js_2 = require("./solver/index.js");
|
|
57
|
+
Object.defineProperty(exports, "solveFto", { enumerable: true, get: function () { return index_js_2.solveFto; } });
|
|
58
|
+
Object.defineProperty(exports, "initFtoSolver", { enumerable: true, get: function () { return index_js_2.initFtoSolver; } });
|
|
59
|
+
Object.defineProperty(exports, "isFtoSolverInitialized", { enumerable: true, get: function () { return index_js_2.isFtoSolverInitialized; } });
|
|
60
|
+
var scrambler_js_2 = require("./scrambler.js");
|
|
61
|
+
Object.defineProperty(exports, "ftoScrambleGenerator", { enumerable: true, get: function () { return scrambler_js_2.ftoScrambleGenerator; } });
|
|
62
|
+
Object.defineProperty(exports, "generateFtoScramble", { enumerable: true, get: function () { return scrambler_js_2.generateFtoScramble; } });
|
|
63
|
+
var index_js_3 = require("../../core/index.js");
|
|
64
|
+
Object.defineProperty(exports, "generateScramble", { enumerable: true, get: function () { return index_js_3.generateScramble; } });
|
|
65
|
+
Object.defineProperty(exports, "generateScrambles", { enumerable: true, get: function () { return index_js_3.generateScrambles; } });
|
|
66
|
+
Object.defineProperty(exports, "getEventInfo", { enumerable: true, get: function () { return index_js_3.getEventInfo; } });
|
|
67
|
+
Object.defineProperty(exports, "getSupportedEvents", { enumerable: true, get: function () { return index_js_3.getSupportedEvents; } });
|
|
68
|
+
Object.defineProperty(exports, "initializeScrambler", { enumerable: true, get: function () { return index_js_3.initializeScrambler; } });
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FTO_MOVE_MAP = void 0;
|
|
4
|
+
exports.getFtoMoveFace = getFtoMoveFace;
|
|
5
|
+
exports.invertFtoMove = invertFtoMove;
|
|
6
|
+
exports.invertFtoAlgorithm = invertFtoAlgorithm;
|
|
7
|
+
exports.parseFtoAlgorithm = parseFtoAlgorithm;
|
|
8
|
+
exports.formatFtoAlgorithm = formatFtoAlgorithm;
|
|
9
|
+
exports.applyFtoMove = applyFtoMove;
|
|
10
|
+
exports.applyFtoAlgorithm = applyFtoAlgorithm;
|
|
11
|
+
exports.isRedundantFtoMove = isRedundantFtoMove;
|
|
12
|
+
const types_js_1 = require("./types.js");
|
|
13
|
+
const state_js_1 = require("./state.js");
|
|
14
|
+
const moveU = new state_js_1.FtoCubie([1, 2, 0, 3, 4, 5], [0, 0, 0, 0, 0, 0], [2, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11], [1, 2, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11], [0, 1, 2, 3, 6, 7, 11, 9, 8, 5, 10, 4]);
|
|
15
|
+
const moveF = new state_js_1.FtoCubie([4, 1, 2, 3, 5, 0], [1, 0, 0, 0, 1, 0], [0, 1, 2, 3, 4, 6, 7, 5, 8, 9, 10, 11], [0, 1, 2, 4, 5, 3, 6, 7, 8, 9, 10, 11], [0, 9, 10, 3, 4, 5, 2, 7, 1, 8, 6, 11]);
|
|
16
|
+
const moveBR = new state_js_1.FtoCubie([0, 5, 2, 1, 4, 3], [0, 1, 0, 0, 0, 1], [0, 1, 2, 3, 10, 5, 6, 7, 8, 9, 11, 4], [0, 1, 2, 3, 4, 5, 7, 8, 6, 9, 10, 11], [5, 3, 2, 11, 4, 10, 6, 7, 8, 9, 0, 1]);
|
|
17
|
+
const moveBL = new state_js_1.FtoCubie([0, 1, 3, 4, 2, 5], [0, 0, 1, 1, 0, 0], [0, 1, 2, 8, 4, 5, 6, 7, 9, 3, 10, 11], [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 9], [8, 1, 7, 2, 0, 5, 6, 3, 4, 9, 10, 11]);
|
|
18
|
+
const moveD = new state_js_1.FtoCubie([0, 1, 2, 5, 3, 4], [0, 0, 0, 0, 0, 0], [0, 1, 2, 4, 5, 3, 6, 7, 8, 9, 10, 11], [0, 1, 2, 3, 9, 10, 5, 7, 4, 8, 6, 11], [1, 2, 0, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
|
|
19
|
+
const moveB = new state_js_1.FtoCubie([0, 3, 1, 2, 4, 5], [0, 1, 1, 0, 0, 0], [0, 1, 10, 3, 4, 5, 6, 7, 8, 2, 9, 11], [0, 6, 7, 3, 4, 5, 11, 9, 8, 2, 10, 1], [0, 1, 2, 4, 5, 3, 6, 7, 8, 9, 10, 11]);
|
|
20
|
+
const moveR = new state_js_1.FtoCubie([5, 0, 2, 3, 4, 1], [1, 1, 0, 0, 0, 0], [6, 1, 2, 3, 4, 5, 11, 7, 8, 9, 10, 0], [5, 3, 2, 8, 4, 7, 6, 0, 1, 9, 10, 11], [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 9]);
|
|
21
|
+
const moveL = new state_js_1.FtoCubie([2, 1, 4, 3, 0, 5], [1, 0, 1, 0, 0, 0], [0, 8, 2, 3, 4, 5, 6, 1, 7, 9, 10, 11], [11, 1, 10, 2, 0, 5, 6, 7, 8, 9, 3, 4], [0, 1, 2, 3, 4, 5, 7, 8, 6, 9, 10, 11]);
|
|
22
|
+
exports.FTO_MOVE_MAP = {
|
|
23
|
+
U: moveU,
|
|
24
|
+
"U'": state_js_1.FtoCubie.multiply(moveU, moveU),
|
|
25
|
+
F: moveF,
|
|
26
|
+
"F'": state_js_1.FtoCubie.multiply(moveF, moveF),
|
|
27
|
+
BR: moveBR,
|
|
28
|
+
"BR'": state_js_1.FtoCubie.multiply(moveBR, moveBR),
|
|
29
|
+
BL: moveBL,
|
|
30
|
+
"BL'": state_js_1.FtoCubie.multiply(moveBL, moveBL),
|
|
31
|
+
D: moveD,
|
|
32
|
+
"D'": state_js_1.FtoCubie.multiply(moveD, moveD),
|
|
33
|
+
B: moveB,
|
|
34
|
+
"B'": state_js_1.FtoCubie.multiply(moveB, moveB),
|
|
35
|
+
R: moveR,
|
|
36
|
+
"R'": state_js_1.FtoCubie.multiply(moveR, moveR),
|
|
37
|
+
L: moveL,
|
|
38
|
+
"L'": state_js_1.FtoCubie.multiply(moveL, moveL)
|
|
39
|
+
};
|
|
40
|
+
function getFtoMoveFace(move) {
|
|
41
|
+
const base = move.replace(/'$/, "");
|
|
42
|
+
return base;
|
|
43
|
+
}
|
|
44
|
+
function invertFtoMove(move) {
|
|
45
|
+
if (move.endsWith("'")) {
|
|
46
|
+
return move.slice(0, -1);
|
|
47
|
+
}
|
|
48
|
+
return `${move}'`;
|
|
49
|
+
}
|
|
50
|
+
function invertFtoAlgorithm(moves) {
|
|
51
|
+
const inverted = new Array(moves.length);
|
|
52
|
+
for (let i = 0; i < moves.length; i++) {
|
|
53
|
+
inverted[moves.length - 1 - i] = invertFtoMove(moves[i]);
|
|
54
|
+
}
|
|
55
|
+
return inverted;
|
|
56
|
+
}
|
|
57
|
+
function parseFtoAlgorithm(algorithm) {
|
|
58
|
+
const tokens = algorithm.trim().split(/\s+/).filter(Boolean);
|
|
59
|
+
const result = [];
|
|
60
|
+
for (const token of tokens) {
|
|
61
|
+
if (token in exports.FTO_MOVE_MAP) {
|
|
62
|
+
result.push(token);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw new Error(`Invalid FTO move: ${token}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
function formatFtoAlgorithm(moves) {
|
|
71
|
+
return moves.join(" ");
|
|
72
|
+
}
|
|
73
|
+
function applyFtoMove(state, move) {
|
|
74
|
+
const moveCubie = exports.FTO_MOVE_MAP[move];
|
|
75
|
+
if (!moveCubie) {
|
|
76
|
+
throw new Error(`Unsupported FTO move: ${move}`);
|
|
77
|
+
}
|
|
78
|
+
return state_js_1.FtoCubie.multiply(state, moveCubie);
|
|
79
|
+
}
|
|
80
|
+
function applyFtoAlgorithm(state, algorithm) {
|
|
81
|
+
const moves = typeof algorithm === "string" ? parseFtoAlgorithm(algorithm) : algorithm;
|
|
82
|
+
let current = state;
|
|
83
|
+
for (const move of moves) {
|
|
84
|
+
current = applyFtoMove(current, move);
|
|
85
|
+
}
|
|
86
|
+
return current;
|
|
87
|
+
}
|
|
88
|
+
const FTO_AXIS_ORDER = {
|
|
89
|
+
U: 0,
|
|
90
|
+
D: 1,
|
|
91
|
+
F: 0,
|
|
92
|
+
B: 1,
|
|
93
|
+
L: 0,
|
|
94
|
+
BR: 1,
|
|
95
|
+
R: 0,
|
|
96
|
+
BL: 1
|
|
97
|
+
};
|
|
98
|
+
function isRedundantFtoMove(moves, newMove) {
|
|
99
|
+
if (moves.length === 0)
|
|
100
|
+
return false;
|
|
101
|
+
const newFace = getFtoMoveFace(newMove);
|
|
102
|
+
const newAxis = types_js_1.FTO_AXIS_MAP[newFace];
|
|
103
|
+
const lastMove = moves[moves.length - 1];
|
|
104
|
+
const lastFace = getFtoMoveFace(lastMove);
|
|
105
|
+
// No same face consecutively
|
|
106
|
+
if (lastFace === newFace)
|
|
107
|
+
return true;
|
|
108
|
+
const lastAxis = types_js_1.FTO_AXIS_MAP[lastFace];
|
|
109
|
+
// Different axis is always allowed
|
|
110
|
+
if (newAxis !== lastAxis)
|
|
111
|
+
return false;
|
|
112
|
+
// Same axis (commutes): enforce canonical order
|
|
113
|
+
// to avoid duplicates like [D, U] vs [U, D] and prevent sequences like [U, D, U]
|
|
114
|
+
if (moves.length >= 2) {
|
|
115
|
+
const prevMove = moves[moves.length - 2];
|
|
116
|
+
const prevFace = getFtoMoveFace(prevMove);
|
|
117
|
+
if (types_js_1.FTO_AXIS_MAP[prevFace] === newAxis) {
|
|
118
|
+
return true; // Already 2 moves on this axis in a row
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Canonical ordering for commuting faces on the same axis
|
|
122
|
+
if (FTO_AXIS_ORDER[newFace] <= FTO_AXIS_ORDER[lastFace]) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Uniform random-state generation for Face-Turning Octahedron (FTO).
|
|
4
|
+
*
|
|
5
|
+
* Samples uniformly from the 3.14 x 10^22 reachable states:
|
|
6
|
+
* - Corner permutation in A_6 (360)
|
|
7
|
+
* - Corner orientation in Z_2^5 with sum ≡ 0 (mod 2) (32)
|
|
8
|
+
* - Edge permutation in A_12 (239,500,800)
|
|
9
|
+
* - Orbit 1 centers (uf): multiset arrangement C(12,3)*C(9,3)*C(6,3) (369,600)
|
|
10
|
+
* - Orbit 2 centers (rl): multiset arrangement C(12,3)*C(9,3)*C(6,3) (369,600)
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.generateRandomFtoState = generateRandomFtoState;
|
|
14
|
+
const index_js_1 = require("../../random/index.js");
|
|
15
|
+
const types_js_1 = require("./types.js");
|
|
16
|
+
const state_js_1 = require("./state.js");
|
|
17
|
+
const coordinates_js_1 = require("./coordinates.js");
|
|
18
|
+
const validation_js_1 = require("./validation.js");
|
|
19
|
+
/**
|
|
20
|
+
* Generates a legal, uniformly-sampled random FTO state.
|
|
21
|
+
*/
|
|
22
|
+
function generateRandomFtoState(options = {}) {
|
|
23
|
+
const random = (0, index_js_1.createRandomSource)(options.seed);
|
|
24
|
+
const rejectTrivial = options.rejectTrivial ?? true;
|
|
25
|
+
for (let attempt = 0; attempt < 100; attempt++) {
|
|
26
|
+
const cpRank = random.nextInt(types_js_1.FTO_CORNER_PERM_STATES);
|
|
27
|
+
const coRank = random.nextInt(types_js_1.FTO_CORNER_ORI_STATES);
|
|
28
|
+
const epRank = random.nextInt(types_js_1.FTO_EDGE_PERM_STATES);
|
|
29
|
+
const ufRank = random.nextInt(types_js_1.FTO_CENTER_ORBIT_STATES);
|
|
30
|
+
const rlRank = random.nextInt(types_js_1.FTO_CENTER_ORBIT_STATES);
|
|
31
|
+
const cp = (0, coordinates_js_1.unpackEvenPerm)(types_js_1.FTO_CORNER_COUNT, cpRank);
|
|
32
|
+
const co = (0, coordinates_js_1.unpackCornerOrientation)(coRank);
|
|
33
|
+
const ep = (0, coordinates_js_1.unpackEvenPerm)(types_js_1.FTO_EDGE_COUNT, epRank);
|
|
34
|
+
const uf = (0, coordinates_js_1.unpackCenterOrbit)(ufRank);
|
|
35
|
+
const rl = (0, coordinates_js_1.unpackCenterOrbit)(rlRank);
|
|
36
|
+
const state = new state_js_1.FtoCubie(cp, co, ep, uf, rl);
|
|
37
|
+
if (rejectTrivial && (0, validation_js_1.isTrivialFtoState)(state)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
return state;
|
|
41
|
+
}
|
|
42
|
+
throw new Error("Unable to generate a non-trivial random FTO state.");
|
|
43
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ftoScrambleGenerator = void 0;
|
|
4
|
+
exports.generateFtoScramble = generateFtoScramble;
|
|
5
|
+
const index_js_1 = require("../../random/index.js");
|
|
6
|
+
const moves_js_1 = require("./moves.js");
|
|
7
|
+
const state_js_1 = require("./state.js");
|
|
8
|
+
const facelets_js_1 = require("./facelets.js");
|
|
9
|
+
const index_js_2 = require("./solver/index.js");
|
|
10
|
+
exports.ftoScrambleGenerator = {
|
|
11
|
+
info: {
|
|
12
|
+
eventId: "fto",
|
|
13
|
+
name: "Face-Turning Octahedron",
|
|
14
|
+
puzzle: "fto",
|
|
15
|
+
quality: "random-state",
|
|
16
|
+
generator: "fto-three-phase",
|
|
17
|
+
description: "Random-state Face-Turning Octahedron scramble generated by a 3-phase reduction solver."
|
|
18
|
+
},
|
|
19
|
+
generate(options = {}) {
|
|
20
|
+
return generateFtoScramble(options);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function generateFtoScramble(options = {}) {
|
|
24
|
+
const random = (0, index_js_1.createRandomSource)(options.seed);
|
|
25
|
+
const { scramble, moves, state, facelets } = (0, index_js_2.generateFtoRandomState)(() => random.next());
|
|
26
|
+
if (!options.skipValidation) {
|
|
27
|
+
const replayed = (0, moves_js_1.applyFtoAlgorithm)((0, state_js_1.createSolvedFtoState)(), moves);
|
|
28
|
+
if (!replayed.isEqual(state)) {
|
|
29
|
+
throw new Error("Generated FTO scramble does not reproduce the target random state.");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const solutionMoves = (0, moves_js_1.invertFtoAlgorithm)(moves);
|
|
33
|
+
const faceletString = (0, facelets_js_1.formatFtoFacelets)(facelets);
|
|
34
|
+
const result = {
|
|
35
|
+
eventId: "fto",
|
|
36
|
+
scramble,
|
|
37
|
+
moves,
|
|
38
|
+
quality: "random-state",
|
|
39
|
+
generator: "fto-three-phase",
|
|
40
|
+
metadata: {
|
|
41
|
+
totalMoves: moves.length,
|
|
42
|
+
solutionDepth: solutionMoves.length,
|
|
43
|
+
solutionMoves,
|
|
44
|
+
state,
|
|
45
|
+
facelets,
|
|
46
|
+
faceletString
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
if (options.seed !== undefined) {
|
|
50
|
+
result.seed = options.seed;
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|