@cubingcenter/scrambler 0.5.1 → 0.5.3
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/puzzles/cube2/facelets.d.ts.map +1 -1
- package/dist/puzzles/cube2/facelets.js +43 -22
- package/dist/puzzles/cube2/random-state.d.ts.map +1 -1
- package/dist/puzzles/cube2/random-state.js +38 -34
- package/dist/puzzles/cube2/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube2/scrambler.js +24 -10
- package/dist/puzzles/cube2/solver/browser-loader.d.ts +2 -2
- package/dist/puzzles/cube2/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/browser-loader.js +2 -2
- package/dist/puzzles/cube2/solver/generated/manifest.json +3 -3
- package/dist/puzzles/cube2/solver/generated/policy.bin +0 -0
- package/dist/puzzles/cube2/solver/generated-assets.d.ts +1 -1
- package/dist/puzzles/cube2/solver/generated-assets.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/index.d.ts +2 -1
- package/dist/puzzles/cube2/solver/index.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/index.js +2 -1
- package/dist/puzzles/cube2/solver/node-loader.d.ts +1 -1
- package/dist/puzzles/cube2/solver/node-loader.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/node-loader.js +2 -2
- package/dist/puzzles/cube2/solver/search.d.ts +3 -0
- package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/search.js +51 -36
- package/dist/puzzles/cube2/solver/table-metadata.d.ts +2 -2
- package/dist/puzzles/cube2/solver/table-metadata.js +2 -2
- package/dist/puzzles/cube2/solver/tables.d.ts +2 -1
- package/dist/puzzles/cube2/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/tables.js +39 -13
- package/dist/puzzles/cube2/state.d.ts.map +1 -1
- package/dist/puzzles/cube2/state.js +3 -1
- package/dist/puzzles/cube2/validation.d.ts +2 -0
- package/dist/puzzles/cube2/validation.d.ts.map +1 -1
- package/dist/puzzles/cube2/validation.js +45 -8
- package/dist/puzzles/cube3/facelets.d.ts.map +1 -1
- package/dist/puzzles/cube3/facelets.js +53 -28
- package/dist/puzzles/cube3/random-state.d.ts.map +1 -1
- package/dist/puzzles/cube3/random-state.js +9 -2
- package/dist/puzzles/cube3/scrambler.js +1 -1
- package/dist/puzzles/cube3/state.d.ts.map +1 -1
- package/dist/puzzles/cube3/state.js +4 -1
- package/dist/puzzles/cube3/validation.d.ts.map +1 -1
- package/dist/puzzles/cube3/validation.js +5 -2
- package/dist/puzzles/skewb/random-state.d.ts +1 -0
- package/dist/puzzles/skewb/random-state.d.ts.map +1 -1
- package/dist/puzzles/skewb/random-state.js +9 -1
- package/dist/puzzles/skewb/scrambler.d.ts.map +1 -1
- package/dist/puzzles/skewb/scrambler.js +6 -2
- package/dist/puzzles/skewb/solver/tables.d.ts +1 -0
- package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -1
- package/dist/puzzles/skewb/solver/tables.js +11 -5
- package/dist-cjs/puzzles/cube2/facelets.js +43 -22
- package/dist-cjs/puzzles/cube2/random-state.js +37 -33
- package/dist-cjs/puzzles/cube2/scrambler.js +22 -8
- package/dist-cjs/puzzles/cube2/solver/browser-loader.js +2 -2
- package/dist-cjs/puzzles/cube2/solver/generated/manifest.json +3 -3
- package/dist-cjs/puzzles/cube2/solver/generated/policy.bin +0 -0
- package/dist-cjs/puzzles/cube2/solver/index.js +18 -1
- package/dist-cjs/puzzles/cube2/solver/node-loader.js +2 -2
- package/dist-cjs/puzzles/cube2/solver/search.js +53 -35
- package/dist-cjs/puzzles/cube2/solver/table-metadata.js +2 -2
- package/dist-cjs/puzzles/cube2/solver/tables.js +41 -14
- package/dist-cjs/puzzles/cube2/state.js +3 -1
- package/dist-cjs/puzzles/cube2/validation.js +47 -8
- package/dist-cjs/puzzles/cube3/facelets.js +53 -28
- package/dist-cjs/puzzles/cube3/random-state.js +8 -1
- package/dist-cjs/puzzles/cube3/scrambler.js +1 -1
- package/dist-cjs/puzzles/cube3/state.js +4 -1
- package/dist-cjs/puzzles/cube3/validation.js +5 -2
- package/dist-cjs/puzzles/skewb/random-state.js +9 -0
- package/dist-cjs/puzzles/skewb/scrambler.js +5 -1
- package/dist-cjs/puzzles/skewb/solver/tables.js +12 -6
- package/package.json +1 -1
- package/dist/puzzles/cube2/solver/generated/distances.bin +0 -1
- package/dist/puzzles/cube3/solver/browser-worker-pool.d.ts +0 -31
- package/dist/puzzles/cube3/solver/browser-worker-pool.d.ts.map +0 -1
- package/dist/puzzles/cube3/solver/browser-worker-pool.js +0 -118
- package/dist/puzzles/cube3/solver/browser-worker.d.ts +0 -2
- package/dist/puzzles/cube3/solver/browser-worker.d.ts.map +0 -1
- package/dist/puzzles/cube3/solver/browser-worker.js +0 -71
- package/dist/puzzles/cube3/solver/worker-pool.d.ts +0 -18
- package/dist/puzzles/cube3/solver/worker-pool.d.ts.map +0 -1
- package/dist/puzzles/cube3/solver/worker-pool.js +0 -116
- package/dist/puzzles/cube3/solver/worker.d.ts +0 -2
- package/dist/puzzles/cube3/solver/worker.d.ts.map +0 -1
- package/dist/puzzles/cube3/solver/worker.js +0 -73
- package/dist-cjs/puzzles/cube2/solver/generated/distances.bin +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"facelets.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/facelets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"facelets.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/facelets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAC;AAgErF,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,CAqBhE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CAEnE;AAED,wBAAgB,iBAAiB,IAAI,SAAS,SAAS,EAAE,CAExD"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const FACE_ORDER = ["U", "R", "F", "D", "L", "B"];
|
|
2
|
+
const STICKERS = ["U", "R", "F", "D", "L", "B"];
|
|
3
|
+
const STICKER_INDEX = { U: 0, R: 1, F: 2, D: 3, L: 4, B: 5 };
|
|
2
4
|
const CORNER_PIECE_STICKERS = [
|
|
3
5
|
["U", "R", "F"],
|
|
4
6
|
["U", "F", "L"],
|
|
@@ -19,12 +21,48 @@ const CORNER_POSITION_SLOTS = [
|
|
|
19
21
|
[["D", 2], ["B", 3], ["L", 2]],
|
|
20
22
|
[["D", 3], ["R", 3], ["B", 2]]
|
|
21
23
|
];
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
const CORNER_CELLS = buildCells();
|
|
25
|
+
function buildCells() {
|
|
26
|
+
const cells = [];
|
|
24
27
|
for (let position = 0; position < CORNER_POSITION_SLOTS.length; position += 1) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
const byPiece = [];
|
|
29
|
+
for (let piece = 0; piece < CORNER_PIECE_STICKERS.length; piece += 1) {
|
|
30
|
+
const byOrientation = [];
|
|
31
|
+
for (let orientation = 0; orientation < 3; orientation += 1) {
|
|
32
|
+
const stickers = CORNER_PIECE_STICKERS[piece];
|
|
33
|
+
const slotList = CORNER_POSITION_SLOTS[position];
|
|
34
|
+
const cell = [];
|
|
35
|
+
for (let index = 0; index < slotList.length; index += 1) {
|
|
36
|
+
const [face, stickerIndex] = slotList[index];
|
|
37
|
+
cell.push(FACE_ORDER.indexOf(face));
|
|
38
|
+
cell.push(stickerIndex);
|
|
39
|
+
cell.push(STICKER_INDEX[stickers[(index - orientation + stickers.length) % stickers.length]]);
|
|
40
|
+
}
|
|
41
|
+
byOrientation.push(cell);
|
|
42
|
+
}
|
|
43
|
+
byPiece.push(byOrientation);
|
|
44
|
+
}
|
|
45
|
+
cells.push(byPiece);
|
|
46
|
+
}
|
|
47
|
+
return cells;
|
|
48
|
+
}
|
|
49
|
+
export function toCube2Facelets(state) {
|
|
50
|
+
const facelets = {
|
|
51
|
+
U: Array(4),
|
|
52
|
+
R: Array(4),
|
|
53
|
+
F: Array(4),
|
|
54
|
+
D: Array(4),
|
|
55
|
+
L: Array(4),
|
|
56
|
+
B: Array(4)
|
|
57
|
+
};
|
|
58
|
+
const faces = [facelets.U, facelets.R, facelets.F, facelets.D, facelets.L, facelets.B];
|
|
59
|
+
const permutation = state.corners.permutation;
|
|
60
|
+
const orientation = state.corners.orientation;
|
|
61
|
+
for (let position = 0; position < CORNER_CELLS.length; position += 1) {
|
|
62
|
+
const cells = CORNER_CELLS[position][permutation[position]][orientation[position]];
|
|
63
|
+
for (let cellIndex = 0; cellIndex < cells.length; cellIndex += 3) {
|
|
64
|
+
faces[cells[cellIndex]][cells[cellIndex + 1]] = STICKERS[cells[cellIndex + 2]];
|
|
65
|
+
}
|
|
28
66
|
}
|
|
29
67
|
return facelets;
|
|
30
68
|
}
|
|
@@ -34,20 +72,3 @@ export function formatCube2Facelets(facelets) {
|
|
|
34
72
|
export function getCube2FaceOrder() {
|
|
35
73
|
return FACE_ORDER;
|
|
36
74
|
}
|
|
37
|
-
function createEmptyFacelets() {
|
|
38
|
-
return {
|
|
39
|
-
U: Array(4).fill("U"),
|
|
40
|
-
R: Array(4).fill("R"),
|
|
41
|
-
F: Array(4).fill("F"),
|
|
42
|
-
D: Array(4).fill("D"),
|
|
43
|
-
L: Array(4).fill("L"),
|
|
44
|
-
B: Array(4).fill("B")
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function placeOrientedStickers(facelets, slots, stickers, orientation) {
|
|
48
|
-
for (let index = 0; index < slots.length; index += 1) {
|
|
49
|
-
const [face, stickerIndex] = slots[index];
|
|
50
|
-
const sticker = stickers[(index - orientation + stickers.length) % stickers.length];
|
|
51
|
-
facelets[face][stickerIndex] = sticker;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"random-state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/random-state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"random-state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/random-state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGtE,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,uBAA4B,GAAG,UAAU,CAiB1F"}
|
|
@@ -1,51 +1,55 @@
|
|
|
1
1
|
import { createRandomSource } from "../../random/index.js";
|
|
2
|
-
import {
|
|
3
|
-
import { isAllowedRandomCube2State } from "./validation.js";
|
|
2
|
+
import { isTrivialCube2State } from "./validation.js";
|
|
4
3
|
export function generateRandomCube2State(options = {}) {
|
|
5
4
|
const random = createRandomSource(options.seed);
|
|
6
5
|
const rejectTrivial = options.rejectTrivial ?? true;
|
|
7
6
|
for (let attempt = 0; attempt < 100; attempt += 1) {
|
|
7
|
+
// The state is legal by construction (DBL corner fixed, even
|
|
8
|
+
// permutation, orientation sum divisible by 3, values in range), so the
|
|
9
|
+
// only meaningful rejection is the trivial set: solved + the 18
|
|
10
|
+
// single-move states (scrambles shorter than 2 moves), compared by
|
|
11
|
+
// arrays — no coordinate encodings in this hot path.
|
|
8
12
|
const state = createLegalRandomState(random);
|
|
9
|
-
if (!rejectTrivial ||
|
|
13
|
+
if (!rejectTrivial || !isTrivialCube2State(state)) {
|
|
10
14
|
return state;
|
|
11
15
|
}
|
|
12
16
|
}
|
|
13
17
|
throw new Error("Unable to generate a non-trivial random 2x2 state.");
|
|
14
18
|
}
|
|
15
19
|
function createLegalRandomState(random) {
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const orient7 = randomOrientations(CORNER_COUNT - 1, 3, random);
|
|
20
|
-
orient7.splice(6, 0, 0);
|
|
21
|
-
return {
|
|
22
|
-
corners: {
|
|
23
|
-
permutation: mappedPerm,
|
|
24
|
-
orientation: orient7
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
function shuffledRange(length, random) {
|
|
29
|
-
const values = Array.from({ length }, (_, index) => index);
|
|
30
|
-
for (let index = values.length - 1; index > 0; index -= 1) {
|
|
20
|
+
// 7 free corners (piece 6 = DBL stays fixed at position 6)
|
|
21
|
+
const perm7 = [0, 1, 2, 3, 4, 5, 6];
|
|
22
|
+
for (let index = 6; index > 0; index -= 1) {
|
|
31
23
|
const swapIndex = random.nextInt(index + 1);
|
|
32
|
-
|
|
24
|
+
if (swapIndex < index) {
|
|
25
|
+
const temporary = perm7[index];
|
|
26
|
+
perm7[index] = perm7[swapIndex];
|
|
27
|
+
perm7[swapIndex] = temporary;
|
|
28
|
+
}
|
|
33
29
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
30
|
+
// Map the shuffle domain {0..6} to {0..5,7} and insert 6 at position 6
|
|
31
|
+
// (DBL fixed). Single allocation, no intermediate arrays.
|
|
32
|
+
const last = perm7[6] >= 6 ? perm7[6] + 1 : perm7[6];
|
|
33
|
+
const permutation = new Array(8);
|
|
34
|
+
for (let index = 0; index < 6; index += 1) {
|
|
35
|
+
const value = perm7[index];
|
|
36
|
+
permutation[index] = value >= 6 ? value + 1 : value;
|
|
37
|
+
}
|
|
38
|
+
permutation[6] = 6;
|
|
39
|
+
permutation[7] = last;
|
|
40
|
+
// 7 free orientations with sum divisible by 3; DBL stays oriented
|
|
41
|
+
const orientation = [0, 0, 0, 0, 0, 0, 0, 0];
|
|
38
42
|
let total = 0;
|
|
39
|
-
for (let index = 0; index <
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
total +=
|
|
43
|
+
for (let index = 0; index < 6; index += 1) {
|
|
44
|
+
const value = random.nextInt(3);
|
|
45
|
+
orientation[index] = value;
|
|
46
|
+
total += value;
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
orientation[7] = (3 - (total % 3)) % 3;
|
|
49
|
+
return {
|
|
50
|
+
corners: {
|
|
51
|
+
permutation,
|
|
52
|
+
orientation
|
|
53
|
+
}
|
|
54
|
+
};
|
|
51
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"scrambler.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/scrambler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAiB9F,eAAO,MAAM,sBAAsB,EAAE,iBAYpC,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3D,OAAO,CAAC,cAAc,CAAC,CAqDzB"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { formatCube2Algorithm
|
|
1
|
+
import { formatCube2Algorithm } from "./moves.js";
|
|
2
2
|
import { generateRandomCube2State } from "./random-state.js";
|
|
3
3
|
import { formatCube2Facelets, toCube2Facelets } from "./facelets.js";
|
|
4
|
-
import {
|
|
4
|
+
import { areCube2TablesLoaded, solveCube2StateIndices, solveCube2StateIndicesSync, verifyCube2SolutionIndices, BFS_MOVES } from "./solver/index.js";
|
|
5
|
+
// BFS_MOVES = [U, U2, U', R, R2, R', F, F2, F'] — the inverse of index m is
|
|
6
|
+
// CUBE2_MOVE_INVERSE[m] (U2/R2/F2 are self-inverse, so m ^ 1 does not apply).
|
|
7
|
+
const CUBE2_MOVE_INVERSE = [2, 1, 0, 5, 4, 3, 8, 7, 6];
|
|
5
8
|
export const cube2ScrambleGenerator = {
|
|
6
9
|
info: {
|
|
7
10
|
eventId: "222",
|
|
@@ -17,20 +20,31 @@ export const cube2ScrambleGenerator = {
|
|
|
17
20
|
};
|
|
18
21
|
export async function generateCube2Scramble(options = {}) {
|
|
19
22
|
const state = generateRandomCube2State(options);
|
|
20
|
-
const solution =
|
|
21
|
-
|
|
23
|
+
const solution = areCube2TablesLoaded()
|
|
24
|
+
? solveCube2StateIndicesSync(state)
|
|
25
|
+
: await solveCube2StateIndices(state);
|
|
26
|
+
const depth = solution.length;
|
|
27
|
+
// Scramble = inverse of the solution, reversed.
|
|
28
|
+
const scrambleMoves = new Array(depth);
|
|
29
|
+
for (let index = 0; index < depth; index += 1) {
|
|
30
|
+
scrambleMoves[index] = BFS_MOVES[CUBE2_MOVE_INVERSE[solution[depth - 1 - index]]];
|
|
31
|
+
}
|
|
22
32
|
if (!options.skipValidation) {
|
|
23
|
-
|
|
33
|
+
// The scramble is the exact inverse of the solution, so verifying that
|
|
34
|
+
// the solution solves the target state is equivalent to verifying that
|
|
35
|
+
// the scramble reproduces it — a single numeric walk suffices.
|
|
36
|
+
if (!verifyCube2SolutionIndices(state, solution)) {
|
|
24
37
|
throw new Error("Generated 2x2 scramble does not reproduce the target random state.");
|
|
25
38
|
}
|
|
26
|
-
if (!verifyCube2Solution(state, solution.moves)) {
|
|
27
|
-
throw new Error("Generated 2x2 solution does not solve the target random state.");
|
|
28
|
-
}
|
|
29
39
|
if (scrambleMoves.length < 2) {
|
|
30
40
|
throw new Error("Generated 2x2 scramble is too short.");
|
|
31
41
|
}
|
|
32
42
|
}
|
|
33
43
|
const facelets = toCube2Facelets(state);
|
|
44
|
+
const solutionMoves = new Array(depth);
|
|
45
|
+
for (let index = 0; index < depth; index += 1) {
|
|
46
|
+
solutionMoves[index] = BFS_MOVES[solution[index]];
|
|
47
|
+
}
|
|
34
48
|
const result = {
|
|
35
49
|
eventId: "222",
|
|
36
50
|
scramble: formatCube2Algorithm(scrambleMoves),
|
|
@@ -41,8 +55,8 @@ export async function generateCube2Scramble(options = {}) {
|
|
|
41
55
|
state,
|
|
42
56
|
facelets,
|
|
43
57
|
faceletString: formatCube2Facelets(facelets),
|
|
44
|
-
solutionMoves
|
|
45
|
-
solutionDepth:
|
|
58
|
+
solutionMoves,
|
|
59
|
+
solutionDepth: depth
|
|
46
60
|
}
|
|
47
61
|
};
|
|
48
62
|
if (options.seed !== undefined) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export declare function getCachedBrowserTables(): {
|
|
2
2
|
permutationTable: Uint16Array;
|
|
3
3
|
orientationTable: Uint16Array;
|
|
4
|
-
|
|
4
|
+
policyTable: Uint8Array;
|
|
5
5
|
} | undefined;
|
|
6
6
|
export declare function clearCachedBrowserTables(): void;
|
|
7
7
|
export declare function loadBrowserTables(baseUrl?: string): Promise<{
|
|
8
8
|
permutationTable: Uint16Array;
|
|
9
9
|
orientationTable: Uint16Array;
|
|
10
|
-
|
|
10
|
+
policyTable: Uint8Array;
|
|
11
11
|
}>;
|
|
12
12
|
//# sourceMappingURL=browser-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/browser-loader.ts"],"names":[],"mappings":"AAWA,wBAAgB,sBAAsB;sBALlB,WAAW;sBACX,WAAW;
|
|
1
|
+
{"version":3,"file":"browser-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/browser-loader.ts"],"names":[],"mappings":"AAWA,wBAAgB,sBAAsB;sBALlB,WAAW;sBACX,WAAW;iBAChB,UAAU;cAKxB;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED,wBAAsB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjE,gBAAgB,EAAE,WAAW,CAAC;IAC9B,gBAAgB,EAAE,WAAW,CAAC;IAC9B,WAAW,EAAE,UAAU,CAAC;CACzB,CAAC,CAqBD"}
|
|
@@ -17,12 +17,12 @@ export async function loadBrowserTables(baseUrl) {
|
|
|
17
17
|
const [permTable, orientTable, dist] = await Promise.all([
|
|
18
18
|
fetchUint16Table(resolved, manifest.files.permutationTable, CUBE2_SOLVER_TABLE_METADATA.permutationTable.entries),
|
|
19
19
|
fetchUint16Table(resolved, manifest.files.orientationTable, CUBE2_SOLVER_TABLE_METADATA.orientationTable.entries),
|
|
20
|
-
fetchUint8Table(resolved, manifest.files.
|
|
20
|
+
fetchUint8Table(resolved, manifest.files.policy, CUBE2_SOLVER_TABLE_METADATA.policy.entries)
|
|
21
21
|
]);
|
|
22
22
|
cachedBrowserTables = {
|
|
23
23
|
permutationTable: permTable,
|
|
24
24
|
orientationTable: orientTable,
|
|
25
|
-
|
|
25
|
+
policyTable: dist
|
|
26
26
|
};
|
|
27
27
|
return cachedBrowserTables;
|
|
28
28
|
}
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated-assets.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/generated-assets.ts"],"names":[],"mappings":"AAYA,wBAAsB,8BAA8B,IAAI,OAAO,CAAC;IAC9D,gBAAgB,EAAE,WAAW,CAAC;IAC9B,gBAAgB,EAAE,WAAW,CAAC;IAC9B,
|
|
1
|
+
{"version":3,"file":"generated-assets.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/generated-assets.ts"],"names":[],"mappings":"AAYA,wBAAsB,8BAA8B,IAAI,OAAO,CAAC;IAC9D,gBAAgB,EAAE,WAAW,CAAC;IAC9B,gBAAgB,EAAE,WAAW,CAAC;IAC9B,WAAW,EAAE,UAAU,CAAC;CACzB,CAAC,CAeD"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { solveCube2State, verifyCube2Scramble, verifyCube2Solution } from "./search.js";
|
|
1
|
+
export { solveCube2State, solveCube2StateIndices, solveCube2StateIndicesSync, verifyCube2Scramble, verifyCube2Solution, verifyCube2SolutionIndices } from "./search.js";
|
|
2
2
|
export type { Cube2Solution } from "./search.js";
|
|
3
|
+
export { areCube2TablesLoaded, BFS_MOVES, POLICY_TABLE, ensureTablesLoaded, encodePermutation, encodeOrientation, getDistance, getPermutationTransition, getOrientationTransition, MOVE_COUNT, ORIENTATION_COUNT, ORIENTATION_TABLE, PERMUTATION_TABLE } from "./tables.js";
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,EACnB,0BAA0B,EAC3B,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,wBAAwB,EACxB,wBAAwB,EACxB,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,aAAa,CAAC"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { solveCube2State, verifyCube2Scramble, verifyCube2Solution } from "./search.js";
|
|
1
|
+
export { solveCube2State, solveCube2StateIndices, solveCube2StateIndicesSync, verifyCube2Scramble, verifyCube2Solution, verifyCube2SolutionIndices } from "./search.js";
|
|
2
|
+
export { areCube2TablesLoaded, BFS_MOVES, POLICY_TABLE, ensureTablesLoaded, encodePermutation, encodeOrientation, getDistance, getPermutationTransition, getOrientationTransition, MOVE_COUNT, ORIENTATION_COUNT, ORIENTATION_TABLE, PERMUTATION_TABLE } from "./tables.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/node-loader.ts"],"names":[],"mappings":"AAgBA,wBAAgB,8BAA8B,IAAI;IAChD,gBAAgB,EAAE,WAAW,CAAC;IAC9B,gBAAgB,EAAE,WAAW,CAAC;IAC9B,
|
|
1
|
+
{"version":3,"file":"node-loader.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/node-loader.ts"],"names":[],"mappings":"AAgBA,wBAAgB,8BAA8B,IAAI;IAChD,gBAAgB,EAAE,WAAW,CAAC;IAC9B,gBAAgB,EAAE,WAAW,CAAC;IAC9B,WAAW,EAAE,UAAU,CAAC;CACzB,CAmBA"}
|
|
@@ -11,11 +11,11 @@ export function readGeneratedCube2SolverTables() {
|
|
|
11
11
|
}
|
|
12
12
|
const permutationTable = readUint16Table(assetDirectory, manifest.files.permutationTable, CUBE2_SOLVER_TABLE_METADATA.permutationTable.checksum);
|
|
13
13
|
const orientationTable = readUint16Table(assetDirectory, manifest.files.orientationTable, CUBE2_SOLVER_TABLE_METADATA.orientationTable.checksum);
|
|
14
|
-
const
|
|
14
|
+
const policyTable = readUint8Table(assetDirectory, manifest.files.policy, CUBE2_SOLVER_TABLE_METADATA.policy.checksum);
|
|
15
15
|
return {
|
|
16
16
|
permutationTable,
|
|
17
17
|
orientationTable,
|
|
18
|
-
|
|
18
|
+
policyTable
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
function readUint16Table(assetDirectory, entry, expectedChecksum) {
|
|
@@ -5,6 +5,9 @@ export interface Cube2Solution {
|
|
|
5
5
|
state: Cube2State;
|
|
6
6
|
}
|
|
7
7
|
export declare function solveCube2State(state: Cube2State): Promise<Cube2Solution>;
|
|
8
|
+
export declare function solveCube2StateIndices(state: Cube2State): Promise<number[]>;
|
|
9
|
+
export declare function solveCube2StateIndicesSync(state: Cube2State): number[];
|
|
8
10
|
export declare function verifyCube2Scramble(state: Cube2State, scrambleMoves: readonly Cube2Move[]): boolean;
|
|
9
11
|
export declare function verifyCube2Solution(state: Cube2State, solutionMoves: readonly Cube2Move[]): boolean;
|
|
12
|
+
export declare function verifyCube2SolutionIndices(state: Cube2State, solution: readonly number[]): boolean;
|
|
10
13
|
//# sourceMappingURL=search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAczD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAczD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAQ/E;AAKD,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGjF;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,CAKtE;AAoDD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAUnG;AAGD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAOnG;AAMD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAclG"}
|
|
@@ -1,52 +1,49 @@
|
|
|
1
1
|
import { createSolvedCube2State } from "../state.js";
|
|
2
|
-
import { encodeOrientation, encodePermutation, ensureTablesLoaded, PERMUTATION_TABLE, ORIENTATION_TABLE,
|
|
2
|
+
import { encodeOrientation, encodePermutation, ensureTablesLoaded, PERMUTATION_TABLE, ORIENTATION_TABLE, POLICY_TABLE, ORIENTATION_COUNT, BFS_MOVES, MOVE_COUNT } from "./tables.js";
|
|
3
3
|
export async function solveCube2State(state) {
|
|
4
4
|
await ensureTablesLoaded();
|
|
5
|
+
const indices = solveWithTablesIndices(state);
|
|
6
|
+
return {
|
|
7
|
+
moves: indices.map((index) => BFS_MOVES[index]),
|
|
8
|
+
depth: indices.length,
|
|
9
|
+
state: createSolvedCube2State()
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
// Index-based solve for the hot scramble path: returns the solution as move
|
|
13
|
+
// indices (0..8) in walk order. The inverse of index m is CUBE2_MOVE_INVERSE[m]
|
|
14
|
+
// (U2/R2/F2 are self-inverse, so m ^ 1 does not apply here).
|
|
15
|
+
export async function solveCube2StateIndices(state) {
|
|
16
|
+
await ensureTablesLoaded();
|
|
17
|
+
return solveWithTablesIndices(state);
|
|
18
|
+
}
|
|
19
|
+
export function solveCube2StateIndicesSync(state) {
|
|
20
|
+
if (!POLICY_TABLE) {
|
|
21
|
+
throw new Error("Cube2 solver tables not loaded. Call ensureTablesLoaded() first.");
|
|
22
|
+
}
|
|
23
|
+
return solveWithTablesIndices(state);
|
|
24
|
+
}
|
|
25
|
+
function solveWithTablesIndices(state) {
|
|
5
26
|
if (state.corners.permutation[6] !== 6 || state.corners.orientation[6] !== 0) {
|
|
6
27
|
throw new Error("The 2x2 solver requires the DBL corner (index 6) to be solved " +
|
|
7
28
|
"as the frame of reference. Please normalize the state before solving.");
|
|
8
29
|
}
|
|
9
30
|
const permTable = PERMUTATION_TABLE;
|
|
10
31
|
const orientTable = ORIENTATION_TABLE;
|
|
11
|
-
const
|
|
32
|
+
const policy = POLICY_TABLE;
|
|
12
33
|
let permIndex = encodePermutation(state.corners.permutation);
|
|
13
34
|
let orientIndex = encodeOrientation(state.corners.orientation);
|
|
14
35
|
const moves = [];
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
let
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const orientOffset = orientIndex * MOVE_COUNT;
|
|
25
|
-
const nextDistance = distance - 1;
|
|
26
|
-
for (let m = 0; m < BFS_MOVES.length; m++) {
|
|
27
|
-
const nextPerm = permTable[permOffset + m];
|
|
28
|
-
const nextOrient = orientTable[orientOffset + m];
|
|
29
|
-
// High-performance branchless inlined lookup
|
|
30
|
-
const combined = nextPerm * ORIENTATION_COUNT + nextOrient;
|
|
31
|
-
const nextDist = (distances[combined >> 1] >> ((combined & 1) << 2)) & 0x0f;
|
|
32
|
-
if (nextDist === nextDistance) {
|
|
33
|
-
moves.push(BFS_MOVES[m]);
|
|
34
|
-
permIndex = nextPerm;
|
|
35
|
-
orientIndex = nextOrient;
|
|
36
|
-
distance = nextDistance;
|
|
37
|
-
foundNext = true;
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (!foundNext) {
|
|
42
|
-
throw new Error("BFS distance table corrupted or unreachable state.");
|
|
43
|
-
}
|
|
36
|
+
// Direct policy walk: the precomputed optimal move per state, so no
|
|
37
|
+
// candidate scanning (the old BFS-distance gradient walk) is needed.
|
|
38
|
+
let combined = permIndex * ORIENTATION_COUNT + orientIndex;
|
|
39
|
+
while (combined !== 0) {
|
|
40
|
+
const m = (policy[combined >> 1] >> ((combined & 1) << 2)) & 0x0f;
|
|
41
|
+
moves.push(m);
|
|
42
|
+
permIndex = permTable[permIndex * MOVE_COUNT + m];
|
|
43
|
+
orientIndex = orientTable[orientIndex * MOVE_COUNT + m];
|
|
44
|
+
combined = permIndex * ORIENTATION_COUNT + orientIndex;
|
|
44
45
|
}
|
|
45
|
-
return
|
|
46
|
-
moves,
|
|
47
|
-
depth: moves.length,
|
|
48
|
-
state: createSolvedCube2State()
|
|
49
|
-
};
|
|
46
|
+
return moves;
|
|
50
47
|
}
|
|
51
48
|
const MOVE_INDEX = {};
|
|
52
49
|
for (let i = 0; i < BFS_MOVES.length; i++) {
|
|
@@ -74,3 +71,21 @@ export function verifyCube2Solution(state, solutionMoves) {
|
|
|
74
71
|
const { permIndex, orientIndex } = walkCube2Coordinates(encodePermutation(state.corners.permutation), encodeOrientation(state.corners.orientation), solutionMoves);
|
|
75
72
|
return permIndex === 0 && orientIndex === 0;
|
|
76
73
|
}
|
|
74
|
+
// Numeric verification for the hot scramble path: walks the solution (move
|
|
75
|
+
// indices, walk order) from the target state to solved. The scramble is the
|
|
76
|
+
// exact inverse of the solution, so this is equivalent to verifying that the
|
|
77
|
+
// scramble reproduces the target state — one walk, no string parsing.
|
|
78
|
+
export function verifyCube2SolutionIndices(state, solution) {
|
|
79
|
+
const permTable = PERMUTATION_TABLE;
|
|
80
|
+
const orientTable = ORIENTATION_TABLE;
|
|
81
|
+
if (!permTable || !orientTable) {
|
|
82
|
+
throw new Error("Cube2 solver tables not loaded. Call ensureTablesLoaded() first.");
|
|
83
|
+
}
|
|
84
|
+
let permIndex = encodePermutation(state.corners.permutation);
|
|
85
|
+
let orientIndex = encodeOrientation(state.corners.orientation);
|
|
86
|
+
for (const m of solution) {
|
|
87
|
+
permIndex = permTable[permIndex * MOVE_COUNT + m];
|
|
88
|
+
orientIndex = orientTable[orientIndex * MOVE_COUNT + m];
|
|
89
|
+
}
|
|
90
|
+
return permIndex === 0 && orientIndex === 0;
|
|
91
|
+
}
|
|
@@ -7,9 +7,9 @@ export declare const CUBE2_SOLVER_TABLE_METADATA: {
|
|
|
7
7
|
readonly entries: 6561;
|
|
8
8
|
readonly checksum: 1566738619;
|
|
9
9
|
};
|
|
10
|
-
readonly
|
|
10
|
+
readonly policy: {
|
|
11
11
|
readonly entries: 1837080;
|
|
12
|
-
readonly checksum:
|
|
12
|
+
readonly checksum: 2042005723;
|
|
13
13
|
readonly maxDepth: 11;
|
|
14
14
|
};
|
|
15
15
|
};
|
|
@@ -5,8 +5,9 @@ export declare function encodePermutation(permutation: readonly number[]): numbe
|
|
|
5
5
|
export declare function encodeOrientation(orientation: readonly number[]): number;
|
|
6
6
|
export declare let PERMUTATION_TABLE: Uint16Array | null;
|
|
7
7
|
export declare let ORIENTATION_TABLE: Uint16Array | null;
|
|
8
|
-
export declare let
|
|
8
|
+
export declare let POLICY_TABLE: Uint8Array | null;
|
|
9
9
|
export declare function ensureTablesLoaded(): Promise<void>;
|
|
10
|
+
export declare function areCube2TablesLoaded(): boolean;
|
|
10
11
|
export declare function getDistance(permIndex: number, orientIndex: number): number;
|
|
11
12
|
export declare function getPermutationTransition(move: number, permIndex: number): number;
|
|
12
13
|
export declare function getOrientationTransition(move: number, orientIndex: number): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/tables.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,UAAU,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../../src/puzzles/cube2/solver/tables.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,UAAU,IAAI,CAAC;AAW5B,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAYxE;AAWD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAWxE;AAeD,eAAO,IAAI,iBAAiB,EAAE,WAAW,GAAG,IAAW,CAAC;AACxD,eAAO,IAAI,iBAAiB,EAAE,WAAW,GAAG,IAAW,CAAC;AACxD,eAAO,IAAI,YAAY,EAAE,UAAU,GAAG,IAAW,CAAC;AAElD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUxD;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAMD,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAkB1E;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAKlF;AAED,eAAO,MAAM,SAAS,EAAE,SAAS,MAAM,EAItC,CAAC"}
|
|
@@ -5,19 +5,31 @@ export const MOVE_COUNT = 9;
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Coordinate encoding / decoding
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
|
+
// Lehmer encoding of the 7 free corners (DBL at index 6 is fixed), with a
|
|
9
|
+
// bitmask instead of array removal: available values tracked as bits, the
|
|
10
|
+
// rank of a value = the popcount of the bits below it.
|
|
11
|
+
const PERM7_FACT = [720, 120, 24, 6, 2, 1, 1];
|
|
8
12
|
export function encodePermutation(permutation) {
|
|
9
|
-
const perm7 = permutation.filter((_, i) => i !== 6);
|
|
10
|
-
const mapped = perm7.map((x) => (x > 6 ? x - 1 : x));
|
|
11
13
|
let index = 0;
|
|
12
|
-
|
|
14
|
+
let available = 0b1111111;
|
|
13
15
|
for (let position = 0; position < 7; position += 1) {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
available
|
|
16
|
+
const permPosition = position < 6 ? position : position + 1;
|
|
17
|
+
const piece = permutation[permPosition];
|
|
18
|
+
const value = piece > 6 ? piece - 1 : piece;
|
|
19
|
+
const rank = popcount(available & ((1 << value) - 1));
|
|
20
|
+
index += rank * PERM7_FACT[position];
|
|
21
|
+
available &= ~(1 << value);
|
|
18
22
|
}
|
|
19
23
|
return index;
|
|
20
24
|
}
|
|
25
|
+
function popcount(x) {
|
|
26
|
+
let count = 0;
|
|
27
|
+
while (x !== 0) {
|
|
28
|
+
x &= x - 1;
|
|
29
|
+
count += 1;
|
|
30
|
+
}
|
|
31
|
+
return count;
|
|
32
|
+
}
|
|
21
33
|
export function encodeOrientation(orientation) {
|
|
22
34
|
const orient7 = orientation.filter((_, i) => i !== 6);
|
|
23
35
|
let index = 0;
|
|
@@ -41,7 +53,7 @@ function factorialSmall(n) {
|
|
|
41
53
|
let tablesLoaded = false;
|
|
42
54
|
export let PERMUTATION_TABLE = null;
|
|
43
55
|
export let ORIENTATION_TABLE = null;
|
|
44
|
-
export let
|
|
56
|
+
export let POLICY_TABLE = null;
|
|
45
57
|
export async function ensureTablesLoaded() {
|
|
46
58
|
if (tablesLoaded) {
|
|
47
59
|
return;
|
|
@@ -49,19 +61,33 @@ export async function ensureTablesLoaded() {
|
|
|
49
61
|
const tables = await loadGeneratedCube2SolverTables();
|
|
50
62
|
PERMUTATION_TABLE = tables.permutationTable;
|
|
51
63
|
ORIENTATION_TABLE = tables.orientationTable;
|
|
52
|
-
|
|
64
|
+
POLICY_TABLE = tables.policyTable;
|
|
53
65
|
tablesLoaded = true;
|
|
54
66
|
}
|
|
67
|
+
export function areCube2TablesLoaded() {
|
|
68
|
+
return tablesLoaded;
|
|
69
|
+
}
|
|
55
70
|
// ---------------------------------------------------------------------------
|
|
56
71
|
// Public API
|
|
57
72
|
// ---------------------------------------------------------------------------
|
|
58
73
|
export function getDistance(permIndex, orientIndex) {
|
|
59
|
-
if (!
|
|
74
|
+
if (!POLICY_TABLE) {
|
|
60
75
|
throw new Error("Cube2 solver tables not loaded. Call ensureTablesLoaded() first.");
|
|
61
76
|
}
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
|
|
77
|
+
const permTable = PERMUTATION_TABLE;
|
|
78
|
+
const orientTable = ORIENTATION_TABLE;
|
|
79
|
+
let p = permIndex;
|
|
80
|
+
let o = orientIndex;
|
|
81
|
+
let combined = p * ORIENTATION_COUNT + o;
|
|
82
|
+
let distance = 0;
|
|
83
|
+
while (combined !== 0) {
|
|
84
|
+
const m = (POLICY_TABLE[combined >> 1] >> ((combined & 1) << 2)) & 0x0f;
|
|
85
|
+
p = permTable[p * MOVE_COUNT + m];
|
|
86
|
+
o = orientTable[o * MOVE_COUNT + m];
|
|
87
|
+
combined = p * ORIENTATION_COUNT + o;
|
|
88
|
+
distance += 1;
|
|
89
|
+
}
|
|
90
|
+
return distance;
|
|
65
91
|
}
|
|
66
92
|
export function getPermutationTransition(move, permIndex) {
|
|
67
93
|
if (!PERMUTATION_TABLE) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,wBAAgB,sBAAsB,IAAI,UAAU,CAOnD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAO7D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAK7E;
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/puzzles/cube2/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,wBAAgB,sBAAsB,IAAI,UAAU,CAOnD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAO7D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAK7E;AAKD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAE7D"}
|