6
votes
Day 11: Plutonian Pebbles
Today's problem description: https://adventofcode.com/2024/day/11
Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python
with any of the "short names" listed in this page of supported languages):
<details>
<summary>Part 1</summary>
```python
Your code here.
```
</details>
The main insight for me when solving part 2 was that the list contains many stones of the same number, so I can just keep track of the counts of the unique stones.
Part 1 & 2
TypeScript
Ack! I walked right into the trap in Part 2. My naive implementation was fine for Part 1 but would've run until the heat death of the universe over 75 steps. This was the first one (but certainly not the last) this year that stumped me when trying to solve on my own. Credit to @Hello for the useful clue, that was enough info to unblock me but not so much that I felt like I was cheating.
I'm keeping my original Part 1 code alongside the optimized Part 2 version below, to compare and contrast.
Spoilers
Originally I split the input into an array and looped through it, building a second array from the results of the rules for each stone. It worked fine for 25 steps... but when I tried it in Part 2 I was startled to see the whole thing explode with a
RangeError: Invalid array length
error. So that data type was a non-starter.At that point I switched to direct string manipulation, because at least there's no firm upper bound on length for strings. I knew this was playing with fire but wanted to see how far it could get me. I looped through the string one char at a time, looking for
" "
delimiters between words (in this case a "word" is a number, but string-encoded). When each word was identified, I'd apply the relevant rule and replace the word with its result in the main string. I had to keep close track of my index because this changed the length of the string and my pointer position within it while I was in the middle of looping through it. At the end I'd just count up the occurrences of" "
in the string to see how many stones I had.This approach was noticeably slower than my array-based solution, for solving Part 1. But it did have the advantage of not throwing RangeErrors so I let it run for a while. I added some duration logging so I could track its progress through each "blink" (step):
At this point I had enough data to see the hockey stick— it would take literally billions of years to reach step 75. That's when I hopped onto Tildes and got the hint I needed.
I think what I had gotten hung up on was this sentence in the puzzle text: "No matter how the stones change, their order is preserved, and they stay on their perfectly straight line." That suggested that the exact order was important so I'd been avoiding discarding that information. In reality, it's only looking for the number of stones, not their relative positions. Good exercise in thinking outside the box! My final code was able to complete both parts in just
10ms. Edit: 76ms, still pretty good imho.Parts 1 and 2 (TypeScript)
Probably would have been my fastest day yet, but I could not get the caching working on the recursive function. Pharo Dictionaries have a
at:ifAbsentPut:
which seemed perfect for implementing a simple cache, but I haven't been able to figure out why I couldn't get it to work. I ended up using mutual recursion and it worked alright, but I'll have to dig deeper to figure out what's up.I miss python's
@cache
...Smalltalk Solution
This one is my favourite puzzle so far this year. Very simple, but a lot of fun.
Edit: Updated the stuff below after refactoring the code.
Part 1 (Rust)
I should have solved this properly from the start, but the experience so far this year has been that the first part can be solved naively. Somehow I always get that the wrong way around, thinking I need a proper Part 1 when I don't, and not thinking properly about part 2 when I need to. I hate how I go into 'hacking' mode immediately instead of taking a minute to think things through.
I initially just used a linked list to iterate on the 'blinks', but after solving part 2 properly, part 1 became a lot simpler as well.
Part 2 (Rust)
Helpers
Benchmark
Wasn't able to figure out the right approach last night, but coming back to the puzzle today it luckily didn't take too long. This is probably still far from optimal, but it seems fast enough.
Solution (Jai)