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!