Advent of Code 2021: Day 6

Search for a command to run...

No comments yet. Be the first to comment.
In this series we solve programming challenges from the Advent of Code 2021 using JavaScript.
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....
This blog post is fourteenth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 14. This challenge was about optimizing an algorithm that generates exponentially larger and larger strings. I found ...

This blog post is thirteenth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 13. All solutions are in this GitHub repository. Solving Part One Given a list of x, y coordinates representing dots ...

This blog post is twelfth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described on Day 12. All solutions are in this GitHub repository. Solving Part One Given a set of connections between underground caves, ...

This blog post is eleventh in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 11. This day had many similarities to Day 9, and I solved the challenge using similar methods. All solutions are in thi...

This blog post is the tenth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 10. All solutions are in this GitHub repository. Solving Part One Given a set of lines with opening and closing bracke...

This blog post is sixth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 6. The challenge was creating and optimizing an algorithm for calculating the lanternfish population after a number of days.
All solutions are in this GitHub repository.
We have an initial set of fish with given internal times until they multiply. According to the problem, after creating a new fish, each fish resets their internal time to 6 days since they need a week to make a new fish. A new fish starts with an internal time of 9 days until multiplying the first time. The challenge is to calculate the amount of fish after 80 days.
We can solve the problem with the following steps:
The input contains comma-separated numbers, which represent the state of each fish. We can use an array to store each fish as a number.
let fish = data.split(',').map((n) => Number(n))
Without considering new fish for now, after a day, each fish's internal time decreases by one until it reaches 0, at which point it resets to 6.
const newFishPopulation = fish.map((f) =>
{
if (f === 0) {
return 6
}
return f - 1
})
We can count the amount of fish that reset to 6 and add that amount to the list of new fish population.
const getNewFishPopulation = (fish) => {
let newFishCount = 0
const newFishPopulation = fish.map((f) => {
if (f === 0) {
newFishCount++
return 6
}
return f - 1
})
newFishPopulation.push(...Array(newFishCount).fill(8))
return newFishPopulation
}
The challenge is to find the amount of fish after 80 days, so we can write a for loop which would update the fish array every day.
for (let day = 1; day <= 80; day++) {
fish = getNewFishPopulation(fish)
}
return fish.length
You can see the final solution for part one on my GitHub repository.
Part two is about optimizing the algorithm to calculate the fish population after 256 days. The solution from part one is not efficient in terms of memory. It exceeds the maximum number of elements allowed in an array, thus throwing the following range error.
fish.push(...Array(newFishCount).fill(8))
^
RangeError: Maximum call stack size exceeded
While thinking about this problem, it occurred to me that fish with the same state produces the same amount of ancestors. For example, two fishes left with three days until reproduction create the same amount of ancestors after 80 or any amount of days. Thus, it would be enough to keep track of the amount of fish in a given state each day. So I opted for an occurrence array with nine elements, where each index represents the state of days until reproduction and stores the amount of fish with that corresponding state.
We can break the problem like this:
import { URL, fileURLToPath } from 'url'
import { readInput } from '../utils/readInput.js'
const sumFish = (occurenceArray) => {
return occurenceArray.reduce((sum, fishCount) => sum + fishCount, 0)
}
const solve = (data) => {
const fish = data.split(',').map((n) => Number(n))
const fishOccurence = Array(9).fill(0)
fish.forEach((f) => fishOccurence[f]++)
for (let day = 1; day <= 256; day++) {
const newFishCount = fishOccurence.shift()
fishOccurence[6] += newFishCount
fishOccurence.push(newFishCount)
}
return sumFish(fishOccurence)
}
const inputPath = fileURLToPath(new URL('./input.txt', import.meta.url))
const data = await readInput(inputPath)
console.log(solve(data))
Day 6 offered a challenge in terms of optimizing an algorithm. Although it stored duplicate elements, a simple solution worked well for part one. However, part two required using an occurrence array instead.