Files
soma-solver/public/solver/SomaSolver.js
Daniel Ledda e7b8ae6120 updates
2021-06-02 08:50:52 +02:00

49 lines
2.2 KiB
JavaScript

import VoxelSpace from "./VoxelSpace.js";
import SomaSolution from "./SomaSolution.js";
export default class SomaSolver {
constructor(dimension) {
this.solutions = [];
this.iterations = 0;
if (dimension % 1 !== 0 || dimension < 0) {
throw new Error("The argument 'dimension' must be a positive whole number");
}
this.dim = dimension;
this.solutionCube = new VoxelSpace(0, [dimension, dimension, dimension], Array(dimension ** 3).fill(0));
}
async solve(polycubes) {
if (polycubes.length === 0) {
throw new Error("You must pass at least one polycube to solve the puzzle.");
}
let cumulativeSize = polycubes.reduce((prev, curr) => prev + curr.size(), 0);
if (cumulativeSize !== this.dim ** 3) {
throw new Error(`The polycubes passed do not add up to exactly enough units to form a cube of dimension ${this.dim}! Got: ${cumulativeSize}, need: ${this.dim ** 3}`);
}
this.solutions = [];
const combosWithRots = polycubes.slice(1).map(polycube => polycube.getUniqueRotations().map((rot) => rot.getAllPositionsInCube(this.dim)).flat());
const combos = [polycubes[0].getAllPositionsInCube(this.dim), ...combosWithRots];
this.backtrackSolve(this.solutionCube, combos, new SomaSolution(this.dim));
this.solutions = SomaSolution.filterUnique(this.solutions);
}
getSolutions() {
return this.solutions.slice();
}
backtrackSolve(workingSolution, polycubes, currentSoln) {
const nextCubeGroup = polycubes[0];
for (let i = 0; i < nextCubeGroup.length; i++) {
const fusionAttempt = workingSolution.plus(nextCubeGroup[i]);
if (fusionAttempt) {
const nextSoln = currentSoln.clone();
nextSoln.addSpace(nextCubeGroup[i]);
if (polycubes.length === 1) {
this.solutions.push(nextSoln);
currentSoln = new SomaSolution(this.dim);
return;
}
else {
this.backtrackSolve(fusionAttempt, polycubes.slice(1), nextSoln);
}
}
}
}
}