cubegin 0.0.1
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/CHANGELOG.md +17 -0
- package/LICENSE +674 -0
- package/NOTICE +11 -0
- package/README.md +49 -0
- package/dist/scramble-core/src/batch.mjs +18 -0
- package/dist/scramble-core/src/generator.d.mts +35 -0
- package/dist/scramble-core/src/generator.mjs +136 -0
- package/dist/scramble-core/src/generators/clock.d.mts +11 -0
- package/dist/scramble-core/src/generators/clock.mjs +32 -0
- package/dist/scramble-core/src/generators/cube-random-turns.d.mts +11 -0
- package/dist/scramble-core/src/generators/cube-random-turns.mjs +54 -0
- package/dist/scramble-core/src/generators/four-by-four.d.mts +14 -0
- package/dist/scramble-core/src/generators/four-by-four.mjs +43 -0
- package/dist/scramble-core/src/generators/megaminx.d.mts +11 -0
- package/dist/scramble-core/src/generators/megaminx.mjs +18 -0
- package/dist/scramble-core/src/generators/pyraminx.d.mts +11 -0
- package/dist/scramble-core/src/generators/pyraminx.mjs +17 -0
- package/dist/scramble-core/src/generators/skewb.d.mts +11 -0
- package/dist/scramble-core/src/generators/skewb.mjs +17 -0
- package/dist/scramble-core/src/generators/square1.d.mts +11 -0
- package/dist/scramble-core/src/generators/square1.mjs +28 -0
- package/dist/scramble-core/src/generators/three-by-three.d.mts +25 -0
- package/dist/scramble-core/src/generators/three-by-three.mjs +85 -0
- package/dist/scramble-core/src/generators/two-by-two.d.mts +11 -0
- package/dist/scramble-core/src/generators/two-by-two.mjs +17 -0
- package/dist/scramble-core/src/random-source.d.mts +7 -0
- package/dist/scramble-core/src/random-source.mjs +8 -0
- package/dist/scramble-core/src/solvers/min2phase/coord-cube.mjs +10 -0
- package/dist/scramble-core/src/solvers/min2phase/cubie-cube.mjs +246 -0
- package/dist/scramble-core/src/solvers/min2phase/engine.mjs +1281 -0
- package/dist/scramble-core/src/solvers/min2phase/search-wca.mjs +21 -0
- package/dist/scramble-core/src/solvers/min2phase/search.mjs +25 -0
- package/dist/scramble-core/src/solvers/min2phase/tools.mjs +169 -0
- package/dist/scramble-core/src/solvers/min2phase/util.mjs +30 -0
- package/dist/scramble-core/src/solvers/pyraminx-solver.d.mts +17 -0
- package/dist/scramble-core/src/solvers/pyraminx-solver.mjs +350 -0
- package/dist/scramble-core/src/solvers/skewb-solver.d.mts +15 -0
- package/dist/scramble-core/src/solvers/skewb-solver.mjs +399 -0
- package/dist/scramble-core/src/solvers/sq12phase/full-cube.mjs +212 -0
- package/dist/scramble-core/src/solvers/sq12phase/search.mjs +520 -0
- package/dist/scramble-core/src/solvers/sq12phase/shape.mjs +214 -0
- package/dist/scramble-core/src/solvers/sq12phase/square.mjs +135 -0
- package/dist/scramble-core/src/solvers/threephase/center.mjs +798 -0
- package/dist/scramble-core/src/solvers/threephase/edge.mjs +632 -0
- package/dist/scramble-core/src/solvers/threephase/full-cube.mjs +554 -0
- package/dist/scramble-core/src/solvers/threephase/search.mjs +262 -0
- package/dist/scramble-core/src/solvers/threephase/tables.mjs +201 -0
- package/dist/scramble-core/src/solvers/two-by-two-solver.d.mts +15 -0
- package/dist/scramble-core/src/solvers/two-by-two-solver.mjs +298 -0
- package/dist/scramble-core.d.mts +15 -0
- package/dist/scramble-core.mjs +15 -0
- package/dist/scramble-image/src/color.d.mts +12 -0
- package/dist/scramble-image/src/color.mjs +11 -0
- package/dist/scramble-image/src/render.d.mts +10 -0
- package/dist/scramble-image/src/render.mjs +71 -0
- package/dist/scramble-image/src/renderers/clock.d.mts +6 -0
- package/dist/scramble-image/src/renderers/clock.mjs +145 -0
- package/dist/scramble-image/src/renderers/cube-isometric.d.mts +8 -0
- package/dist/scramble-image/src/renderers/cube-isometric.mjs +204 -0
- package/dist/scramble-image/src/renderers/cube-net.d.mts +8 -0
- package/dist/scramble-image/src/renderers/cube-net.mjs +52 -0
- package/dist/scramble-image/src/renderers/megaminx-isometric.d.mts +9 -0
- package/dist/scramble-image/src/renderers/megaminx-isometric.mjs +320 -0
- package/dist/scramble-image/src/renderers/megaminx.d.mts +9 -0
- package/dist/scramble-image/src/renderers/megaminx.mjs +173 -0
- package/dist/scramble-image/src/renderers/pyraminx-isometric.d.mts +9 -0
- package/dist/scramble-image/src/renderers/pyraminx-isometric.mjs +185 -0
- package/dist/scramble-image/src/renderers/pyraminx.d.mts +9 -0
- package/dist/scramble-image/src/renderers/pyraminx.mjs +111 -0
- package/dist/scramble-image/src/renderers/skewb-isometric.d.mts +9 -0
- package/dist/scramble-image/src/renderers/skewb-isometric.mjs +233 -0
- package/dist/scramble-image/src/renderers/skewb.d.mts +9 -0
- package/dist/scramble-image/src/renderers/skewb.mjs +187 -0
- package/dist/scramble-image/src/renderers/square1.d.mts +10 -0
- package/dist/scramble-image/src/renderers/square1.mjs +253 -0
- package/dist/scramble-image/src/svg/svg-document.d.mts +6 -0
- package/dist/scramble-image/src/svg/svg-document.mjs +7 -0
- package/dist/scramble-image/src/svg/svg-elements.d.mts +15 -0
- package/dist/scramble-image/src/svg/svg-elements.mjs +25 -0
- package/dist/scramble-image/src/svg/svg-serialize.mjs +29 -0
- package/dist/scramble-image.d.mts +15 -0
- package/dist/scramble-image.mjs +15 -0
- package/dist/scramble-puzzle/src/algorithm.d.mts +8 -0
- package/dist/scramble-puzzle/src/algorithm.mjs +16 -0
- package/dist/scramble-puzzle/src/algorithm2.mjs +16 -0
- package/dist/scramble-puzzle/src/clock/clock-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/clock/clock-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/clock/clock-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/clock/clock-parser.d.mts +18 -0
- package/dist/scramble-puzzle/src/clock/clock-parser.mjs +35 -0
- package/dist/scramble-puzzle/src/clock/clock-parser2.mjs +35 -0
- package/dist/scramble-puzzle/src/clock/clock-state.d.mts +8 -0
- package/dist/scramble-puzzle/src/clock/clock-state.mjs +212 -0
- package/dist/scramble-puzzle/src/clock/clock-state2.d.mts +13 -0
- package/dist/scramble-puzzle/src/clock/clock-state2.mjs +212 -0
- package/dist/scramble-puzzle/src/cube/cube-definition.d.mts +9 -0
- package/dist/scramble-puzzle/src/cube/cube-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/cube/cube-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/cube/cube-move.d.mts +4 -0
- package/dist/scramble-puzzle/src/cube/cube-move2.d.mts +17 -0
- package/dist/scramble-puzzle/src/cube/cube-parser.d.mts +7 -0
- package/dist/scramble-puzzle/src/cube/cube-parser.mjs +60 -0
- package/dist/scramble-puzzle/src/cube/cube-parser2.mjs +60 -0
- package/dist/scramble-puzzle/src/cube/cube-state.d.mts +12 -0
- package/dist/scramble-puzzle/src/cube/cube-state.mjs +187 -0
- package/dist/scramble-puzzle/src/cube/cube-state2.d.mts +15 -0
- package/dist/scramble-puzzle/src/cube/cube-state2.mjs +187 -0
- package/dist/scramble-puzzle/src/errors.d.mts +15 -0
- package/dist/scramble-puzzle/src/errors.mjs +24 -0
- package/dist/scramble-puzzle/src/errors2.mjs +30 -0
- package/dist/scramble-puzzle/src/events.d.mts +5 -0
- package/dist/scramble-puzzle/src/events.mjs +90 -0
- package/dist/scramble-puzzle/src/events2.d.mts +98 -0
- package/dist/scramble-puzzle/src/events2.mjs +109 -0
- package/dist/scramble-puzzle/src/index.mjs +22 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser.d.mts +5 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser.mjs +57 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.d.mts +20 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.mjs +57 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state.d.mts +9 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state.mjs +112 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state2.d.mts +14 -0
- package/dist/scramble-puzzle/src/megaminx/megaminx-state2.mjs +112 -0
- package/dist/scramble-puzzle/src/puzzle-definition.d.mts +19 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.d.mts +5 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.mjs +34 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.d.mts +21 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.mjs +34 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.d.mts +11 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.mjs +90 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.d.mts +14 -0
- package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.mjs +90 -0
- package/dist/scramble-puzzle/src/registry.d.mts +11 -0
- package/dist/scramble-puzzle/src/registry.mjs +13 -0
- package/dist/scramble-puzzle/src/skewb/skewb-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/skewb/skewb-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/skewb/skewb-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser.d.mts +5 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser.mjs +33 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser2.d.mts +14 -0
- package/dist/scramble-puzzle/src/skewb/skewb-parser2.mjs +33 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state.d.mts +11 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state.mjs +75 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state2.d.mts +14 -0
- package/dist/scramble-puzzle/src/skewb/skewb-state2.mjs +75 -0
- package/dist/scramble-puzzle/src/square1/square1-definition.d.mts +8 -0
- package/dist/scramble-puzzle/src/square1/square1-definition.mjs +18 -0
- package/dist/scramble-puzzle/src/square1/square1-definition2.mjs +18 -0
- package/dist/scramble-puzzle/src/square1/square1-parser.d.mts +17 -0
- package/dist/scramble-puzzle/src/square1/square1-parser.mjs +43 -0
- package/dist/scramble-puzzle/src/square1/square1-parser2.mjs +47 -0
- package/dist/scramble-puzzle/src/square1/square1-state.d.mts +9 -0
- package/dist/scramble-puzzle/src/square1/square1-state.mjs +115 -0
- package/dist/scramble-puzzle/src/square1/square1-state2.d.mts +21 -0
- package/dist/scramble-puzzle/src/square1/square1-state2.mjs +115 -0
- package/dist/scramble-puzzle.d.mts +25 -0
- package/dist/scramble-puzzle.mjs +23 -0
- package/package.json +37 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { axisForRestriction, splitAlgorithm } from "../solvers/min2phase/util.mjs";
|
|
2
|
+
import { SearchWCA } from "../solvers/min2phase/search-wca.mjs";
|
|
3
|
+
import { randomCube } from "../solvers/min2phase/tools.mjs";
|
|
4
|
+
//#region .build/vendor/scramble-core/src/generators/three-by-three.ts
|
|
5
|
+
const THREE_BY_THREE_MAX_SCRAMBLE_LENGTH = 21;
|
|
6
|
+
const THREE_BY_THREE_PROBE_MAX = 1e5;
|
|
7
|
+
const THREE_BY_THREE_PROBE_MIN = 0;
|
|
8
|
+
const THREE_BY_THREE_MAX_ATTEMPTS = 20;
|
|
9
|
+
const FMC_PADDING = "R' U' F";
|
|
10
|
+
const ORIENTATION_SEQUENCES = [
|
|
11
|
+
[],
|
|
12
|
+
["Uw"],
|
|
13
|
+
["Uw2"],
|
|
14
|
+
["Uw'"],
|
|
15
|
+
["Rw"],
|
|
16
|
+
["Rw", "Uw"],
|
|
17
|
+
["Rw", "Uw2"],
|
|
18
|
+
["Rw", "Uw'"],
|
|
19
|
+
["Rw2"],
|
|
20
|
+
["Rw2", "Uw"],
|
|
21
|
+
["Rw2", "Uw2"],
|
|
22
|
+
["Rw2", "Uw'"],
|
|
23
|
+
["Rw'"],
|
|
24
|
+
["Rw'", "Uw"],
|
|
25
|
+
["Rw'", "Uw2"],
|
|
26
|
+
["Rw'", "Uw'"],
|
|
27
|
+
["Fw"],
|
|
28
|
+
["Fw", "Uw"],
|
|
29
|
+
["Fw", "Uw2"],
|
|
30
|
+
["Fw", "Uw'"],
|
|
31
|
+
["Fw'"],
|
|
32
|
+
["Fw'", "Uw"],
|
|
33
|
+
["Fw'", "Uw2"],
|
|
34
|
+
["Fw'", "Uw'"]
|
|
35
|
+
];
|
|
36
|
+
const generateThreeByThreeScramble = ({ random }) => generateInverseSolution({ random });
|
|
37
|
+
const generateThreeByThreeNoInspectionScramble = ({ random }) => {
|
|
38
|
+
const orientation = chooseOrientation(random);
|
|
39
|
+
return [...splitAlgorithm(generateInverseSolution({
|
|
40
|
+
random,
|
|
41
|
+
lastAxisRestriction: orientation[0]?.[0] ?? null
|
|
42
|
+
})), ...orientation].join(" ");
|
|
43
|
+
};
|
|
44
|
+
const generateThreeByThreeFewestMovesScramble = ({ random }) => {
|
|
45
|
+
return `${FMC_PADDING} ${generateInverseSolution({
|
|
46
|
+
random,
|
|
47
|
+
firstAxisRestriction: "F",
|
|
48
|
+
lastAxisRestriction: "R"
|
|
49
|
+
})} ${FMC_PADDING}`;
|
|
50
|
+
};
|
|
51
|
+
const generateMultiBlindScramble = ({ random, cubeCount }) => {
|
|
52
|
+
validateCubeCount(cubeCount);
|
|
53
|
+
return Array.from({ length: cubeCount }, () => generateThreeByThreeNoInspectionScramble({ random })).join("\n");
|
|
54
|
+
};
|
|
55
|
+
const generateInverseSolution = ({ random, firstAxisRestriction, lastAxisRestriction }) => {
|
|
56
|
+
const search = new SearchWCA();
|
|
57
|
+
for (let attempt = 0; attempt < THREE_BY_THREE_MAX_ATTEMPTS; attempt += 1) {
|
|
58
|
+
const solution = search.solution(randomCube(random), THREE_BY_THREE_MAX_SCRAMBLE_LENGTH, THREE_BY_THREE_PROBE_MAX, THREE_BY_THREE_PROBE_MIN, 2, firstAxisRestriction, lastAxisRestriction).trim();
|
|
59
|
+
if (!solution.startsWith("Error")) {
|
|
60
|
+
if (satisfiesAxisRestrictions(solution, firstAxisRestriction, lastAxisRestriction)) return solution;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (solution !== "Error 7" && solution !== "Error 8") throw new Error(`@cubegin/scramble-core: min2phase returned ${solution}`);
|
|
64
|
+
}
|
|
65
|
+
throw new Error("@cubegin/scramble-core: min2phase could not find a 3x3 scramble within retry limit");
|
|
66
|
+
};
|
|
67
|
+
const satisfiesAxisRestrictions = (scramble, firstAxisRestriction, lastAxisRestriction) => {
|
|
68
|
+
const moves = splitAlgorithm(scramble);
|
|
69
|
+
return !violatesAxisRestriction(moves[0], firstAxisRestriction) && !violatesAxisRestriction(moves.at(-1), lastAxisRestriction);
|
|
70
|
+
};
|
|
71
|
+
const violatesAxisRestriction = (move, restriction) => {
|
|
72
|
+
if (move === void 0 || restriction === null || restriction === void 0) return false;
|
|
73
|
+
return axisForRestriction(move[0]) === axisForRestriction(restriction);
|
|
74
|
+
};
|
|
75
|
+
const chooseOrientation = (random) => {
|
|
76
|
+
const index = random.nextInt(ORIENTATION_SEQUENCES.length);
|
|
77
|
+
const orientation = ORIENTATION_SEQUENCES[index];
|
|
78
|
+
if (orientation === void 0) throw new RangeError(`@cubegin/scramble-core: random source returned ${index} for max ${ORIENTATION_SEQUENCES.length}`);
|
|
79
|
+
return orientation;
|
|
80
|
+
};
|
|
81
|
+
const validateCubeCount = (cubeCount) => {
|
|
82
|
+
if (!Number.isSafeInteger(cubeCount) || cubeCount <= 0) throw new Error("@cubegin/scramble-core: multi-blind cubeCount must be a positive safe integer");
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
export { generateMultiBlindScramble, generateThreeByThreeFewestMovesScramble, generateThreeByThreeNoInspectionScramble, generateThreeByThreeScramble };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RandomSource } from "../random-source.mjs";
|
|
2
|
+
|
|
3
|
+
//#region .build/vendor/scramble-core/src/generators/two-by-two.d.ts
|
|
4
|
+
interface TwoByTwoScrambleOptions {
|
|
5
|
+
random: RandomSource;
|
|
6
|
+
}
|
|
7
|
+
declare const generateTwoByTwoScramble: ({
|
|
8
|
+
random
|
|
9
|
+
}: TwoByTwoScrambleOptions) => string;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { TwoByTwoScrambleOptions, generateTwoByTwoScramble };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TwoByTwoSolver } from "../solvers/two-by-two-solver.mjs";
|
|
2
|
+
//#region .build/vendor/scramble-core/src/generators/two-by-two.ts
|
|
3
|
+
const ERROR_PREFIX = "@cubegin/scramble-core";
|
|
4
|
+
const SCRAMBLE_LENGTH = 11;
|
|
5
|
+
const WCA_MIN_SCRAMBLE_DISTANCE = 4;
|
|
6
|
+
const MAX_WCA_ATTEMPTS = 100;
|
|
7
|
+
const generateTwoByTwoScramble = ({ random }) => {
|
|
8
|
+
const solver = new TwoByTwoSolver();
|
|
9
|
+
for (let attempt = 0; attempt < MAX_WCA_ATTEMPTS; attempt += 1) {
|
|
10
|
+
const state = solver.randomState(random);
|
|
11
|
+
if (solver.solveIn(state, WCA_MIN_SCRAMBLE_DISTANCE - 1) !== null) continue;
|
|
12
|
+
return solver.generateExactly(state, SCRAMBLE_LENGTH);
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`${ERROR_PREFIX}: could not generate a 2x2 WCA scramble after ${MAX_WCA_ATTEMPTS} attempts`);
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { generateTwoByTwoScramble };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region .build/vendor/scramble-core/src/random-source.ts
|
|
2
|
+
const ERROR_PREFIX = "@cubegin/scramble-core";
|
|
3
|
+
const createMathRandomSource = () => ({ nextInt(maxExclusive) {
|
|
4
|
+
if (!Number.isSafeInteger(maxExclusive) || maxExclusive <= 0) throw new Error(`${ERROR_PREFIX}: random maxExclusive must be a positive safe integer`);
|
|
5
|
+
return Math.floor(Math.random() * maxExclusive);
|
|
6
|
+
} });
|
|
7
|
+
//#endregion
|
|
8
|
+
export { createMathRandomSource };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { initialize } from "./engine.mjs";
|
|
2
|
+
//#region .build/vendor/scramble-core/src/solvers/min2phase/coord-cube.ts
|
|
3
|
+
let isInitialized = false;
|
|
4
|
+
const initCoordCube = () => {
|
|
5
|
+
if (isInitialized) return;
|
|
6
|
+
initialize();
|
|
7
|
+
isInitialized = true;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { initCoordCube };
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { SOLVED_FACE_CUBE } from "./util.mjs";
|
|
2
|
+
//#region .build/vendor/scramble-core/src/solvers/min2phase/cubie-cube.ts
|
|
3
|
+
const CORNER_FACELET = [
|
|
4
|
+
[
|
|
5
|
+
8,
|
|
6
|
+
9,
|
|
7
|
+
20
|
|
8
|
+
],
|
|
9
|
+
[
|
|
10
|
+
6,
|
|
11
|
+
18,
|
|
12
|
+
38
|
|
13
|
+
],
|
|
14
|
+
[
|
|
15
|
+
0,
|
|
16
|
+
36,
|
|
17
|
+
47
|
|
18
|
+
],
|
|
19
|
+
[
|
|
20
|
+
2,
|
|
21
|
+
45,
|
|
22
|
+
11
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
29,
|
|
26
|
+
26,
|
|
27
|
+
15
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
27,
|
|
31
|
+
44,
|
|
32
|
+
24
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
33,
|
|
36
|
+
53,
|
|
37
|
+
42
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
35,
|
|
41
|
+
17,
|
|
42
|
+
51
|
|
43
|
+
]
|
|
44
|
+
];
|
|
45
|
+
const EDGE_FACELET = [
|
|
46
|
+
[5, 10],
|
|
47
|
+
[7, 19],
|
|
48
|
+
[3, 37],
|
|
49
|
+
[1, 46],
|
|
50
|
+
[32, 16],
|
|
51
|
+
[28, 25],
|
|
52
|
+
[30, 43],
|
|
53
|
+
[34, 52],
|
|
54
|
+
[23, 12],
|
|
55
|
+
[21, 41],
|
|
56
|
+
[50, 39],
|
|
57
|
+
[48, 14]
|
|
58
|
+
];
|
|
59
|
+
const FACE_NAMES = [
|
|
60
|
+
"U",
|
|
61
|
+
"R",
|
|
62
|
+
"F",
|
|
63
|
+
"D",
|
|
64
|
+
"L",
|
|
65
|
+
"B"
|
|
66
|
+
];
|
|
67
|
+
var CubieCube = class CubieCube {
|
|
68
|
+
cp;
|
|
69
|
+
co;
|
|
70
|
+
ep;
|
|
71
|
+
eo;
|
|
72
|
+
constructor(cp = [
|
|
73
|
+
0,
|
|
74
|
+
1,
|
|
75
|
+
2,
|
|
76
|
+
3,
|
|
77
|
+
4,
|
|
78
|
+
5,
|
|
79
|
+
6,
|
|
80
|
+
7
|
|
81
|
+
], co = [
|
|
82
|
+
0,
|
|
83
|
+
0,
|
|
84
|
+
0,
|
|
85
|
+
0,
|
|
86
|
+
0,
|
|
87
|
+
0,
|
|
88
|
+
0,
|
|
89
|
+
0
|
|
90
|
+
], ep = [
|
|
91
|
+
0,
|
|
92
|
+
1,
|
|
93
|
+
2,
|
|
94
|
+
3,
|
|
95
|
+
4,
|
|
96
|
+
5,
|
|
97
|
+
6,
|
|
98
|
+
7,
|
|
99
|
+
8,
|
|
100
|
+
9,
|
|
101
|
+
10,
|
|
102
|
+
11
|
|
103
|
+
], eo = [
|
|
104
|
+
0,
|
|
105
|
+
0,
|
|
106
|
+
0,
|
|
107
|
+
0,
|
|
108
|
+
0,
|
|
109
|
+
0,
|
|
110
|
+
0,
|
|
111
|
+
0,
|
|
112
|
+
0,
|
|
113
|
+
0,
|
|
114
|
+
0,
|
|
115
|
+
0
|
|
116
|
+
]) {
|
|
117
|
+
this.cp = [...cp];
|
|
118
|
+
this.co = [...co];
|
|
119
|
+
this.ep = [...ep];
|
|
120
|
+
this.eo = [...eo];
|
|
121
|
+
}
|
|
122
|
+
static solved() {
|
|
123
|
+
return new CubieCube();
|
|
124
|
+
}
|
|
125
|
+
static fromCoordinates(cperm, twist, eperm, flip) {
|
|
126
|
+
const cube = new CubieCube();
|
|
127
|
+
setNPerm(cube.cp, cperm, 8);
|
|
128
|
+
setTwist(cube.co, twist);
|
|
129
|
+
setNPerm(cube.ep, eperm, 12);
|
|
130
|
+
setFlip(cube.eo, flip);
|
|
131
|
+
return cube;
|
|
132
|
+
}
|
|
133
|
+
static fromFaceCube(facelets) {
|
|
134
|
+
if (facelets.length !== 54) return null;
|
|
135
|
+
const centerColors = [
|
|
136
|
+
facelets[4],
|
|
137
|
+
facelets[13],
|
|
138
|
+
facelets[22],
|
|
139
|
+
facelets[31],
|
|
140
|
+
facelets[40],
|
|
141
|
+
facelets[49]
|
|
142
|
+
];
|
|
143
|
+
const colors = Array.from(facelets, (facelet) => centerColors.indexOf(facelet));
|
|
144
|
+
if (colors.some((color) => color < 0)) return null;
|
|
145
|
+
const cp = Array(8).fill(0);
|
|
146
|
+
const co = Array(8).fill(0);
|
|
147
|
+
const ep = Array(12).fill(0);
|
|
148
|
+
const eo = Array(12).fill(0);
|
|
149
|
+
for (let corner = 0; corner < 8; corner += 1) {
|
|
150
|
+
let orientation = 0;
|
|
151
|
+
while (orientation < 3 && colors[CORNER_FACELET[corner][orientation]] !== 0 && colors[CORNER_FACELET[corner][orientation]] !== 3) orientation += 1;
|
|
152
|
+
if (orientation === 3) return null;
|
|
153
|
+
const color1 = colors[CORNER_FACELET[corner][(orientation + 1) % 3]];
|
|
154
|
+
const color2 = colors[CORNER_FACELET[corner][(orientation + 2) % 3]];
|
|
155
|
+
const cubie = CORNER_FACELET.findIndex(([, facelet1, facelet2]) => color1 === Math.floor(facelet1 / 9) && color2 === Math.floor(facelet2 / 9));
|
|
156
|
+
if (cubie < 0) return null;
|
|
157
|
+
cp[corner] = cubie;
|
|
158
|
+
co[corner] = orientation % 3;
|
|
159
|
+
}
|
|
160
|
+
for (let edge = 0; edge < 12; edge += 1) {
|
|
161
|
+
const color0 = colors[EDGE_FACELET[edge][0]];
|
|
162
|
+
const color1 = colors[EDGE_FACELET[edge][1]];
|
|
163
|
+
const cubie = EDGE_FACELET.findIndex(([facelet0, facelet1]) => color0 === Math.floor(facelet0 / 9) && color1 === Math.floor(facelet1 / 9));
|
|
164
|
+
if (cubie >= 0) {
|
|
165
|
+
ep[edge] = cubie;
|
|
166
|
+
eo[edge] = 0;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const flippedCubie = EDGE_FACELET.findIndex(([facelet0, facelet1]) => color0 === Math.floor(facelet1 / 9) && color1 === Math.floor(facelet0 / 9));
|
|
170
|
+
if (flippedCubie < 0) return null;
|
|
171
|
+
ep[edge] = flippedCubie;
|
|
172
|
+
eo[edge] = 1;
|
|
173
|
+
}
|
|
174
|
+
return new CubieCube(cp, co, ep, eo);
|
|
175
|
+
}
|
|
176
|
+
toFaceCube() {
|
|
177
|
+
const facelets = Array.from(SOLVED_FACE_CUBE);
|
|
178
|
+
for (let corner = 0; corner < 8; corner += 1) {
|
|
179
|
+
const cubie = this.cp[corner];
|
|
180
|
+
const orientation = this.co[corner];
|
|
181
|
+
for (let index = 0; index < 3; index += 1) facelets[CORNER_FACELET[corner][(index + orientation) % 3]] = FACE_NAMES[Math.floor(CORNER_FACELET[cubie][index] / 9)] ?? "U";
|
|
182
|
+
}
|
|
183
|
+
for (let edge = 0; edge < 12; edge += 1) {
|
|
184
|
+
const cubie = this.ep[edge];
|
|
185
|
+
const orientation = this.eo[edge];
|
|
186
|
+
for (let index = 0; index < 2; index += 1) facelets[EDGE_FACELET[edge][(index + orientation) % 2]] = FACE_NAMES[Math.floor(EDGE_FACELET[cubie][index] / 9)] ?? "U";
|
|
187
|
+
}
|
|
188
|
+
return facelets.join("");
|
|
189
|
+
}
|
|
190
|
+
verify() {
|
|
191
|
+
if (this.ep.reduce((mask, edge) => mask | 1 << edge, 0) !== 4095) return -2;
|
|
192
|
+
if (this.eo.reduce((sum, orientation) => sum ^ orientation, 0) !== 0) return -3;
|
|
193
|
+
if (this.cp.reduce((mask, corner) => mask | 1 << corner, 0) !== 255) return -4;
|
|
194
|
+
if (this.co.reduce((sum, orientation) => sum + orientation, 0) % 3 !== 0) return -5;
|
|
195
|
+
if ((getNParity(getNPerm(this.ep, 12), 12) ^ getNParity(getNPerm(this.cp, 8), 8)) !== 0) return -6;
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const getNParity = (index, n) => {
|
|
200
|
+
let parity = 0;
|
|
201
|
+
let value = index;
|
|
202
|
+
for (let current = n - 2; current >= 0; current -= 1) {
|
|
203
|
+
parity ^= value % (n - current);
|
|
204
|
+
value = Math.floor(value / (n - current));
|
|
205
|
+
}
|
|
206
|
+
return parity & 1;
|
|
207
|
+
};
|
|
208
|
+
const getNPerm = (permutation, n) => {
|
|
209
|
+
let index = 0;
|
|
210
|
+
for (let i = 0; i < n; i += 1) {
|
|
211
|
+
index *= n - i;
|
|
212
|
+
for (let j = i + 1; j < n; j += 1) if ((permutation[j] ?? 0) < (permutation[i] ?? 0)) index += 1;
|
|
213
|
+
}
|
|
214
|
+
return index;
|
|
215
|
+
};
|
|
216
|
+
const setNPerm = (permutation, index, n) => {
|
|
217
|
+
for (let i = n - 1; i >= 0; i -= 1) {
|
|
218
|
+
permutation[i] = index % (n - i);
|
|
219
|
+
index = Math.floor(index / (n - i));
|
|
220
|
+
for (let j = i + 1; j < n; j += 1) if ((permutation[j] ?? 0) >= (permutation[i] ?? 0)) permutation[j] = (permutation[j] ?? 0) + 1;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const setTwist = (orientations, index) => {
|
|
224
|
+
let twist = 0;
|
|
225
|
+
let value = index;
|
|
226
|
+
for (let i = 6; i >= 0; i -= 1) {
|
|
227
|
+
const orientation = value % 3;
|
|
228
|
+
orientations[i] = orientation;
|
|
229
|
+
twist += orientation;
|
|
230
|
+
value = Math.floor(value / 3);
|
|
231
|
+
}
|
|
232
|
+
orientations[7] = (15 - twist) % 3;
|
|
233
|
+
};
|
|
234
|
+
const setFlip = (orientations, index) => {
|
|
235
|
+
let parity = 0;
|
|
236
|
+
let value = index;
|
|
237
|
+
for (let i = 10; i >= 0; i -= 1) {
|
|
238
|
+
const orientation = value & 1;
|
|
239
|
+
orientations[i] = orientation;
|
|
240
|
+
parity ^= orientation;
|
|
241
|
+
value >>= 1;
|
|
242
|
+
}
|
|
243
|
+
orientations[11] = parity;
|
|
244
|
+
};
|
|
245
|
+
//#endregion
|
|
246
|
+
export { CubieCube, getNParity, getNPerm };
|