snake cube solver

by dp0ch

HTML

<html>
  <head>
    <script src="https://cdn.plot.ly/plotly-1.40.1.min.js"></script>
  </head>
  <body>
    <div id="graph"></div>
  </body>

</html>

CSS

body, html, #graph{
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

Babel + JSX

const cube = [3, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2];

(async () => {
	const solution = await solveCube(cube);
  console.log(solution);
	render(solution); 
})()

/// SOLVER ///

function solveCube(cubeSequence) {
	let moves = 0;
  const cubeDimension = Math.cbrt(cubeSequence.reduce((acc, n) => n + acc, 0));
  if (!Number.isInteger(cubeDimension)) throw new Error('Invalid/unsolvable cube sequence');
  const [firstSegment, ...restSequence] = cubeSequence;
  if (firstSegment > cubeDimension || firstSegment < 2) throw new Error('Invalid/unsolvable cube sequence');
  const solution = solve([firstSegment - 1, ...restSequence]);
  if (!solution) throw new Error('Invalid/unsolvable cube sequence');
  return solution;
  
  async function solve(
  	cubeSequence, 
    {
    	direction = {x: 0, y: 0, z: 0}, 
    	position = {x: 0, y: 0, z: 0},
    	cellOccupation = {[[0, 0, 0]]: true},
    	bounds = {
  			lower: {x: 0, y: 0, z: 0},
    		upper: {x: 0, y: 0, z: 0},
  		},
    } = {}
  ) {
  	if (cubeSequence.length <= 0) return [position];
  	const [segment, ...restSequence] = cubeSequence;
      
    for(const moveDirection of orthogonals(direction, segment)) {
    	const move = getMove(moveDirection, {position, cellOccupation, bounds});
      console.log(++moves);
      if (!move) continue;
      const solution = await new Promise((resolve) => {
      	setTimeout(async () => {
        	resolve(await solve(restSequence, move));
        }, 0);
      });
      if (solution) return [position, ...solution];
    }
  }
  
  function getMove(direction, {position, cellOccupation, bounds}) {
  	const nextPosition = vec3Add(position, direction);
    const nextBounds = extendBounds(bounds, nextPosition);
    if (!nextBounds) return null;
    
    const nextCells = extendCellOccupation(cellOccupation, position, nextPosition);
    if (!nextCells) return null;
   	
    return {
    	direction,
      position: nextPosition,
      bounds: nextBounds,
      cellOccupation:...