Files
rubik/tests/solver.test.js
tiennm99 eb592e5c98 feat: add kociemba solver and vitest unit tests
- Solver: cubejs-backed two-phase solver, lazy-loaded chunk so the ~80 KB
  table-init cost stays out of the main bundle. New cube-to-facelets
  converter (3D model -> 54-char URFDLB string) verified bit-for-bit
  against cubejs's own move() output.
- Solve button in ControlsPanel with disabled "Solving..." state, wired
  through the CubeView controller; animates each move sequentially.
- Rewrite solved-check to the WCA face-uniformity definition. The old
  strict "identity quaternion per cubie" check rejected center spins
  (invisible) and whole-cube rotations, both of which are still solved
  per WCA / Kociemba.
- Vitest specs under tests/ cover cubie-model, move-definitions,
  move-parser, apply-move (4x turns, inverses, sune order=6, R2 == R R),
  scrambler, solved-check, algorithm-runner, cube-to-facelets, solver.
  39 tests, ~3 s. Adds npm test / npm run test:watch scripts.
2026-04-27 10:25:28 +07:00

47 lines
1.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect } from 'vitest';
import { createSolvedCube } from '../src/lib/core/cubie-model.js';
import { applyMove } from '../src/lib/core/apply-move.js';
import { parseAlgorithm } from '../src/lib/core/move-parser.js';
import { isSolved } from '../src/lib/core/solved-check.js';
import { solve } from '../src/lib/core/solver.js';
function run(cubies, algo) {
for (const m of parseAlgorithm(algo)) applyMove(cubies, m);
}
describe('solver', () => {
// 45 s init for cubejs Kociemba tables on first call. Set a generous bound.
it('returns an algorithm that brings a scrambled cube to solved', async () => {
const scramble = "R U R' F' R U R' U' R' F R2 U' R'";
const c = createSolvedCube();
run(c, scramble);
expect(isSolved(c)).toBe(false);
const solution = await solve(c);
expect(typeof solution).toBe('string');
expect(solution.length).toBeGreaterThan(0);
run(c, solution);
expect(isSolved(c)).toBe(true);
}, 30000);
it('solves a deeper scramble', async () => {
const scramble = "F R U' B2 D L' F' U R2 D' B U L' F2 D B' R U2 L'";
const c = createSolvedCube();
run(c, scramble);
const solution = await solve(c);
run(c, solution);
expect(isSolved(c)).toBe(true);
}, 30000);
it('returns a solution that keeps an already-solved cube solved', async () => {
// cubejs does not always return '' for solved input — it can return
// a non-trivial identity-equivalent algorithm. Verify by applying.
const c = createSolvedCube();
const solution = await solve(c);
run(c, solution);
expect(isSolved(c)).toBe(true);
}, 30000);
});