53 lines
2.3 KiB
TypeScript
53 lines
2.3 KiB
TypeScript
import VoxelSpace from "./VoxelSpace";
|
|
import SomaSolution from "./SomaSolution";
|
|
|
|
export default class SomaSolver {
|
|
private solutionCube: VoxelSpace;
|
|
private dim: number;
|
|
private solutions: SomaSolution[] = [];
|
|
private iterations: number = 0;
|
|
constructor(dimension: number) {
|
|
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: VoxelSpace[]) {
|
|
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: VoxelSpace) => 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();
|
|
}
|
|
|
|
private backtrackSolve(workingSolution: VoxelSpace, polycubes: VoxelSpace[][], currentSoln: SomaSolution, depth = 0) {
|
|
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, depth + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |