Files
rubic-cube/src/utils/solvers/KociembaSolver.js
Grzegorz Kucmierz 8a20531fa0
All checks were successful
Deploy to Production / deploy (push) Successful in 21s
feat: separate solver logic into dedicated web worker, improve toast notifications
2026-02-24 09:56:16 +00:00

141 lines
3.7 KiB
JavaScript

import Cube from "cubejs";
import { DeepCube, CORNERS, EDGES } from "../DeepCube.js";
export class KociembaSolver {
static init() {
Cube.initSolver();
}
constructor(cube) {
this.cube = cube.clone();
}
// Convert DeepCube permutation/orientation to Kociemba facelet string
// Kociemba format: U1..U9 R1..R9 F1..F9 D1..D9 L1..L9 B1..B9
toFaceletString() {
// Array of 54 characters representing the 6 faces.
// 0..8 = U
// 9..17 = R
// 18..26 = F
// 27..35 = D
// 36..44 = L
// 45..53 = B
const f = new Array(54).fill(" ");
// Centers
f[4] = "U";
f[13] = "R";
f[22] = "F";
f[31] = "D";
f[40] = "L";
f[49] = "B";
// DeepCube to Kociemba mapping:
// Corners:
// 0: URF, 1: UFL, 2: ULB, 3: UBR, 4: DFR, 5: DLF, 6: DBL, 7: DRB
// Edges:
// 0: UR, 1: UF, 2: UL, 3: UB, 4: DR, 5: DF, 6: DL, 7: DB, 8: FR, 9: FL, 10: BL, 11: BR
const cornerColors = [
["U", "R", "F"], // 0: URF
["U", "F", "L"], // 1: UFL
["U", "L", "B"], // 2: ULB
["U", "B", "R"], // 3: UBR
["D", "F", "R"], // 4: DFR
["D", "L", "F"], // 5: DLF
["D", "B", "L"], // 6: DBL
["D", "R", "B"], // 7: DRB
];
const cornerFacelets = [
[8, 9, 20], // URF (U9, R1, F3)
[6, 18, 38], // UFL (U7, F1, L3)
[0, 36, 47], // ULB (U1, L1, B3)
[2, 45, 11], // UBR (U3, B1, R3)
[29, 26, 15], // DFR (D3, F9, R7)
[27, 44, 24], // DLF (D1, L9, F7)
[33, 53, 42], // DBL (D7, B9, L7)
[35, 17, 51], // DRB (D9, R9, B7)
];
for (let i = 0; i < 8; i++) {
const perm = this.cube.cp[i];
const ori = this.cube.co[i];
// The physical piece at position `i` is `perm`.
// Its colors are cornerColors[perm].
// Because of orientation, the colors are shifted.
// If ori=0, U/D color is on U/D face.
// If ori=1, U/D color is twisted clockwise.
// If ori=2, U/D color is twisted counter-clockwise.
const c0 = cornerColors[perm][(0 - ori + 3) % 3];
const c1 = cornerColors[perm][(1 - ori + 3) % 3];
const c2 = cornerColors[perm][(2 - ori + 3) % 3];
f[cornerFacelets[i][0]] = c0;
f[cornerFacelets[i][1]] = c1;
f[cornerFacelets[i][2]] = c2;
}
const edgeColors = [
["U", "R"], // 0: UR
["U", "F"], // 1: UF
["U", "L"], // 2: UL
["U", "B"], // 3: UB
["D", "R"], // 4: DR
["D", "F"], // 5: DF
["D", "L"], // 6: DL
["D", "B"], // 7: DB
["F", "R"], // 8: FR
["F", "L"], // 9: FL
["B", "L"], // 10: BL
["B", "R"], // 11: BR
];
const edgeFacelets = [
[5, 10], // UR (U6, R2)
[7, 19], // UF (U8, F2)
[3, 37], // UL (U4, L2)
[1, 46], // UB (U2, B2)
[32, 16], // DR (D6, R8)
[28, 25], // DF (D2, F8)
[30, 43], // DL (D4, L8)
[34, 52], // DB (D8, B8)
[23, 12], // FR (F6, R4)
[21, 41], // FL (F4, L6)
[50, 39], // BL (B6, L4)
[48, 14], // BR (B4, R6)
];
for (let i = 0; i < 12; i++) {
const perm = this.cube.ep[i];
const ori = this.cube.eo[i];
const e0 = edgeColors[perm][(0 + ori) % 2];
const e1 = edgeColors[perm][(1 + ori) % 2];
f[edgeFacelets[i][0]] = e0;
f[edgeFacelets[i][1]] = e1;
}
return f.join("");
}
solve() {
const faceletStr = this.toFaceletString();
try {
const cube = Cube.fromString(faceletStr);
if (cube.isSolved()) return [];
const solution = cube.solve();
if (!solution) return [];
return solution.split(" ").filter((m) => m);
} catch (e) {
throw new Error(
`Kociemba Solve Failed: ${e.message} \nFacelet: ${faceletStr}`,
);
}
}
}