@cubingcenter/scrambler 0.6.0 → 0.6.2
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/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.js +26 -1
- package/dist/puzzles/cube3/solver/generated/manifest.json +14 -0
- package/dist/puzzles/cube3/solver/generated/phase1-udco.bin +1 -0
- package/dist/puzzles/cube3/solver/generated/phase1-udeo.bin +1 -0
- package/dist/puzzles/cube3/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/generated-assets.js +2 -1
- package/dist/puzzles/cube3/solver/node-loader.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/node-loader.js +22 -0
- package/dist/puzzles/cube3/solver/pair-browser-loader.d.ts +11 -0
- package/dist/puzzles/cube3/solver/pair-browser-loader.d.ts.map +1 -0
- package/dist/puzzles/cube3/solver/pair-browser-loader.js +93 -0
- package/dist/puzzles/cube3/solver/pair-node-loader.d.ts +6 -0
- package/dist/puzzles/cube3/solver/pair-node-loader.d.ts.map +1 -0
- package/dist/puzzles/cube3/solver/pair-node-loader.js +79 -0
- package/dist/puzzles/cube3/solver/pair-tables-types.d.ts +37 -0
- package/dist/puzzles/cube3/solver/pair-tables-types.d.ts.map +1 -0
- package/dist/puzzles/cube3/solver/pair-tables-types.js +29 -0
- package/dist/puzzles/cube3/solver/pair-tables.d.ts +29 -0
- package/dist/puzzles/cube3/solver/pair-tables.d.ts.map +1 -0
- package/dist/puzzles/cube3/solver/pair-tables.js +69 -0
- package/dist/puzzles/cube3/solver/phase1.d.ts +3 -1
- package/dist/puzzles/cube3/solver/phase1.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase1.js +32 -2
- package/dist/puzzles/cube3/solver/phase2.d.ts +3 -0
- package/dist/puzzles/cube3/solver/phase2.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/phase2.js +63 -5
- package/dist/puzzles/cube3/solver/tables.d.ts +16 -0
- package/dist/puzzles/cube3/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/tables.js +4 -2
- package/dist/puzzles/cube4/scrambler.d.ts +4 -1
- package/dist/puzzles/cube4/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube4/scrambler.js +101 -14
- package/dist-cjs/puzzles/cube3/solver/browser-loader.js +26 -1
- package/dist-cjs/puzzles/cube3/solver/generated/manifest.json +14 -0
- package/dist-cjs/puzzles/cube3/solver/generated/phase1-udco.bin +1 -0
- package/dist-cjs/puzzles/cube3/solver/generated/phase1-udeo.bin +1 -0
- package/dist-cjs/puzzles/cube3/solver/generated-assets.js +2 -1
- package/dist-cjs/puzzles/cube3/solver/node-loader.js +22 -0
- package/dist-cjs/puzzles/cube3/solver/pair-browser-loader.js +96 -0
- package/dist-cjs/puzzles/cube3/solver/pair-node-loader.js +85 -0
- package/dist-cjs/puzzles/cube3/solver/pair-tables-types.js +33 -0
- package/dist-cjs/puzzles/cube3/solver/pair-tables.js +107 -0
- package/dist-cjs/puzzles/cube3/solver/phase1.js +32 -2
- package/dist-cjs/puzzles/cube3/solver/phase2.js +63 -5
- package/dist-cjs/puzzles/cube3/solver/tables.js +4 -2
- package/dist-cjs/puzzles/cube4/scrambler.js +101 -15
- package/package.json +4 -1
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* The 4x4 scramble generator: sample a uniform random state, solve it with
|
|
4
4
|
* the reduction solver (phases 1-4), and invert the solution. The scramble
|
|
5
5
|
* always reproduces the sampled target state and facelets exactly.
|
|
6
|
+
*
|
|
7
|
+
* If the solver fails after 5 attempts it falls back to cubing.js
|
|
8
|
+
* `randomScrambleForEvent("444")` (also random-state). If that also fails,
|
|
9
|
+
* a WCA-compatible random-moves sequence (40 moves) is returned.
|
|
6
10
|
*/
|
|
7
11
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
12
|
if (k2 === undefined) k2 = k;
|
|
@@ -39,7 +43,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
43
|
})();
|
|
40
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
45
|
exports.cube4ScrambleGenerator = void 0;
|
|
42
|
-
exports.isCube4TablesLoaded = isCube4TablesLoaded;
|
|
43
46
|
exports.generateCube4Scramble = generateCube4Scramble;
|
|
44
47
|
const moves_js_1 = require("./moves.js");
|
|
45
48
|
const random_state_js_1 = require("./random-state.js");
|
|
@@ -47,6 +50,95 @@ const state_js_1 = require("./state.js");
|
|
|
47
50
|
const facelets_js_1 = require("./facelets.js");
|
|
48
51
|
const solve_js_1 = require("./reduction/solve.js");
|
|
49
52
|
const index_js_1 = require("../cube3/solver/index.js");
|
|
53
|
+
const index_js_2 = require("../../random/index.js");
|
|
54
|
+
// ────────────────────────────────────────────────────────────
|
|
55
|
+
// cubing.js fallback (random-state, WCA-compliant)
|
|
56
|
+
// ────────────────────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Try to generate a 4x4 scramble using cubing.js `randomScrambleForEvent`.
|
|
59
|
+
* Uses a dynamic import so browser bundles can tree-shake it when unused.
|
|
60
|
+
* Returns null if cubing.js is unavailable.
|
|
61
|
+
*/
|
|
62
|
+
async function generateCube4WithCubingJs() {
|
|
63
|
+
try {
|
|
64
|
+
const { randomScrambleForEvent } = await Promise.resolve().then(() => __importStar(require(
|
|
65
|
+
/* webpackIgnore: true */
|
|
66
|
+
/* @vite-ignore */
|
|
67
|
+
"cubing/scramble")));
|
|
68
|
+
const alg = await randomScrambleForEvent("444");
|
|
69
|
+
const scramble = alg.toString();
|
|
70
|
+
const moves = scramble.trim().split(/\s+/);
|
|
71
|
+
return {
|
|
72
|
+
eventId: "444",
|
|
73
|
+
scramble,
|
|
74
|
+
moves,
|
|
75
|
+
quality: "random-state",
|
|
76
|
+
generator: "cubing-js",
|
|
77
|
+
metadata: {
|
|
78
|
+
generator: "cubing-js",
|
|
79
|
+
distribution: "random-state",
|
|
80
|
+
note: "Generated by cubing.js randomScrambleForEvent as fallback."
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ────────────────────────────────────────────────────────────
|
|
89
|
+
// Last-resort: random-moves (no external dep, always works)
|
|
90
|
+
// ────────────────────────────────────────────────────────────
|
|
91
|
+
const CUBE4_FACES = ["U", "R", "F", "D", "L", "B"];
|
|
92
|
+
// Opposite face indices (U↔D, R↔L, F↔B)
|
|
93
|
+
const CUBE4_OPPOSITE = { U: "D", D: "U", R: "L", L: "R", F: "B", B: "F" };
|
|
94
|
+
const CUBE4_SUFFIXES = ["", "2", "'"];
|
|
95
|
+
const CUBE4_WIDE_FACES = ["Uw", "Rw", "Fw", "Dw", "Lw", "Bw"];
|
|
96
|
+
// Opposite wide-move faces
|
|
97
|
+
const CUBE4_WIDE_OPPOSITE = {
|
|
98
|
+
Uw: "Dw", Dw: "Uw", Rw: "Lw", Lw: "Rw", Fw: "Bw", Bw: "Fw"
|
|
99
|
+
};
|
|
100
|
+
// All available move bases (outer + wide). Outer and wide turns are treated
|
|
101
|
+
// independently for the same-face/opposite-face check using their base letter.
|
|
102
|
+
const ALL_MOVE_BASES = [...CUBE4_FACES, ...CUBE4_WIDE_FACES];
|
|
103
|
+
function generateCube4RandomMoves(options = {}) {
|
|
104
|
+
const rng = (0, index_js_2.createRandomSource)(options.seed);
|
|
105
|
+
const moveCount = 40;
|
|
106
|
+
const moves = [];
|
|
107
|
+
let lastFace = null;
|
|
108
|
+
let secondLastFace = null;
|
|
109
|
+
const getBaseLetter = (face) => face.length > 1 ? face[0] : face;
|
|
110
|
+
for (let i = 0; i < moveCount; i++) {
|
|
111
|
+
let face;
|
|
112
|
+
// Reject same face as last or opposite face when the last two moves
|
|
113
|
+
// share the same axis (to avoid redundant move pairs like R L R).
|
|
114
|
+
do {
|
|
115
|
+
face = ALL_MOVE_BASES[rng.nextInt(ALL_MOVE_BASES.length)];
|
|
116
|
+
} while (face === lastFace ||
|
|
117
|
+
(lastFace !== null &&
|
|
118
|
+
(CUBE4_OPPOSITE[face] === lastFace || CUBE4_WIDE_OPPOSITE[face] === lastFace) &&
|
|
119
|
+
secondLastFace !== null &&
|
|
120
|
+
getBaseLetter(secondLastFace) === getBaseLetter(face)));
|
|
121
|
+
const suffix = CUBE4_SUFFIXES[rng.nextInt(3)];
|
|
122
|
+
moves.push(`${face}${suffix}`);
|
|
123
|
+
secondLastFace = lastFace;
|
|
124
|
+
lastFace = face;
|
|
125
|
+
}
|
|
126
|
+
const scramble = moves.join(" ");
|
|
127
|
+
return {
|
|
128
|
+
eventId: "444",
|
|
129
|
+
scramble,
|
|
130
|
+
moves,
|
|
131
|
+
quality: "random-moves",
|
|
132
|
+
generator: "cube4-random-moves-fallback",
|
|
133
|
+
metadata: {
|
|
134
|
+
generator: "cube4-random-moves-fallback",
|
|
135
|
+
distribution: "random-moves",
|
|
136
|
+
note: "Reduction solver and cubing.js both failed; using random-moves.",
|
|
137
|
+
...options.metadata
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// ────────────────────────────────────────────────────────────
|
|
50
142
|
let cachedTables;
|
|
51
143
|
async function loadCube4Tables(baseUrl) {
|
|
52
144
|
if (cachedTables)
|
|
@@ -78,18 +170,6 @@ async function loadCube4Tables(baseUrl) {
|
|
|
78
170
|
cachedTables = tables;
|
|
79
171
|
return tables;
|
|
80
172
|
}
|
|
81
|
-
function isCube4TablesLoaded() {
|
|
82
|
-
// For the scrambler retry logic, we need to know if tables are already
|
|
83
|
-
// loaded to avoid re-loading on every attempt.
|
|
84
|
-
try {
|
|
85
|
-
// @ts-ignore
|
|
86
|
-
const loader = globalThis;
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
173
|
exports.cube4ScrambleGenerator = {
|
|
94
174
|
info: {
|
|
95
175
|
eventId: "444",
|
|
@@ -97,7 +177,7 @@ exports.cube4ScrambleGenerator = {
|
|
|
97
177
|
puzzle: "cube-4x4",
|
|
98
178
|
quality: "random-state",
|
|
99
179
|
generator: "cube4-reduction",
|
|
100
|
-
description: "Random-state 4x4 scramble via the reduction solver (centers + pairing + 3x3 finish)."
|
|
180
|
+
description: "Random-state 4x4 scramble via the reduction solver (centers + pairing + 3x3 finish). Falls back to random-moves if the solver fails."
|
|
101
181
|
},
|
|
102
182
|
generate(options = {}) {
|
|
103
183
|
return generateCube4Scramble(options);
|
|
@@ -174,5 +254,11 @@ async function generateCube4Scramble(options = {}) {
|
|
|
174
254
|
throw error;
|
|
175
255
|
}
|
|
176
256
|
}
|
|
177
|
-
|
|
257
|
+
// All solver attempts exhausted — try cubing.js first, then random-moves.
|
|
258
|
+
console.warn("[cube4-scrambler] Reduction solver failed after 5 attempts; trying cubing.js fallback.", lastError);
|
|
259
|
+
const cubingJsResult = await generateCube4WithCubingJs();
|
|
260
|
+
if (cubingJsResult)
|
|
261
|
+
return cubingJsResult;
|
|
262
|
+
console.warn("[cube4-scrambler] cubing.js fallback also failed; using random-moves.");
|
|
263
|
+
return generateCube4RandomMoves(options);
|
|
178
264
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cubingcenter/scrambler",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Extensible scramble generation toolkit for CubingCenter projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -57,6 +57,9 @@
|
|
|
57
57
|
"tsx": "^4.20.0",
|
|
58
58
|
"typescript": "^5.9.0"
|
|
59
59
|
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"cubing": "^0.63.4"
|
|
62
|
+
},
|
|
60
63
|
"scripts": {
|
|
61
64
|
"build": "node scripts/clean.cjs && tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/write-cjs-package.cjs && node scripts/copy-assets.cjs",
|
|
62
65
|
"test": "node --test --import tsx test/*.test.ts",
|