🧑 - 2025 DAY 2 SOLUTIONS - 🧑
Day 2: Gift Shop
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
An ID is invalid if and only if it is divisible by a number of the form 1001001001, where the 1's are separated by the same number of 0's and the block length times the number of blocks equals the digit length of the ID. Given that, the problem reduces to summing the members of some arithmetic progressions; we never have to iterate over the members of a range at all.
Awesome! I was looking for this type of solution and made some progress but couldn't get to it
Wow! It's so obvious, now when I read it.
I was considering multiplication in a similar fashion to get invalid numbers in range, but ended up just iterating over a string.
C
There are interesting analytical observations to be made about the problem to sidestep most of the actual iteration, but I wasn't up to working it all out and the runtime was pretty much instant anyway.
Here's my original solution with ints, using divions with powers of 10 to do the splitting: day02-u64.c
But I'm only doing the C implementations to prototype my assembly solutions, and dealing with 64-bit numbers, especially divisions, on x86-16 is painful, so I rewrote the solution using a fixed-length string "numbers" instead: day02.c
Still working on the assembly version
Assembly update: have part 1 working now! It's dog slow on DOSBox, but on QEMU it's good: day02.asm
c
One last time with threads.
p1 isolated: 12ms
p2 isolated: 13ms
combined run: 25ms
I like your regexes a lot better than mine. I wonder if there is a perf difference between them. I'll have to try.
Edit: Yours are faster, 3.5s vs 3.9s
Circling back around to go faster.
p1 isolated: 76ms
p2 isolated: 82ms
combined run: 156ms
When you have regex, everything looks like a haystack.
Nearly solved pt2 by accident in pt1. Just showing the invalid checks, rest of the code is uninteresting.
edit: The bot worked as well! With some slight human intervention. Tomorrow might be automatic if we are lucky.
Regex free solution. Much faster (233ms vs ~4s)
heh, recompiling the regex was wasting 80% of my time :D
Every so often I look for a library that will compile the regex at compile time - iirc, there's some stuff needing to made const fn before that can happen.
Last time I used regex, lazy_static was the way to go; I assume that regex can go in OnceCell nowadays.
I just passed it around, felt easier and rust-like. Compile time would be nice, but I have a vague feeling this would be too restrictive for some regexes/engines?
Maybe? There's some deep wizardry shown in some people's macros so a regex feels fairly basic in comparison.
Another day where the dumb way would have so much quicker and easier, but I'm not competing for time.
I decided to solve it numerically without regex or using
to_string(), which was more taxing for the ol' grey matter but is perhaps fairly optimal (if I bothered to pre-compute all those pow() calls, anyway).Part 2 runs in 35ms (on my AMD Ryzen 7 9800X3D), whereas the to_string() version runs in 40ms. So... not really worth it, and it's less readable.
Rust
to_string version:
Easy one to get through, no edge-cases biting me this time.
I learned this year again: running in interpreted mode can cause significant slowdowns. Later, I'll hopefully find the time clean it up, this solution feels ugly. Reading everyone else did it also like this or with regex makes me feel better about it though.
Haskell
::: spoiler Code from this morning (AoC is at 06:00 at my place)
:::
Using the interpreter, this solution made me wait for two minutes until I could submit. x.x After testing it again in compiled mode, it only takes four seconds.
120s -> 4s is a solid optimisation :)
Nim
Easy one today. Part 2 is pretty forgiving on performance, so regex bruteforce was only a couple seconds . But eventually I've cleaned it up and did a solution that runs in ~340 ms.
Full solution at Codeberg: solution.nim
At least for rust, regex perf was basically the same for pt1 and pt2. So very forgiving.
C# - no regex, 235ms for part 2. down to 51ms when I put each range on its own thread
::: spoiler spoiler
:::
Javascript
More bruteforcing! There are probably better ways to do this but I'm happy enough with this lol.
::: spoiler Solution You can replace the require('fs') on the first line with the input and run it in your browser console as well.
:::
Uiua
Considerably easier than Day 1 for me. Uiua does have regex support, but no back references, so this is my poor man's version.
You can run the code on Uiua Pad, btw.
And here's a much improved version based on my understanding of another solution on the Discord.
Futhark
I translated my Haskell solution to Futhark, basically. It runs abysmally faster.
The syntax highlighting is likely very off, because the closest language highlighter I could find was
ocaml.::: spoiler Sed-Script to Transform input for Futhark
:::
Elixir
This one took way to long to do because I got hung up on what turned out to just be forgetting to rename functions when copying code from part 1 to part 2.
I did part 1 in language but turned to regex for part 2.
Kotlin
got up early for this one, sadly it took me over 30 minutes to realize, that my code at the time was also considering a single digit valid .-.
also still pretty scuffed, but hey it works:
::: spoiler Solution
:::
full code on Codeberg
My part 2 Kotlin solution:
I didn't look closely enough at the input to know how big an entire list of IDs would be huge or not. But I assumed it was. So instead I just did ranges as Pairs.
I also only considered the prime factors up to 7, because there weren't any IDs that needed any higher.
Edit: I also worried that a brute force solution might be slow, but being day 2, I might have been a little too worried about that. The main algorithm ran in 68ms.
Python
I love it when I can just slap a problem with a regex and be done with it.
First I tried to to part 2 with a very poor regex strategy and the performance was abysmal. Switched to plain substrings and boom, instant result.
Golang
Haskell
Not much time for challenges right now sadly :/
DOS + BIOS boot (hybrid binary)
Repo | day02.asm | .COM download
Got the x86-16 assembly implementation working at last! Here, 64-bit integer math, especially lots of divisions by power of 10, wasn't going to do so the code instead operates on fixed-width, zero-padded numeric strings. Lots of time lost to debugging control flow/logic mistakes this time. I need to make printf() a priority!
Short input so no space issues, sitting comfortably at 45K, well below the 64K COM limit! Sadly no time yet to add animations or anything cool.
(Browser-based) Javascript
This year I'm tired of dealing with reading from files and setting up IDEs, so I'm attempting to solve each day directly in my web browser's console: after opening my problem input in a new tab I can do
mySolutionFunction(document.body.textContent)in that tab's console. Thankfully the browser I use (ff) has a mode that lets me write several lines and then run them, otherwise this would not be simpler. Unfortunately, this means I lost my code for day1 when I closed the tab a bit too quickly.I didn't want to use regex for today; you need backreferences and those are impossible to optimize if they blow up (computationally speaking). I'm not so sure my solution for part 2 actually does run in more linear time than a regex with a single backreference does...
Rust
View on github
I feared that this required some complicated maths to quickly figure out the next "invalid" number, but the total number of IDs to check was only about 2 million, so brute force it is.
Janet