This one was pretty interesting, as it was a tricky challenge. Let's see why.
Problem — Part 1
The sea floor is getting steeper. Maybe the sleigh keys got carried this way?
A massive school of glowing lanternfish swims past. They must spawn quickly to reach such large numbers - maybe exponentially quickly? You should model their growth rate to be sure.
Although you know nothing about this specific species of lanternfish, you make some guesses about their attributes. Surely, each lanternfish creates a new lanternfish once every 7 days.
However, this process isn't necessarily synchronized between every lanternfish - one lanternfish might have 2 days left until it creates another lanternfish, while another might have 4. So, you can model each fish as a single number that represents the number of days until it creates a new lanternfish.
Furthermore, you reason, a new lanternfish would surely need slightly longer before it's capable of producing more lanternfish: two more days for its first cycle.
So, suppose you have a lanternfish with an internal timer value of 3:
- After one day, its internal timer would become
2.
- After another day, its internal timer would become
1.
- After another day, its internal timer would become
0.
- After another day, its internal timer would reset to
6, and it would create a new lanternfish with an internal timer of8.
- After another day, the first lanternfish would have an internal timer of
5, and the second lanternfish would have an internal timer of7.
A lanternfish that creates a new fish resets its timer to 6, not 7(because 0 is included as a valid timer value). The new lanternfish starts with an internal timer of 8 and does not start counting down until the next day.
Realizing what you're trying to do, the submarine automatically produces a list of the ages of several hundred nearby lanternfish (your puzzle input). For example, suppose you were given the following list:
3,4,3,1,2This list means that the first fish has an internal timer of 3, the second fish has an internal timer of 4, and so on until the fifth fish, which has an internal timer of 2. Simulating these fish over several days would proceed as follows:
Initial state: 3,4,3,1,2
After 1 day: 2,3,2,0,1
After 2 days: 1,2,1,6,0,8
After 3 days: 0,1,0,5,6,7,8
After 4 days: 6,0,6,4,5,6,7,8,8
After 5 days: 5,6,5,3,4,5,6,7,7,8
After 6 days: 4,5,4,2,3,4,5,6,6,7
After 7 days: 3,4,3,1,2,3,4,5,5,6
After 8 days: 2,3,2,0,1,2,3,4,4,5
After 9 days: 1,2,1,6,0,1,2,3,3,4,8
After 10 days: 0,1,0,5,6,0,1,2,2,3,7,8
After 11 days: 6,0,6,4,5,6,0,1,1,2,6,7,8,8,8
After 12 days: 5,6,5,3,4,5,6,0,0,1,5,6,7,7,7,8,8
After 13 days: 4,5,4,2,3,4,5,6,6,0,4,5,6,6,6,7,7,8,8
After 14 days: 3,4,3,1,2,3,4,5,5,6,3,4,5,5,5,6,6,7,7,8
After 15 days: 2,3,2,0,1,2,3,4,4,5,2,3,4,4,4,5,5,6,6,7
After 16 days: 1,2,1,6,0,1,2,3,3,4,1,2,3,3,3,4,4,5,5,6,8
After 17 days: 0,1,0,5,6,0,1,2,2,3,0,1,2,2,2,3,3,4,4,5,7,8
After 18 days: 6,0,6,4,5,6,0,1,1,2,6,0,1,1,1,2,2,3,3,4,6,7,8,8,8,8
Each day, a 0 becomes a 6 and adds a new 8 to the end of the list, while each other number decreases by 1 if it was present at the start of the day.
In this example, after 18 days, there are a total of 26 fish. After 80 days, there would be a total of 5934.
Find a way to simulate lanternfish. How many lanternfish would there be after 80 days?
Your puzzle answer was 365862.
Solution — Part 1
The problem looks... simple. The most immediate thing that came into my mind while reading this was to just keep adding fishes to an array till the day are over. I mean, eventually they will end and we will have the lenght of our array to state how many fishes are left.
/** * Decrement the value of every element in the array by 1 * @param {array} vals Array of fishes with their values * @returns number of newborn fishes after the day */ function decreaseValues(vals) { let tot = 0; for (let i = 0; i < vals.length; i++) { if (vals[i] === 0) { vals[i] = 6; tot++; } else { vals[i]--; } } return tot; }
After a fish goes to 0 as a value, he goes back to 6 and adds a newborn fish to the total. Let's see also the main function
function main() { for (let i = 0; i < 80; i++) { const newborn = decreaseValues(values); for (let j = 0; j < newborn; j++) { values.push(8); } } return values.length; } console.log(main());
Pretty basic, that was eas...
Problem — Part 2
Suppose the lanternfish live forever and have unlimited food and space. Would they take over the entire ocean?
After 256 days in the example above, there would be a total of 26984457539 lanternfish!
How many lanternfish would there be after 256 days?
Your puzzle answer was 1653250886439.
Solution — Part 2
So wait.. you want me just to change the number of days this computations goes on? Sure.. but ain't that too simple?
...oh, wait. Let me just run it for a moment

Of course you crash. And of course my solution was waaaay to naive. The worst part is that sounds like I'm trying to solve multiple time the same problem over and over again, while I could just keep the result. Does that ring a bell? For me it was dynamic programming. And I don't like dynamic programming.
Dynamic Programming
I have a confession about why I'm not particularly a fan of DP: I never considered a lot while studying, always avoiding it when possibile. And I'm thankful that this problem came along since it's the perfect opportunity to train this skill too.
I was a bit slow on the solution of this one, so I'll report the steps I made. After reviewing the theory, I opted for the bottom-up approach with tabulation instead of the top-down recursive one.
Practically speaking, I was asking myself the following: since all the fishes can be considered independently, how many fishes will I have if I'm a zero-fish at the end of the 256 days? For me a zero-fish is a lantern fish that the day after will have value 6 and generated another one with value 8. Let's make a quick table:
This could go on forever, but we need to find the way in which those numbers are going on. The point is, that a fish with value 1, a day later is just a fish with value 0.
Considering the notation stands for number of fishes after days if I start with a fish of type . Knowing that we can say:
After the first values, which we know, we can already find the model we are looking for
Where is the number of days Once we have such formula and, looking at the previous table where all the values were "shifted" by one, we can conclude that:
This can be translated in the code in the following way:
import { loadInput } from "./utils.js"; const input = loadInput(); const vals = input.split(",").map(Number); const days = 256; // I need a place to store all the computations const nums = new Array(8); // Values I know at the beginning for the zero fish const val = [1, 2, 2, 2, 2, 2, 2, 2, 3]; val.push(...new Array(days - 9).fill(null)); for (let i = 9; i < days; i++) { val[i] = val[i - 9] + val[i - 7]; } for (let i = 1; i < 8; i++) { nums[i] = val[val.length - i]; } let tot = 0; for (let i = 0; i < vals.length; i++) { tot += nums[vals[i]]; } console.log(tot);
The code definitely could use some rework, but I'm still happy I managed to solve it.