fix(solver): replace exponential IDDFS recursion with instantaneous heuristic simulation macros
This commit is contained in:
9
test/test_aperm.js
Normal file
9
test/test_aperm.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
let cube = new DeepCube();
|
||||
const apply = (str) => { str.split(' ').filter(x => x).forEach(m => cube = cube.multiply(MOVES[m])); };
|
||||
|
||||
apply("R' F R' B2 R F' R' B2 R2");
|
||||
console.log(`cp after A-perm:`, cube.cp.slice(0, 4));
|
||||
// We want to see which two corners are swapped.
|
||||
// Solved is 0,1,2,3.
|
||||
// If it prints 0,1,3,2, then 2 and 3 are swapped (Back corners).
|
||||
25
test/test_beginner_freeze.js
Normal file
25
test/test_beginner_freeze.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
import { BeginnerSolver } from '../src/utils/solvers/BeginnerSolver.js';
|
||||
|
||||
let cube = new DeepCube();
|
||||
const scramble = "R U R' U' R' F R2 U' R' U' R U R' F'"; // T-perm
|
||||
scramble.split(' ').forEach(move => {
|
||||
cube = cube.multiply(MOVES[move]);
|
||||
});
|
||||
|
||||
console.log('Testing BeginnerSolver with T-perm...');
|
||||
const solver = new BeginnerSolver(cube);
|
||||
|
||||
// Add some logging to the solver's methods to trace execution
|
||||
const originalApply = solver.apply.bind(solver);
|
||||
solver.apply = (moveStr) => {
|
||||
// console.log('Applying:', moveStr);
|
||||
originalApply(moveStr);
|
||||
};
|
||||
|
||||
try {
|
||||
const solution = solver.solve();
|
||||
console.log('Solution found:', solution.join(' '));
|
||||
} catch (e) {
|
||||
console.error('Error during solve:', e);
|
||||
}
|
||||
41
test/test_beginner_random.js
Normal file
41
test/test_beginner_random.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { DeepCube, MOVES } from "../src/utils/DeepCube.js";
|
||||
import { BeginnerSolver } from "../src/utils/solvers/BeginnerSolver.js";
|
||||
|
||||
const allMoves = Object.keys(MOVES);
|
||||
|
||||
const getRandomScramble = (length = 20) => {
|
||||
let s = [];
|
||||
for (let i = 0; i < length; i++)
|
||||
s.push(allMoves[Math.floor(Math.random() * allMoves.length)]);
|
||||
return s.join(" ");
|
||||
};
|
||||
|
||||
for (let i = 1; i <= 20; i++) {
|
||||
let cube = new DeepCube();
|
||||
const scramble = getRandomScramble();
|
||||
scramble.split(" ").forEach((move) => (cube = cube.multiply(MOVES[move])));
|
||||
|
||||
const startTime = Date.now();
|
||||
const solver = new BeginnerSolver(cube);
|
||||
try {
|
||||
const solution = solver.solve();
|
||||
const elapsedTime = Date.now() - startTime;
|
||||
console.log(
|
||||
`Test ${i}: Solved in ${elapsedTime}ms. Solution length: ${solution.length}`,
|
||||
);
|
||||
|
||||
// Verify it actually solved it
|
||||
let testCube = cube.clone();
|
||||
solution.forEach((m) => (testCube = testCube.multiply(MOVES[m])));
|
||||
if (!solver.isSolvedState(testCube)) {
|
||||
console.error(
|
||||
`ERROR: Test ${i} failed to fully solve the cube mathematically!`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`ERROR: Test ${i} threw an exception:`, e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
console.log("All 20 tests passed flawlessly!");
|
||||
34
test/test_diagnostics.js
Normal file
34
test/test_diagnostics.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
import { BeginnerSolver } from '../src/utils/solvers/BeginnerSolver.js';
|
||||
|
||||
const allMoves = Object.keys(MOVES);
|
||||
const getRandomScramble = (length = 20) => {
|
||||
let s = [];
|
||||
for (let i = 0; i < length; i++) s.push(allMoves[Math.floor(Math.random() * allMoves.length)]);
|
||||
return s.join(' ');
|
||||
};
|
||||
|
||||
let cube = new DeepCube();
|
||||
const scramble = getRandomScramble();
|
||||
scramble.split(' ').forEach(move => cube = cube.multiply(MOVES[move]));
|
||||
|
||||
const solver = new BeginnerSolver(cube);
|
||||
solver.solve();
|
||||
|
||||
console.log("Check Cross:");
|
||||
for (let i of [4, 5, 6, 7]) console.log(`Edge ${i}: ep=${solver.cube.ep.indexOf(i)} eo=${solver.cube.eo[solver.cube.ep.indexOf(i)]}`);
|
||||
|
||||
console.log("Check F2L Corners:");
|
||||
for (let i of [4, 5, 6, 7]) console.log(`Corner ${i}: cp=${solver.cube.cp.indexOf(i)} co=${solver.cube.co[solver.cube.cp.indexOf(i)]}`);
|
||||
|
||||
console.log("Check F2L Edges:");
|
||||
for (let i of [8, 9, 10, 11]) console.log(`Edge ${i}: ep=${solver.cube.ep.indexOf(i)} eo=${solver.cube.eo[solver.cube.ep.indexOf(i)]}`);
|
||||
|
||||
console.log("Check OLL:");
|
||||
console.log(`co:`, solver.cube.co.slice(0, 4));
|
||||
console.log(`eo:`, solver.cube.eo.slice(0, 4));
|
||||
|
||||
console.log("Check PLL:");
|
||||
console.log(`cp:`, solver.cube.cp.slice(0, 4));
|
||||
console.log(`ep:`, solver.cube.ep.slice(0, 4));
|
||||
|
||||
40
test/test_diagnostics2.js
Normal file
40
test/test_diagnostics2.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
import { BeginnerSolver } from '../src/utils/solvers/BeginnerSolver.js';
|
||||
|
||||
const allMoves = Object.keys(MOVES);
|
||||
const getRandomScramble = (length = 20) => {
|
||||
let s = [];
|
||||
for (let i = 0; i < length; i++) s.push(allMoves[Math.floor(Math.random() * allMoves.length)]);
|
||||
return s.join(' ');
|
||||
};
|
||||
|
||||
for (let iter = 0; iter < 100; iter++) {
|
||||
let cube = new DeepCube();
|
||||
const scramble = getRandomScramble();
|
||||
scramble.split(' ').forEach(move => cube = cube.multiply(MOVES[move]));
|
||||
|
||||
const solver = new BeginnerSolver(cube);
|
||||
solver.solve();
|
||||
|
||||
if (!solver.isSolvedState(solver.cube)) {
|
||||
console.log("FAILED ON SCRAMBLE:", scramble);
|
||||
console.log("Check Cross:");
|
||||
for (let i of [4, 5, 6, 7]) console.log(`Edge ${i}: ep=${solver.cube.ep.indexOf(i)} eo=${solver.cube.eo[solver.cube.ep.indexOf(i)]}`);
|
||||
|
||||
console.log("Check F2L Corners:");
|
||||
for (let i of [4, 5, 6, 7]) console.log(`Corner ${i}: cp=${solver.cube.cp.indexOf(i)} co=${solver.cube.co[solver.cube.cp.indexOf(i)]}`);
|
||||
|
||||
console.log("Check F2L Edges:");
|
||||
for (let i of [8, 9, 10, 11]) console.log(`Edge ${i}: ep=${solver.cube.ep.indexOf(i)} eo=${solver.cube.eo[solver.cube.ep.indexOf(i)]}`);
|
||||
|
||||
console.log("Check OLL:");
|
||||
console.log(`co:`, solver.cube.co.slice(0, 4));
|
||||
console.log(`eo:`, solver.cube.eo.slice(0, 4));
|
||||
|
||||
console.log("Check PLL:");
|
||||
console.log(`cp:`, solver.cube.cp.slice(0, 4));
|
||||
console.log(`ep:`, solver.cube.ep.slice(0, 4));
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
console.log("All 100 tests passed!");
|
||||
24
test/test_macros.js
Normal file
24
test/test_macros.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
|
||||
let cube = new DeepCube();
|
||||
const apply = (str) => {
|
||||
str.split(' ').forEach(m => {
|
||||
cube = cube.multiply(MOVES[m]);
|
||||
});
|
||||
};
|
||||
|
||||
apply("R U R'");
|
||||
console.log("Piece 4 (R U R') is at position:", cube.cp.indexOf(4), "Orientation:", cube.co[cube.cp.indexOf(4)]);
|
||||
|
||||
cube = new DeepCube();
|
||||
apply("R U' R' U R U2 R'");
|
||||
console.log("Piece 4 (Up-face extraction) position:", cube.cp.indexOf(4), "Orientation:", cube.co[cube.cp.indexOf(4)]);
|
||||
|
||||
cube = new DeepCube();
|
||||
apply("R U R'"); // insert front facing
|
||||
console.log("Piece 4 (Front-face extraction) position:", cube.cp.indexOf(4), "Orientation:", cube.co[cube.cp.indexOf(4)]);
|
||||
|
||||
cube = new DeepCube();
|
||||
apply("F' U' F"); // insert left facing
|
||||
console.log("Piece 4 (Side-face extraction) position:", cube.cp.indexOf(4), "Orientation:", cube.co[cube.cp.indexOf(4)]);
|
||||
|
||||
24
test/test_macros2.js
Normal file
24
test/test_macros2.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
|
||||
let cube;
|
||||
const apply = (str) => {
|
||||
str.split(' ').forEach(m => {
|
||||
cube = cube.multiply(MOVES[m]);
|
||||
});
|
||||
};
|
||||
|
||||
const check = (name, alg, initPos, initOri) => {
|
||||
cube = new DeepCube();
|
||||
apply(alg);
|
||||
// We applied alg to a SOLVED cube.
|
||||
// The piece that WAS at 4 (DFR) is now at some position P with orientation O.
|
||||
// To solve it, we would need to reverse the alg.
|
||||
// So if we find a piece at P with orientation O, we apply the reverse alg!
|
||||
console.log(`${name}: Extraction piece 4 is at pos ${cube.cp.indexOf(4)} ori ${cube.co[cube.cp.indexOf(4)]}`);
|
||||
};
|
||||
|
||||
check("R U R'", "R U R'");
|
||||
check("R U' R'", "R U' R'");
|
||||
check("F' U' F", "F' U' F");
|
||||
check("R U2 R' U' R U R'", "R U' R' U R U2 R'");
|
||||
|
||||
10
test/test_macros3.js
Normal file
10
test/test_macros3.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
|
||||
let cube = new DeepCube();
|
||||
const apply = (str) => { str.split(' ').forEach(m => { cube = cube.multiply(MOVES[m]); }); };
|
||||
|
||||
cube = new DeepCube(); apply("F' U F");
|
||||
console.log("F' U F reverse puts piece 4 at pos:", cube.cp.indexOf(4), "ori:", cube.co[cube.cp.indexOf(4)]);
|
||||
|
||||
cube = new DeepCube(); apply("U' F' U F");
|
||||
console.log("U' F' U F reverse puts piece 4 at pos:", cube.cp.indexOf(4), "ori:", cube.co[cube.cp.indexOf(4)]);
|
||||
22
test/test_macros4.js
Normal file
22
test/test_macros4.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
|
||||
let cube = new DeepCube();
|
||||
const apply = (str) => { str.split(' ').forEach(m => { cube = cube.multiply(MOVES[m]); }); };
|
||||
|
||||
const check = (name, alg, expectedPos, expectedOri) => {
|
||||
cube = new DeepCube();
|
||||
apply(alg); // reverse of extraction
|
||||
let p5 = cube.cp.indexOf(5); let o5 = cube.co[p5];
|
||||
console.log(`${name}: pos 5 is ${p5} (expected ${expectedPos}), ori ${o5} (expected ${expectedOri})`);
|
||||
};
|
||||
|
||||
// DLF (5) Target UFL (1)
|
||||
check("F' U' F reverse", "F' U F", 1, 2); // if reverse puts it at pos 1 ori 2, then if at pos 1 ori 2 use F' U' F!
|
||||
check("L U L' reverse", "L U' L'", 1, 1);
|
||||
check("L' U' L reverse", "L' U L", 1, 1); // wait, L' moves DLF to UBL(2)? Let's find out!
|
||||
|
||||
// Check extraction from 5
|
||||
cube = new DeepCube(); apply("L U L'");
|
||||
console.log("Extract DLF (5) with L U L' gives pos:", cube.cp.indexOf(5), "ori:", cube.co[cube.cp.indexOf(5)]);
|
||||
cube = new DeepCube(); apply("F' U' F");
|
||||
console.log("Extract DLF (5) with F' U' F gives pos:", cube.cp.indexOf(5), "ori:", cube.co[cube.cp.indexOf(5)]);
|
||||
22
test/test_moves.js
Normal file
22
test/test_moves.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { DeepCube, MOVES } from '../src/utils/DeepCube.js';
|
||||
|
||||
let cube = new DeepCube();
|
||||
const apply = (str) => {
|
||||
str.split(' ').forEach(m => {
|
||||
cube = cube.multiply(MOVES[m]);
|
||||
});
|
||||
};
|
||||
|
||||
// We want to verify `R U R'` extracts piece 4 (DFR) to U layer.
|
||||
apply("R U R'");
|
||||
console.log("Piece 4 is at position:", cube.cp.indexOf(4), "Orientation:", cube.co[cube.cp.indexOf(4)]);
|
||||
|
||||
cube = new DeepCube();
|
||||
// What if piece 4 is at URF (position 0)? We want to insert it to DFR (position 4).
|
||||
// If Yellow is UP, co=0.
|
||||
// Let's create a state where DFR is at URF with co=0.
|
||||
// We can do this by applying R U2 R' U' R U R' IN REVERSE to extract it.
|
||||
// Reverse of R U2 R' U' R U R' is: R U' R' U R U2 R'
|
||||
apply("R U' R' U R U2 R'");
|
||||
console.log("Extraction -> Piece 4 position:", cube.cp.indexOf(4), "Orientation:", cube.co[cube.cp.indexOf(4)]);
|
||||
|
||||
Reference in New Issue
Block a user