3
\$\begingroup\$

I wanted to practice functional programming (FP) without using any library but using vanilla JS only. So I took a problem from Advent of Code.

https://adventofcode.com/2017/day/3

You come across an experimental new kind of memory stored on an infinite two-dimensional grid.

Each square on the grid is allocated in a spiral pattern starting at a location marked 1 and then counting up while spiraling outward. For example, the first few squares are allocated like this:

  17  16  15  14  13
  18   5   4   3  12
  19   6   1   2  11
  20   7   8   9  10
  21  22  23---> ...

While this is very space-efficient (no squares are skipped), requested data must be carried back to square 1 (the location of the only access port for this memory system) by programs that can only move up, down, left, or right. They always take the shortest path: the Manhattan Distance between the location of the data and square 1.

For example:

Data from square 1 is carried 0 steps, since it's at the access port. Data from square 12 is carried 3 steps, such as: down, left, left. Data from square 23 is carried only 2 steps: up twice. Data from square 1024 must be carried 31 steps. How many steps are required to carry the data from the square identified in your puzzle input all the way to the access port?

Your puzzle input is still 289326.

My solution in FP is:

const getSquare = (b, n) => {
  const result = Math.pow(b, 2);
  if (n === 1) {
    return 1;
  }
  if (result >= n) {
    return b;
  }
  return getSquare(b + 2, n);
};
const seq = (m, n) => m > n ? [] : [m].concat(seq(m + 1, n));
const getDirection = (square, n) => {
  const steps = (square - 1) / 2;
  if (n === 1) return 0;
  const east = seq(Math.pow(square - 2, 2) + 1, Math.pow(square - 2, 2) +
    square - 1);
  const north = seq(east[east.length - 1] + 1, east[east.length - 1] +
    square - 1);
  const west = seq(north[north.length - 1] + 1, north[north.length - 1] +
    square - 1);
  const south = seq(west[west.length - 1] + 1, west[west.length - 1] +
    square - 1);
  const x_directions = [east, west];
  const y_directions = [north, south];
  const getSteps = getStepsOf(n);
  const xy_direction = getSteps(x_directions);
  const yx_direction = getSteps(y_directions);
  const addSteps = addXAndYSteps(steps);

  return xy_direction !== -1 ? addSteps(xy_direction) : addSteps(yx_direction);
};
const addXAndYSteps = steps => directions => {
  if ((directions + 1) > steps) {
    return steps + ((directions + 1) - steps);
  } else if ((directions + 1) === steps) {
    return steps;
  } else {
    return steps + (steps - (directions + 1));
  }
};
const getStepsOf = n => directions => directions.reduce((res, direction) => {
  const position = direction.findIndex(dir => dir === n);
  return (position > -1) ? position : res;
}, -1);
const num = 289326;
const solution = n => getDirection(getSquare(1, n), n);
console.log("Total Steps: ", solution(num));

Is there a better way to write it in FP with pure JavaScript, i.e. no additional FP library? Any improvement suggestions are welcomed.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.