Advent of Code 2021: Day 7

Advent of Code 2021: Day 7

This blog post is seventh in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 7. Given many horizontal positions for submarines navigated by crabs, we must align them using the least amount of fuel. Yes, it is another entertaining story!

All solutions are in this GitHub repository.

Solving Part One

The alignment position must be between the minimum and maximum horizontal submarine positions. We can then calculate the needed fuel for each alignment position between these thresholds.

We can break down the solution as follows:

  • read positions from input
  • find the minimum and maximum positions
  • calculate the fuel corresponding to each alignment
  • find the minimum fuel

Read positions from input

The readInput function created on Day 1 is useful for getting the file data as string. We can then map this data to a number array.

const positions = data.split(',').map((n) => Number(n))

Find the minimum and maximum positions

Since solving Advent of Code challenges, I have noticed the reduce function is very handy for many calculations based on elements in an array. Finding the minimum and maximum number in an array is one of those cases. I also relied on Math.min and Math.max to avoid writing conditional statements, thus additional lines of code.

const [minAlignPos, maxAlignPos] = positions.reduce(
  ([min, max], pos) => [Math.min(min, pos), Math.max(max, pos)],
  [positions[0], positions[0]]
)

Calculate the fuel corresponding to each alignment

We can iterate through each alignment between the maximum and minimum positions using a for loop.

for (let alignPos = minAlignPos; alignPos <= maxAlignPos; alignPos++) {
  const fuel = calculateFuel(positions, alignPos)
}

We can use the reduce function again to calculate the fuel required for aligning all positions. We must sum the differences between each position and the alignment position.

const calculateFuel = (positions, alignPos) => {
  return positions.reduce((fuel, pos) => fuel + Math.abs(pos - alignPos), 0)
}

Find the minimum fuel

After calculating the fuel for each alignment, we can determine the minimum fuel needed by comparing each fuel amount with the minFuel variable and updating it accordingly.

let minFuel

for (let alignPos = minAlignPos; alignPos <= maxAlignPos; alignPos++) {
  const fuel = calculateFuel(positions, alignPos)
  if (!minFuel || fuel < minFuel) {
    minFuel = fuel
  }
}

return minFuel

The final solution for part one is in my GitHub repository.

Solving Part Two

In part two, the problem describes a different way of calculating the fuel. Instead of a constant amount of fuel, the required fuel increases with 1 unit each step. Thus, aligning n steps would require 1 + 2 + 3 + ... + n amount of fuel. We can use Gauss's summation and calculate the steps as follows n * ( n + 1 ) / 2.

const calculateFuelForSteps = (n) => (n * (n + 1)) / 2

const calculateFuel = (positions, alignPos) => {
  return positions.reduce(
    (fuel, pos) => fuel + calculateFuelForSteps(Math.abs(pos - alignPos)),
    0
  )
}

The final solution for part two is in my GitHub repository.

Conclusion

We found the most fuel-efficient way of aligning a set of crab submarines given their horizontal positions. I had fun reading and solving the challenge of Day 7 and am looking forward to Day 8!