great stuff
This commit is contained in:
53
src/SomaSolver.ts
Normal file
53
src/SomaSolver.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user