@cubingcenter/scrambler 0.4.0 → 0.5.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 +67 -3
- package/dist/core/api.d.ts.map +1 -1
- package/dist/core/api.js +18 -6
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/puzzles/clock/index.d.ts +1 -0
- package/dist/puzzles/clock/index.d.ts.map +1 -1
- package/dist/puzzles/clock/index.js +4 -0
- package/dist/puzzles/cube2/index.d.ts +1 -0
- package/dist/puzzles/cube2/index.d.ts.map +1 -1
- package/dist/puzzles/cube2/index.js +4 -0
- package/dist/puzzles/cube2/scrambler.d.ts.map +1 -1
- package/dist/puzzles/cube2/scrambler.js +4 -6
- package/dist/puzzles/cube2/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/browser-loader.js +4 -12
- package/dist/puzzles/cube2/solver/index.d.ts +1 -1
- package/dist/puzzles/cube2/solver/index.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/index.js +1 -1
- package/dist/puzzles/cube2/solver/search.d.ts +2 -0
- package/dist/puzzles/cube2/solver/search.d.ts.map +1 -1
- package/dist/puzzles/cube2/solver/search.js +26 -0
- package/dist/puzzles/cube2/validation.d.ts.map +1 -1
- package/dist/puzzles/cube2/validation.js +15 -3
- package/dist/puzzles/cube3/index.d.ts +1 -0
- package/dist/puzzles/cube3/index.d.ts.map +1 -1
- package/dist/puzzles/cube3/index.js +4 -0
- package/dist/puzzles/cube3/solver/browser-loader.d.ts.map +1 -1
- package/dist/puzzles/cube3/solver/browser-loader.js +5 -29
- package/dist/puzzles/cube4/index.d.ts +1 -0
- package/dist/puzzles/cube4/index.d.ts.map +1 -1
- package/dist/puzzles/cube4/index.js +4 -0
- package/dist/puzzles/cube5x5/index.d.ts +1 -0
- package/dist/puzzles/cube5x5/index.d.ts.map +1 -1
- package/dist/puzzles/cube5x5/index.js +4 -0
- package/dist/puzzles/cube6x6/index.d.ts +1 -0
- package/dist/puzzles/cube6x6/index.d.ts.map +1 -1
- package/dist/puzzles/cube6x6/index.js +4 -0
- package/dist/puzzles/cube7x7/index.d.ts +1 -0
- package/dist/puzzles/cube7x7/index.d.ts.map +1 -1
- package/dist/puzzles/cube7x7/index.js +4 -0
- package/dist/puzzles/megaminx/index.d.ts +1 -0
- package/dist/puzzles/megaminx/index.d.ts.map +1 -1
- package/dist/puzzles/megaminx/index.js +4 -0
- package/dist/puzzles/pyraminx/index.d.ts +3 -1
- package/dist/puzzles/pyraminx/index.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/index.js +6 -1
- package/dist/puzzles/pyraminx/scrambler.d.ts.map +1 -1
- package/dist/puzzles/pyraminx/scrambler.js +24 -20
- package/dist/puzzles/pyraminx/solver/browser-loader.d.ts +14 -0
- package/dist/puzzles/pyraminx/solver/browser-loader.d.ts.map +1 -0
- package/dist/puzzles/pyraminx/solver/browser-loader.js +63 -0
- package/dist/puzzles/pyraminx/solver/generated/centers-table.bin +0 -0
- package/dist/puzzles/pyraminx/solver/generated/manifest.json +26 -0
- package/dist/puzzles/pyraminx/solver/generated/orientation-table.bin +0 -0
- package/dist/puzzles/pyraminx/solver/generated/permutation-table.bin +0 -0
- package/dist/puzzles/pyraminx/solver/generated/policy.bin +0 -0
- package/dist/puzzles/pyraminx/solver/generated-assets.d.ts +7 -0
- package/dist/puzzles/pyraminx/solver/generated-assets.d.ts.map +1 -0
- package/dist/puzzles/pyraminx/solver/generated-assets.js +24 -0
- package/dist/puzzles/pyraminx/solver/index.d.ts +5 -0
- package/dist/puzzles/pyraminx/solver/index.d.ts.map +1 -0
- package/dist/puzzles/pyraminx/solver/index.js +4 -0
- package/dist/puzzles/pyraminx/solver/node-loader.d.ts +7 -0
- package/dist/puzzles/pyraminx/solver/node-loader.d.ts.map +1 -0
- package/dist/puzzles/pyraminx/solver/node-loader.js +73 -0
- package/dist/puzzles/pyraminx/solver/search.d.ts +10 -0
- package/dist/puzzles/pyraminx/solver/search.d.ts.map +1 -0
- package/dist/puzzles/pyraminx/solver/search.js +82 -0
- package/dist/puzzles/pyraminx/solver/table-metadata.d.ts +20 -0
- package/dist/puzzles/pyraminx/solver/table-metadata.d.ts.map +1 -0
- package/dist/puzzles/pyraminx/solver/table-metadata.js +19 -0
- package/dist/puzzles/pyraminx/solver/tables.d.ts +43 -0
- package/dist/puzzles/pyraminx/solver/tables.d.ts.map +1 -0
- package/dist/puzzles/pyraminx/solver/tables.js +300 -0
- package/dist/puzzles/shared/compressed-fetch.d.ts +12 -0
- package/dist/puzzles/shared/compressed-fetch.d.ts.map +1 -0
- package/dist/puzzles/shared/compressed-fetch.js +68 -0
- package/dist/puzzles/skewb/facelets.d.ts.map +1 -1
- package/dist/puzzles/skewb/facelets.js +46 -23
- package/dist/puzzles/skewb/index.d.ts +3 -1
- package/dist/puzzles/skewb/index.d.ts.map +1 -1
- package/dist/puzzles/skewb/index.js +6 -1
- package/dist/puzzles/skewb/random-state.d.ts +1 -1
- package/dist/puzzles/skewb/random-state.d.ts.map +1 -1
- package/dist/puzzles/skewb/random-state.js +25 -18
- package/dist/puzzles/skewb/scrambler.d.ts.map +1 -1
- package/dist/puzzles/skewb/scrambler.js +10 -13
- package/dist/puzzles/skewb/solver/browser-loader.d.ts +20 -0
- package/dist/puzzles/skewb/solver/browser-loader.d.ts.map +1 -0
- package/dist/puzzles/skewb/solver/browser-loader.js +86 -0
- package/dist/puzzles/skewb/solver/generated/centers-table.bin +0 -0
- package/dist/puzzles/skewb/solver/generated/helpers.bin +0 -0
- package/dist/puzzles/skewb/solver/generated/manifest.json +31 -0
- package/dist/puzzles/skewb/solver/generated/orientation-table.bin +0 -0
- package/dist/puzzles/skewb/solver/generated/permutation-table.bin +0 -0
- package/dist/puzzles/skewb/solver/generated/policy.bin +0 -0
- package/dist/puzzles/skewb/solver/generated-assets.d.ts +10 -0
- package/dist/puzzles/skewb/solver/generated-assets.d.ts.map +1 -0
- package/dist/puzzles/skewb/solver/generated-assets.js +24 -0
- package/dist/puzzles/skewb/solver/index.d.ts +5 -0
- package/dist/puzzles/skewb/solver/index.d.ts.map +1 -0
- package/dist/puzzles/skewb/solver/index.js +4 -0
- package/dist/puzzles/skewb/solver/node-loader.d.ts +10 -0
- package/dist/puzzles/skewb/solver/node-loader.d.ts.map +1 -0
- package/dist/puzzles/skewb/solver/node-loader.js +91 -0
- package/dist/puzzles/skewb/solver/search.d.ts +11 -0
- package/dist/puzzles/skewb/solver/search.d.ts.map +1 -0
- package/dist/puzzles/skewb/solver/search.js +80 -0
- package/dist/puzzles/skewb/solver/table-metadata.d.ts +27 -0
- package/dist/puzzles/skewb/solver/table-metadata.d.ts.map +1 -0
- package/dist/puzzles/skewb/solver/table-metadata.js +26 -0
- package/dist/puzzles/skewb/solver/tables.d.ts +68 -0
- package/dist/puzzles/skewb/solver/tables.d.ts.map +1 -0
- package/dist/puzzles/skewb/solver/tables.js +508 -0
- package/dist/random/prng.js +10 -1
- package/dist-cjs/core/api.js +51 -6
- package/dist-cjs/puzzles/clock/index.js +13 -4
- package/dist-cjs/puzzles/cube2/index.js +13 -4
- package/dist-cjs/puzzles/cube2/scrambler.js +2 -4
- package/dist-cjs/puzzles/cube2/solver/browser-loader.js +4 -12
- package/dist-cjs/puzzles/cube2/solver/index.js +3 -1
- package/dist-cjs/puzzles/cube2/solver/search.js +28 -0
- package/dist-cjs/puzzles/cube2/validation.js +14 -2
- package/dist-cjs/puzzles/cube3/index.js +13 -4
- package/dist-cjs/puzzles/cube3/solver/browser-loader.js +5 -29
- package/dist-cjs/puzzles/cube4/index.js +13 -4
- package/dist-cjs/puzzles/cube5x5/index.js +13 -4
- package/dist-cjs/puzzles/cube6x6/index.js +13 -4
- package/dist-cjs/puzzles/cube7x7/index.js +13 -4
- package/dist-cjs/puzzles/megaminx/index.js +13 -4
- package/dist-cjs/puzzles/pyraminx/index.js +50 -6
- package/dist-cjs/puzzles/pyraminx/scrambler.js +23 -19
- package/dist-cjs/puzzles/pyraminx/solver/browser-loader.js +68 -0
- package/dist-cjs/puzzles/pyraminx/solver/generated/centers-table.bin +0 -0
- package/dist-cjs/puzzles/pyraminx/solver/generated/manifest.json +26 -0
- package/dist-cjs/puzzles/pyraminx/solver/generated/orientation-table.bin +0 -0
- package/dist-cjs/puzzles/pyraminx/solver/generated/permutation-table.bin +0 -0
- package/dist-cjs/puzzles/pyraminx/solver/generated/policy.bin +0 -0
- package/dist-cjs/puzzles/pyraminx/solver/generated-assets.js +60 -0
- package/dist-cjs/puzzles/pyraminx/solver/index.js +23 -0
- package/dist-cjs/puzzles/pyraminx/solver/node-loader.js +79 -0
- package/dist-cjs/puzzles/pyraminx/solver/search.js +88 -0
- package/dist-cjs/puzzles/pyraminx/solver/table-metadata.js +22 -0
- package/dist-cjs/puzzles/pyraminx/solver/tables.js +327 -0
- package/dist-cjs/puzzles/shared/compressed-fetch.js +71 -0
- package/dist-cjs/puzzles/skewb/facelets.js +46 -23
- package/dist-cjs/puzzles/skewb/index.js +55 -8
- package/dist-cjs/puzzles/skewb/random-state.js +25 -18
- package/dist-cjs/puzzles/skewb/scrambler.js +9 -12
- package/dist-cjs/puzzles/skewb/solver/browser-loader.js +91 -0
- package/dist-cjs/puzzles/skewb/solver/generated/centers-table.bin +0 -0
- package/dist-cjs/puzzles/skewb/solver/generated/helpers.bin +0 -0
- package/dist-cjs/puzzles/skewb/solver/generated/manifest.json +31 -0
- package/dist-cjs/puzzles/skewb/solver/generated/orientation-table.bin +0 -0
- package/dist-cjs/puzzles/skewb/solver/generated/permutation-table.bin +0 -0
- package/dist-cjs/puzzles/skewb/solver/generated/policy.bin +0 -0
- package/dist-cjs/puzzles/skewb/solver/generated-assets.js +60 -0
- package/dist-cjs/puzzles/skewb/solver/index.js +23 -0
- package/dist-cjs/puzzles/skewb/solver/node-loader.js +97 -0
- package/dist-cjs/puzzles/skewb/solver/search.js +87 -0
- package/dist-cjs/puzzles/skewb/solver/table-metadata.js +29 -0
- package/dist-cjs/puzzles/skewb/solver/tables.js +539 -0
- package/dist-cjs/random/prng.js +10 -1
- package/package.json +20 -6
- package/dist/puzzles/pyraminx/solver.d.ts +0 -10
- package/dist/puzzles/pyraminx/solver.d.ts.map +0 -1
- package/dist/puzzles/pyraminx/solver.js +0 -160
- package/dist/puzzles/skewb/solver.d.ts +0 -11
- package/dist/puzzles/skewb/solver.d.ts.map +0 -1
- package/dist/puzzles/skewb/solver.js +0 -149
- package/dist-cjs/puzzles/pyraminx/solver.js +0 -170
- package/dist-cjs/puzzles/skewb/solver.js +0 -160
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { applyPyraminxMove } from "./moves.js";
|
|
2
|
-
import { createSolvedPyraminxState } from "./state.js";
|
|
3
|
-
// Fast state-to-index encoder/decoder to allow optimal BFS solving
|
|
4
|
-
// Factorials for permutation encoding
|
|
5
|
-
const FACT = [1, 1, 2, 6, 24, 120, 720];
|
|
6
|
-
export function getPermutationIndex(perm) {
|
|
7
|
-
let index = 0;
|
|
8
|
-
const n = perm.length;
|
|
9
|
-
for (let i = 0; i < n; i++) {
|
|
10
|
-
let count = 0;
|
|
11
|
-
for (let j = i + 1; j < n; j++) {
|
|
12
|
-
if (perm[j] < perm[i])
|
|
13
|
-
count++;
|
|
14
|
-
}
|
|
15
|
-
index += count * FACT[n - 1 - i];
|
|
16
|
-
}
|
|
17
|
-
return index;
|
|
18
|
-
}
|
|
19
|
-
export function getPermutationFromIndex(index, n) {
|
|
20
|
-
const perm = Array(n).fill(0);
|
|
21
|
-
const temp = Array.from({ length: n }, (_, i) => i);
|
|
22
|
-
let val = index;
|
|
23
|
-
for (let i = 0; i < n; i++) {
|
|
24
|
-
const f = FACT[n - 1 - i];
|
|
25
|
-
const choice = Math.floor(val / f);
|
|
26
|
-
val %= f;
|
|
27
|
-
perm[i] = temp[choice];
|
|
28
|
-
temp.splice(choice, 1);
|
|
29
|
-
}
|
|
30
|
-
return perm;
|
|
31
|
-
}
|
|
32
|
-
export function getOrientationIndex(orient) {
|
|
33
|
-
let index = 0;
|
|
34
|
-
for (let i = 0; i < 5; i++) {
|
|
35
|
-
index = (index << 1) | orient[i];
|
|
36
|
-
}
|
|
37
|
-
return index;
|
|
38
|
-
}
|
|
39
|
-
export function getOrientationFromIndex(index) {
|
|
40
|
-
const orient = Array(6).fill(0);
|
|
41
|
-
let temp = index;
|
|
42
|
-
let sum = 0;
|
|
43
|
-
for (let i = 4; i >= 0; i--) {
|
|
44
|
-
const bit = temp & 1;
|
|
45
|
-
orient[i] = bit;
|
|
46
|
-
sum += bit;
|
|
47
|
-
temp >>= 1;
|
|
48
|
-
}
|
|
49
|
-
orient[5] = sum % 2 === 0 ? 0 : 1;
|
|
50
|
-
return orient;
|
|
51
|
-
}
|
|
52
|
-
export function getCentersIndex(centers) {
|
|
53
|
-
return centers[0] + 3 * centers[1] + 9 * centers[2] + 27 * centers[3];
|
|
54
|
-
}
|
|
55
|
-
export function getCentersFromIndex(index) {
|
|
56
|
-
let temp = index;
|
|
57
|
-
const centers = Array(4).fill(0);
|
|
58
|
-
for (let i = 0; i < 4; i++) {
|
|
59
|
-
centers[i] = temp % 3;
|
|
60
|
-
temp = Math.floor(temp / 3);
|
|
61
|
-
}
|
|
62
|
-
return centers;
|
|
63
|
-
}
|
|
64
|
-
export function getStateIndex(state) {
|
|
65
|
-
const c = getCentersIndex(state.centers);
|
|
66
|
-
const p = getPermutationIndex(state.edgesPerm);
|
|
67
|
-
const o = getOrientationIndex(state.edgesOrient);
|
|
68
|
-
// c is 0..80, p is 0..719, o is 0..31
|
|
69
|
-
return c + 81 * (p + 720 * o);
|
|
70
|
-
}
|
|
71
|
-
// Bidirectional BFS solver
|
|
72
|
-
const MOVES = ["U", "U'", "L", "L'", "R", "R'", "B", "B'"];
|
|
73
|
-
export function solvePyraminx(state) {
|
|
74
|
-
const startIdx = getStateIndex(state);
|
|
75
|
-
const solvedIdx = getStateIndex(createSolvedPyraminxState());
|
|
76
|
-
if (startIdx === solvedIdx)
|
|
77
|
-
return [];
|
|
78
|
-
// Bidirectional BFS:
|
|
79
|
-
// forwardMap and backwardMap store the move that led to this index and the parent index
|
|
80
|
-
const forwardMap = new Map();
|
|
81
|
-
const backwardMap = new Map();
|
|
82
|
-
const forwardQueue = [startIdx];
|
|
83
|
-
const backwardQueue = [solvedIdx];
|
|
84
|
-
forwardMap.set(startIdx, { move: "", parent: -1 });
|
|
85
|
-
backwardMap.set(solvedIdx, { move: "", parent: -1 });
|
|
86
|
-
while (forwardQueue.length > 0 && backwardQueue.length > 0) {
|
|
87
|
-
// Expand forward
|
|
88
|
-
const fSize = forwardQueue.length;
|
|
89
|
-
for (let i = 0; i < Math.min(fSize, 1000); i++) {
|
|
90
|
-
const currIdx = forwardQueue.shift();
|
|
91
|
-
const currState = getPyraminxStateFromIndex(currIdx);
|
|
92
|
-
for (const move of MOVES) {
|
|
93
|
-
const nextState = applyPyraminxMove(currState, move);
|
|
94
|
-
const nextIdx = getStateIndex(nextState);
|
|
95
|
-
if (!forwardMap.has(nextIdx)) {
|
|
96
|
-
forwardMap.set(nextIdx, { move, parent: currIdx });
|
|
97
|
-
if (backwardMap.has(nextIdx)) {
|
|
98
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
99
|
-
}
|
|
100
|
-
forwardQueue.push(nextIdx);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// Expand backward
|
|
105
|
-
const bSize = backwardQueue.length;
|
|
106
|
-
for (let i = 0; i < Math.min(bSize, 1000); i++) {
|
|
107
|
-
const currIdx = backwardQueue.shift();
|
|
108
|
-
const currState = getPyraminxStateFromIndex(currIdx);
|
|
109
|
-
for (const move of MOVES) {
|
|
110
|
-
const nextState = applyPyraminxMove(currState, move);
|
|
111
|
-
const nextIdx = getStateIndex(nextState);
|
|
112
|
-
if (!backwardMap.has(nextIdx)) {
|
|
113
|
-
// Note: we record the inverse move since we are searching from solved
|
|
114
|
-
const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
|
|
115
|
-
backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
|
|
116
|
-
if (forwardMap.has(nextIdx)) {
|
|
117
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
118
|
-
}
|
|
119
|
-
backwardQueue.push(nextIdx);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
throw new Error("Pyraminx state is unsolvable");
|
|
125
|
-
}
|
|
126
|
-
function getPyraminxStateFromIndex(index) {
|
|
127
|
-
let val = index;
|
|
128
|
-
const centersIdx = val % 81;
|
|
129
|
-
val = Math.floor(val / 81);
|
|
130
|
-
const permIdx = val % 720;
|
|
131
|
-
const orientIdx = Math.floor(val / 720);
|
|
132
|
-
return {
|
|
133
|
-
centers: getCentersFromIndex(centersIdx),
|
|
134
|
-
edgesPerm: getPermutationFromIndex(permIdx, 6),
|
|
135
|
-
edgesOrient: getOrientationFromIndex(orientIdx),
|
|
136
|
-
tips: [0, 0, 0, 0] // tips are solved separately
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
function reconstructPath(meetingIdx, forwardMap, backwardMap) {
|
|
140
|
-
const path = [];
|
|
141
|
-
// Reconstruct forward path
|
|
142
|
-
let curr = meetingIdx;
|
|
143
|
-
while (curr !== -1) {
|
|
144
|
-
const edge = forwardMap.get(curr);
|
|
145
|
-
if (edge.parent !== -1) {
|
|
146
|
-
path.unshift(edge.move);
|
|
147
|
-
}
|
|
148
|
-
curr = edge.parent;
|
|
149
|
-
}
|
|
150
|
-
// Reconstruct backward path
|
|
151
|
-
curr = meetingIdx;
|
|
152
|
-
while (curr !== -1) {
|
|
153
|
-
const edge = backwardMap.get(curr);
|
|
154
|
-
if (edge.parent !== -1) {
|
|
155
|
-
path.push(edge.move);
|
|
156
|
-
}
|
|
157
|
-
curr = edge.parent;
|
|
158
|
-
}
|
|
159
|
-
return path;
|
|
160
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { SkewbMove, SkewbState } from "./types.js";
|
|
2
|
-
export declare function getPermutationIndex(perm: readonly number[]): number;
|
|
3
|
-
export declare function getPermutationFromIndex(index: number, n: number): number[];
|
|
4
|
-
export declare function getOrientationIndex(orient: readonly number[]): number;
|
|
5
|
-
export declare function getOrientationFromIndex(index: number): number[];
|
|
6
|
-
export declare function getCenterIndex(centers: readonly number[]): number;
|
|
7
|
-
export declare function getCenterFromIndex(index: number): number[];
|
|
8
|
-
export declare function getStateIndex(state: SkewbState): number;
|
|
9
|
-
export declare function getStateFromIndex(index: number): SkewbState;
|
|
10
|
-
export declare function solveSkewb(state: SkewbState): SkewbMove[];
|
|
11
|
-
//# sourceMappingURL=solver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"solver.d.ts","sourceRoot":"","sources":["../../../src/puzzles/skewb/solver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAWnE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAY1E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAOrE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAS/D;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CASjE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE1D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAOvD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAY3D;AAID,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,EAAE,CA+CzD"}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { applySkewbMove } from "./moves.js";
|
|
2
|
-
import { createSolvedSkewbState } from "./state.js";
|
|
3
|
-
const FACT = [1, 1, 2, 6, 24, 120, 720, 5040, 40320];
|
|
4
|
-
export function getPermutationIndex(perm) {
|
|
5
|
-
// perm length 8, but pos0 is always 0 for WCA reachable states.
|
|
6
|
-
// We encode full 8-perm via Lehmer code (0..40319), but for fixed corner it will be in subset.
|
|
7
|
-
let index = 0;
|
|
8
|
-
const n = perm.length;
|
|
9
|
-
for (let i = 0; i < n; i++) {
|
|
10
|
-
let count = 0;
|
|
11
|
-
for (let j = i + 1; j < n; j++)
|
|
12
|
-
if (perm[j] < perm[i])
|
|
13
|
-
count++;
|
|
14
|
-
index += count * FACT[n - 1 - i];
|
|
15
|
-
}
|
|
16
|
-
return index;
|
|
17
|
-
}
|
|
18
|
-
export function getPermutationFromIndex(index, n) {
|
|
19
|
-
const perm = Array(n).fill(0);
|
|
20
|
-
const temp = Array.from({ length: n }, (_, i) => i);
|
|
21
|
-
let val = index;
|
|
22
|
-
for (let i = 0; i < n; i++) {
|
|
23
|
-
const f = FACT[n - 1 - i];
|
|
24
|
-
const choice = Math.floor(val / f);
|
|
25
|
-
val %= f;
|
|
26
|
-
perm[i] = temp[choice];
|
|
27
|
-
temp.splice(choice, 1);
|
|
28
|
-
}
|
|
29
|
-
return perm;
|
|
30
|
-
}
|
|
31
|
-
export function getOrientationIndex(orient) {
|
|
32
|
-
// orient length 8, index 0 is fixed 0, encode remaining 7 base3
|
|
33
|
-
let index = 0;
|
|
34
|
-
for (let i = 7; i >= 1; i--) {
|
|
35
|
-
index = index * 3 + orient[i];
|
|
36
|
-
}
|
|
37
|
-
return index;
|
|
38
|
-
}
|
|
39
|
-
export function getOrientationFromIndex(index) {
|
|
40
|
-
const orient = Array(8).fill(0);
|
|
41
|
-
orient[0] = 0;
|
|
42
|
-
let val = index;
|
|
43
|
-
for (let i = 1; i < 8; i++) {
|
|
44
|
-
orient[i] = val % 3;
|
|
45
|
-
val = Math.floor(val / 3);
|
|
46
|
-
}
|
|
47
|
-
return orient;
|
|
48
|
-
}
|
|
49
|
-
export function getCenterIndex(centers) {
|
|
50
|
-
let index = 0;
|
|
51
|
-
const n = centers.length;
|
|
52
|
-
for (let i = 0; i < n; i++) {
|
|
53
|
-
let count = 0;
|
|
54
|
-
for (let j = i + 1; j < n; j++)
|
|
55
|
-
if (centers[j] < centers[i])
|
|
56
|
-
count++;
|
|
57
|
-
index += count * FACT[n - 1 - i];
|
|
58
|
-
}
|
|
59
|
-
return index;
|
|
60
|
-
}
|
|
61
|
-
export function getCenterFromIndex(index) {
|
|
62
|
-
return getPermutationFromIndex(index, 6);
|
|
63
|
-
}
|
|
64
|
-
export function getStateIndex(state) {
|
|
65
|
-
const p = getPermutationIndex(state.corners.permutation);
|
|
66
|
-
const c = getCenterIndex(state.centers);
|
|
67
|
-
const o = getOrientationIndex(state.corners.orientation);
|
|
68
|
-
// p in 0..40319, c in 0..719, o in 0..2186
|
|
69
|
-
// Combine: ((p * 720 + c) * 2187 + o) -> up to 63B fits in JS number (53-bit)
|
|
70
|
-
return ((p * 720 + c) * 2187 + o);
|
|
71
|
-
}
|
|
72
|
-
export function getStateFromIndex(index) {
|
|
73
|
-
const o = index % 2187;
|
|
74
|
-
let val = Math.floor(index / 2187);
|
|
75
|
-
const c = val % 720;
|
|
76
|
-
const p = Math.floor(val / 720);
|
|
77
|
-
return {
|
|
78
|
-
corners: {
|
|
79
|
-
permutation: getPermutationFromIndex(p, 8),
|
|
80
|
-
orientation: getOrientationFromIndex(o),
|
|
81
|
-
},
|
|
82
|
-
centers: getCenterFromIndex(c),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
const MOVES = ["R", "R'", "U", "U'", "L", "L'", "B", "B'"];
|
|
86
|
-
export function solveSkewb(state) {
|
|
87
|
-
const startIdx = getStateIndex(state);
|
|
88
|
-
const solvedIdx = getStateIndex(createSolvedSkewbState());
|
|
89
|
-
if (startIdx === solvedIdx)
|
|
90
|
-
return [];
|
|
91
|
-
const forwardMap = new Map();
|
|
92
|
-
const backwardMap = new Map();
|
|
93
|
-
const forwardQueue = [startIdx];
|
|
94
|
-
const backwardQueue = [solvedIdx];
|
|
95
|
-
forwardMap.set(startIdx, { move: "", parent: -1 });
|
|
96
|
-
backwardMap.set(solvedIdx, { move: "", parent: -1 });
|
|
97
|
-
while (forwardQueue.length > 0 && backwardQueue.length > 0) {
|
|
98
|
-
const fSize = forwardQueue.length;
|
|
99
|
-
for (let i = 0; i < Math.min(fSize, 1000); i++) {
|
|
100
|
-
const currIdx = forwardQueue.shift();
|
|
101
|
-
const currState = getStateFromIndex(currIdx);
|
|
102
|
-
for (const move of MOVES) {
|
|
103
|
-
const nextState = applySkewbMove(currState, move);
|
|
104
|
-
const nextIdx = getStateIndex(nextState);
|
|
105
|
-
if (!forwardMap.has(nextIdx)) {
|
|
106
|
-
forwardMap.set(nextIdx, { move, parent: currIdx });
|
|
107
|
-
if (backwardMap.has(nextIdx))
|
|
108
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
109
|
-
forwardQueue.push(nextIdx);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const bSize = backwardQueue.length;
|
|
114
|
-
for (let i = 0; i < Math.min(bSize, 1000); i++) {
|
|
115
|
-
const currIdx = backwardQueue.shift();
|
|
116
|
-
const currState = getStateFromIndex(currIdx);
|
|
117
|
-
for (const move of MOVES) {
|
|
118
|
-
const nextState = applySkewbMove(currState, move);
|
|
119
|
-
const nextIdx = getStateIndex(nextState);
|
|
120
|
-
if (!backwardMap.has(nextIdx)) {
|
|
121
|
-
const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
|
|
122
|
-
backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
|
|
123
|
-
if (forwardMap.has(nextIdx))
|
|
124
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
125
|
-
backwardQueue.push(nextIdx);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
throw new Error("Skewb state is unsolvable");
|
|
131
|
-
}
|
|
132
|
-
function reconstructPath(meetingIdx, forwardMap, backwardMap) {
|
|
133
|
-
const path = [];
|
|
134
|
-
let curr = meetingIdx;
|
|
135
|
-
while (curr !== -1) {
|
|
136
|
-
const edge = forwardMap.get(curr);
|
|
137
|
-
if (edge.parent !== -1)
|
|
138
|
-
path.unshift(edge.move);
|
|
139
|
-
curr = edge.parent;
|
|
140
|
-
}
|
|
141
|
-
curr = meetingIdx;
|
|
142
|
-
while (curr !== -1) {
|
|
143
|
-
const edge = backwardMap.get(curr);
|
|
144
|
-
if (edge.parent !== -1)
|
|
145
|
-
path.push(edge.move);
|
|
146
|
-
curr = edge.parent;
|
|
147
|
-
}
|
|
148
|
-
return path;
|
|
149
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getPermutationIndex = getPermutationIndex;
|
|
4
|
-
exports.getPermutationFromIndex = getPermutationFromIndex;
|
|
5
|
-
exports.getOrientationIndex = getOrientationIndex;
|
|
6
|
-
exports.getOrientationFromIndex = getOrientationFromIndex;
|
|
7
|
-
exports.getCentersIndex = getCentersIndex;
|
|
8
|
-
exports.getCentersFromIndex = getCentersFromIndex;
|
|
9
|
-
exports.getStateIndex = getStateIndex;
|
|
10
|
-
exports.solvePyraminx = solvePyraminx;
|
|
11
|
-
const moves_js_1 = require("./moves.js");
|
|
12
|
-
const state_js_1 = require("./state.js");
|
|
13
|
-
// Fast state-to-index encoder/decoder to allow optimal BFS solving
|
|
14
|
-
// Factorials for permutation encoding
|
|
15
|
-
const FACT = [1, 1, 2, 6, 24, 120, 720];
|
|
16
|
-
function getPermutationIndex(perm) {
|
|
17
|
-
let index = 0;
|
|
18
|
-
const n = perm.length;
|
|
19
|
-
for (let i = 0; i < n; i++) {
|
|
20
|
-
let count = 0;
|
|
21
|
-
for (let j = i + 1; j < n; j++) {
|
|
22
|
-
if (perm[j] < perm[i])
|
|
23
|
-
count++;
|
|
24
|
-
}
|
|
25
|
-
index += count * FACT[n - 1 - i];
|
|
26
|
-
}
|
|
27
|
-
return index;
|
|
28
|
-
}
|
|
29
|
-
function getPermutationFromIndex(index, n) {
|
|
30
|
-
const perm = Array(n).fill(0);
|
|
31
|
-
const temp = Array.from({ length: n }, (_, i) => i);
|
|
32
|
-
let val = index;
|
|
33
|
-
for (let i = 0; i < n; i++) {
|
|
34
|
-
const f = FACT[n - 1 - i];
|
|
35
|
-
const choice = Math.floor(val / f);
|
|
36
|
-
val %= f;
|
|
37
|
-
perm[i] = temp[choice];
|
|
38
|
-
temp.splice(choice, 1);
|
|
39
|
-
}
|
|
40
|
-
return perm;
|
|
41
|
-
}
|
|
42
|
-
function getOrientationIndex(orient) {
|
|
43
|
-
let index = 0;
|
|
44
|
-
for (let i = 0; i < 5; i++) {
|
|
45
|
-
index = (index << 1) | orient[i];
|
|
46
|
-
}
|
|
47
|
-
return index;
|
|
48
|
-
}
|
|
49
|
-
function getOrientationFromIndex(index) {
|
|
50
|
-
const orient = Array(6).fill(0);
|
|
51
|
-
let temp = index;
|
|
52
|
-
let sum = 0;
|
|
53
|
-
for (let i = 4; i >= 0; i--) {
|
|
54
|
-
const bit = temp & 1;
|
|
55
|
-
orient[i] = bit;
|
|
56
|
-
sum += bit;
|
|
57
|
-
temp >>= 1;
|
|
58
|
-
}
|
|
59
|
-
orient[5] = sum % 2 === 0 ? 0 : 1;
|
|
60
|
-
return orient;
|
|
61
|
-
}
|
|
62
|
-
function getCentersIndex(centers) {
|
|
63
|
-
return centers[0] + 3 * centers[1] + 9 * centers[2] + 27 * centers[3];
|
|
64
|
-
}
|
|
65
|
-
function getCentersFromIndex(index) {
|
|
66
|
-
let temp = index;
|
|
67
|
-
const centers = Array(4).fill(0);
|
|
68
|
-
for (let i = 0; i < 4; i++) {
|
|
69
|
-
centers[i] = temp % 3;
|
|
70
|
-
temp = Math.floor(temp / 3);
|
|
71
|
-
}
|
|
72
|
-
return centers;
|
|
73
|
-
}
|
|
74
|
-
function getStateIndex(state) {
|
|
75
|
-
const c = getCentersIndex(state.centers);
|
|
76
|
-
const p = getPermutationIndex(state.edgesPerm);
|
|
77
|
-
const o = getOrientationIndex(state.edgesOrient);
|
|
78
|
-
// c is 0..80, p is 0..719, o is 0..31
|
|
79
|
-
return c + 81 * (p + 720 * o);
|
|
80
|
-
}
|
|
81
|
-
// Bidirectional BFS solver
|
|
82
|
-
const MOVES = ["U", "U'", "L", "L'", "R", "R'", "B", "B'"];
|
|
83
|
-
function solvePyraminx(state) {
|
|
84
|
-
const startIdx = getStateIndex(state);
|
|
85
|
-
const solvedIdx = getStateIndex((0, state_js_1.createSolvedPyraminxState)());
|
|
86
|
-
if (startIdx === solvedIdx)
|
|
87
|
-
return [];
|
|
88
|
-
// Bidirectional BFS:
|
|
89
|
-
// forwardMap and backwardMap store the move that led to this index and the parent index
|
|
90
|
-
const forwardMap = new Map();
|
|
91
|
-
const backwardMap = new Map();
|
|
92
|
-
const forwardQueue = [startIdx];
|
|
93
|
-
const backwardQueue = [solvedIdx];
|
|
94
|
-
forwardMap.set(startIdx, { move: "", parent: -1 });
|
|
95
|
-
backwardMap.set(solvedIdx, { move: "", parent: -1 });
|
|
96
|
-
while (forwardQueue.length > 0 && backwardQueue.length > 0) {
|
|
97
|
-
// Expand forward
|
|
98
|
-
const fSize = forwardQueue.length;
|
|
99
|
-
for (let i = 0; i < Math.min(fSize, 1000); i++) {
|
|
100
|
-
const currIdx = forwardQueue.shift();
|
|
101
|
-
const currState = getPyraminxStateFromIndex(currIdx);
|
|
102
|
-
for (const move of MOVES) {
|
|
103
|
-
const nextState = (0, moves_js_1.applyPyraminxMove)(currState, move);
|
|
104
|
-
const nextIdx = getStateIndex(nextState);
|
|
105
|
-
if (!forwardMap.has(nextIdx)) {
|
|
106
|
-
forwardMap.set(nextIdx, { move, parent: currIdx });
|
|
107
|
-
if (backwardMap.has(nextIdx)) {
|
|
108
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
109
|
-
}
|
|
110
|
-
forwardQueue.push(nextIdx);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// Expand backward
|
|
115
|
-
const bSize = backwardQueue.length;
|
|
116
|
-
for (let i = 0; i < Math.min(bSize, 1000); i++) {
|
|
117
|
-
const currIdx = backwardQueue.shift();
|
|
118
|
-
const currState = getPyraminxStateFromIndex(currIdx);
|
|
119
|
-
for (const move of MOVES) {
|
|
120
|
-
const nextState = (0, moves_js_1.applyPyraminxMove)(currState, move);
|
|
121
|
-
const nextIdx = getStateIndex(nextState);
|
|
122
|
-
if (!backwardMap.has(nextIdx)) {
|
|
123
|
-
// Note: we record the inverse move since we are searching from solved
|
|
124
|
-
const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
|
|
125
|
-
backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
|
|
126
|
-
if (forwardMap.has(nextIdx)) {
|
|
127
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
128
|
-
}
|
|
129
|
-
backwardQueue.push(nextIdx);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
throw new Error("Pyraminx state is unsolvable");
|
|
135
|
-
}
|
|
136
|
-
function getPyraminxStateFromIndex(index) {
|
|
137
|
-
let val = index;
|
|
138
|
-
const centersIdx = val % 81;
|
|
139
|
-
val = Math.floor(val / 81);
|
|
140
|
-
const permIdx = val % 720;
|
|
141
|
-
const orientIdx = Math.floor(val / 720);
|
|
142
|
-
return {
|
|
143
|
-
centers: getCentersFromIndex(centersIdx),
|
|
144
|
-
edgesPerm: getPermutationFromIndex(permIdx, 6),
|
|
145
|
-
edgesOrient: getOrientationFromIndex(orientIdx),
|
|
146
|
-
tips: [0, 0, 0, 0] // tips are solved separately
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
function reconstructPath(meetingIdx, forwardMap, backwardMap) {
|
|
150
|
-
const path = [];
|
|
151
|
-
// Reconstruct forward path
|
|
152
|
-
let curr = meetingIdx;
|
|
153
|
-
while (curr !== -1) {
|
|
154
|
-
const edge = forwardMap.get(curr);
|
|
155
|
-
if (edge.parent !== -1) {
|
|
156
|
-
path.unshift(edge.move);
|
|
157
|
-
}
|
|
158
|
-
curr = edge.parent;
|
|
159
|
-
}
|
|
160
|
-
// Reconstruct backward path
|
|
161
|
-
curr = meetingIdx;
|
|
162
|
-
while (curr !== -1) {
|
|
163
|
-
const edge = backwardMap.get(curr);
|
|
164
|
-
if (edge.parent !== -1) {
|
|
165
|
-
path.push(edge.move);
|
|
166
|
-
}
|
|
167
|
-
curr = edge.parent;
|
|
168
|
-
}
|
|
169
|
-
return path;
|
|
170
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getPermutationIndex = getPermutationIndex;
|
|
4
|
-
exports.getPermutationFromIndex = getPermutationFromIndex;
|
|
5
|
-
exports.getOrientationIndex = getOrientationIndex;
|
|
6
|
-
exports.getOrientationFromIndex = getOrientationFromIndex;
|
|
7
|
-
exports.getCenterIndex = getCenterIndex;
|
|
8
|
-
exports.getCenterFromIndex = getCenterFromIndex;
|
|
9
|
-
exports.getStateIndex = getStateIndex;
|
|
10
|
-
exports.getStateFromIndex = getStateFromIndex;
|
|
11
|
-
exports.solveSkewb = solveSkewb;
|
|
12
|
-
const moves_js_1 = require("./moves.js");
|
|
13
|
-
const state_js_1 = require("./state.js");
|
|
14
|
-
const FACT = [1, 1, 2, 6, 24, 120, 720, 5040, 40320];
|
|
15
|
-
function getPermutationIndex(perm) {
|
|
16
|
-
// perm length 8, but pos0 is always 0 for WCA reachable states.
|
|
17
|
-
// We encode full 8-perm via Lehmer code (0..40319), but for fixed corner it will be in subset.
|
|
18
|
-
let index = 0;
|
|
19
|
-
const n = perm.length;
|
|
20
|
-
for (let i = 0; i < n; i++) {
|
|
21
|
-
let count = 0;
|
|
22
|
-
for (let j = i + 1; j < n; j++)
|
|
23
|
-
if (perm[j] < perm[i])
|
|
24
|
-
count++;
|
|
25
|
-
index += count * FACT[n - 1 - i];
|
|
26
|
-
}
|
|
27
|
-
return index;
|
|
28
|
-
}
|
|
29
|
-
function getPermutationFromIndex(index, n) {
|
|
30
|
-
const perm = Array(n).fill(0);
|
|
31
|
-
const temp = Array.from({ length: n }, (_, i) => i);
|
|
32
|
-
let val = index;
|
|
33
|
-
for (let i = 0; i < n; i++) {
|
|
34
|
-
const f = FACT[n - 1 - i];
|
|
35
|
-
const choice = Math.floor(val / f);
|
|
36
|
-
val %= f;
|
|
37
|
-
perm[i] = temp[choice];
|
|
38
|
-
temp.splice(choice, 1);
|
|
39
|
-
}
|
|
40
|
-
return perm;
|
|
41
|
-
}
|
|
42
|
-
function getOrientationIndex(orient) {
|
|
43
|
-
// orient length 8, index 0 is fixed 0, encode remaining 7 base3
|
|
44
|
-
let index = 0;
|
|
45
|
-
for (let i = 7; i >= 1; i--) {
|
|
46
|
-
index = index * 3 + orient[i];
|
|
47
|
-
}
|
|
48
|
-
return index;
|
|
49
|
-
}
|
|
50
|
-
function getOrientationFromIndex(index) {
|
|
51
|
-
const orient = Array(8).fill(0);
|
|
52
|
-
orient[0] = 0;
|
|
53
|
-
let val = index;
|
|
54
|
-
for (let i = 1; i < 8; i++) {
|
|
55
|
-
orient[i] = val % 3;
|
|
56
|
-
val = Math.floor(val / 3);
|
|
57
|
-
}
|
|
58
|
-
return orient;
|
|
59
|
-
}
|
|
60
|
-
function getCenterIndex(centers) {
|
|
61
|
-
let index = 0;
|
|
62
|
-
const n = centers.length;
|
|
63
|
-
for (let i = 0; i < n; i++) {
|
|
64
|
-
let count = 0;
|
|
65
|
-
for (let j = i + 1; j < n; j++)
|
|
66
|
-
if (centers[j] < centers[i])
|
|
67
|
-
count++;
|
|
68
|
-
index += count * FACT[n - 1 - i];
|
|
69
|
-
}
|
|
70
|
-
return index;
|
|
71
|
-
}
|
|
72
|
-
function getCenterFromIndex(index) {
|
|
73
|
-
return getPermutationFromIndex(index, 6);
|
|
74
|
-
}
|
|
75
|
-
function getStateIndex(state) {
|
|
76
|
-
const p = getPermutationIndex(state.corners.permutation);
|
|
77
|
-
const c = getCenterIndex(state.centers);
|
|
78
|
-
const o = getOrientationIndex(state.corners.orientation);
|
|
79
|
-
// p in 0..40319, c in 0..719, o in 0..2186
|
|
80
|
-
// Combine: ((p * 720 + c) * 2187 + o) -> up to 63B fits in JS number (53-bit)
|
|
81
|
-
return ((p * 720 + c) * 2187 + o);
|
|
82
|
-
}
|
|
83
|
-
function getStateFromIndex(index) {
|
|
84
|
-
const o = index % 2187;
|
|
85
|
-
let val = Math.floor(index / 2187);
|
|
86
|
-
const c = val % 720;
|
|
87
|
-
const p = Math.floor(val / 720);
|
|
88
|
-
return {
|
|
89
|
-
corners: {
|
|
90
|
-
permutation: getPermutationFromIndex(p, 8),
|
|
91
|
-
orientation: getOrientationFromIndex(o),
|
|
92
|
-
},
|
|
93
|
-
centers: getCenterFromIndex(c),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
const MOVES = ["R", "R'", "U", "U'", "L", "L'", "B", "B'"];
|
|
97
|
-
function solveSkewb(state) {
|
|
98
|
-
const startIdx = getStateIndex(state);
|
|
99
|
-
const solvedIdx = getStateIndex((0, state_js_1.createSolvedSkewbState)());
|
|
100
|
-
if (startIdx === solvedIdx)
|
|
101
|
-
return [];
|
|
102
|
-
const forwardMap = new Map();
|
|
103
|
-
const backwardMap = new Map();
|
|
104
|
-
const forwardQueue = [startIdx];
|
|
105
|
-
const backwardQueue = [solvedIdx];
|
|
106
|
-
forwardMap.set(startIdx, { move: "", parent: -1 });
|
|
107
|
-
backwardMap.set(solvedIdx, { move: "", parent: -1 });
|
|
108
|
-
while (forwardQueue.length > 0 && backwardQueue.length > 0) {
|
|
109
|
-
const fSize = forwardQueue.length;
|
|
110
|
-
for (let i = 0; i < Math.min(fSize, 1000); i++) {
|
|
111
|
-
const currIdx = forwardQueue.shift();
|
|
112
|
-
const currState = getStateFromIndex(currIdx);
|
|
113
|
-
for (const move of MOVES) {
|
|
114
|
-
const nextState = (0, moves_js_1.applySkewbMove)(currState, move);
|
|
115
|
-
const nextIdx = getStateIndex(nextState);
|
|
116
|
-
if (!forwardMap.has(nextIdx)) {
|
|
117
|
-
forwardMap.set(nextIdx, { move, parent: currIdx });
|
|
118
|
-
if (backwardMap.has(nextIdx))
|
|
119
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
120
|
-
forwardQueue.push(nextIdx);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const bSize = backwardQueue.length;
|
|
125
|
-
for (let i = 0; i < Math.min(bSize, 1000); i++) {
|
|
126
|
-
const currIdx = backwardQueue.shift();
|
|
127
|
-
const currState = getStateFromIndex(currIdx);
|
|
128
|
-
for (const move of MOVES) {
|
|
129
|
-
const nextState = (0, moves_js_1.applySkewbMove)(currState, move);
|
|
130
|
-
const nextIdx = getStateIndex(nextState);
|
|
131
|
-
if (!backwardMap.has(nextIdx)) {
|
|
132
|
-
const invMove = move.endsWith("'") ? move.slice(0, -1) : `${move}'`;
|
|
133
|
-
backwardMap.set(nextIdx, { move: invMove, parent: currIdx });
|
|
134
|
-
if (forwardMap.has(nextIdx))
|
|
135
|
-
return reconstructPath(nextIdx, forwardMap, backwardMap);
|
|
136
|
-
backwardQueue.push(nextIdx);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
throw new Error("Skewb state is unsolvable");
|
|
142
|
-
}
|
|
143
|
-
function reconstructPath(meetingIdx, forwardMap, backwardMap) {
|
|
144
|
-
const path = [];
|
|
145
|
-
let curr = meetingIdx;
|
|
146
|
-
while (curr !== -1) {
|
|
147
|
-
const edge = forwardMap.get(curr);
|
|
148
|
-
if (edge.parent !== -1)
|
|
149
|
-
path.unshift(edge.move);
|
|
150
|
-
curr = edge.parent;
|
|
151
|
-
}
|
|
152
|
-
curr = meetingIdx;
|
|
153
|
-
while (curr !== -1) {
|
|
154
|
-
const edge = backwardMap.get(curr);
|
|
155
|
-
if (edge.parent !== -1)
|
|
156
|
-
path.push(edge.move);
|
|
157
|
-
curr = edge.parent;
|
|
158
|
-
}
|
|
159
|
-
return path;
|
|
160
|
-
}
|