🧦 - 2025 DAY 11 SOLUTIONS - 🧦
Day 11: Reactor
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
Go
Yeeeaaay graphs! This one has been a pleasure to program and here comes my solution, with pruning of irrelevant branches (cursed nodes) and memoïzation for better performance.
::: spoiler day11.go
:::
I have also finally written a function to automatically download the input file (which will prove useful for... ehm... tomorrow):
::: spoiler download today's input file
:::
Rust
Part 1 was very straight forward. I overcomplicated it a bit by using an actual graph library, but I'm used to using it.
I originally tried to brute force Part 2, which of course failed. I then reverted to dynamic programming, which worked well.
Python
Part 1 can be done with simple dfs / backtracking, even without memoization.
Part 2 needed to have dp / memoization to finish in a reasonable time. Initially, I also checked for cycles in the path, but I removed the check once I realized there were none. Also, instead of adding booleans / int to my memoization function, I chose to compute both path arrangements (svr -> fft -> dac -> out AND svr -> dac -> fft -> out) and add them up.
::: spoiler click to view code
:::
Haskell
Rust
After the struggles of yesterday, nice to have an easy one. Still havent solved yesterdays pt2, struggling to understand z3 + rust.
Hope everyone else isnt too demoralised by the last 2 days!
::: spoiler spoiler
:::
Good luck! If anything, yesterday's problem is motivating (if not challenging) because I'm trying to use it to learn the simplex algorithm (off mediocre online tutorials—doubly so considering I think the problem needs dual simplex [pun intended]). I've spent far more time with pencil and paper trying to understand the algorithm than actually try writing code for it.
Yeah, ill have to bust out the pen and paper as well. Good learning excercise though :) Edit: If you find any good resources, please share :)
Haskell
Oh, this one was easy (dynamic programming at last!). Still haven't figured out the right way to approach yesterday's part two, though.
If you work out a solution to yesterday's part 2 which isn't just "cheat and rely on an external solver library", I will be most impressed.
Programming and mathematics have quite a large overlap and if you want to write tough puzzles it'll be "deep in the woods" for both, but that question is very much on the maths side. And "are you able to pass arguments to Z3?" isn't a very satisfying puzzle for me.
I did linear algebra with sympy over Q to reduce the search space to nullspace x [-N,N] grid (which is generally <=2 dimensional in these inputs and N<50 seems sufficient in most cases) then made easy work of it with vectorization. Similarly for part 2 did linear algebra over F2 but the search grid is also much smaller [0,1] x nullspace
Uiua
If it's stupid but it works...
::: spoiler My dirty hack I broke the maze into SVR>FFT>DAC>OUT and SVR>DAC>FFT>OUT, realised that the latter was taking a suspiciously long time, so submitted just the answer from the former --> success! :::
link (You'll need to up the execution limit)
I also broke up the pathing, mine has zero paths from DAC to FFT. If I join DAC directly FFT, i get a stackoverflow, so maybe its intentional.
If you can explain why it works, not calculating half the paths isn't a hack—it's an optimization. ;)
I think the hack was just skipping the entire second set of paths, but yeah, splitting was an nice optimisation. Might not scale as well if that path had to hit multiple intermediate nodes though.
Yes, it felt a little more like I was solving the puzzle-setter rather than the puzzle today.
Kotlin
This was substantially easier than yesterday's problem. Especially considering I still haven't done Part 2 from yesterday.
Anyway, here is my Part 2 solution for today. Given how quickly Part 1 ran without a cache, I didn't think Part 2 would be much different, until my computer fans spun up and stayed there for over a minute. So I added a cache and re-ran it and it ran in 31ms.
The graph in my input (and I assume everyone else's too) is DAG so one can use transfer matrices for the first part (after severing connections going out of "out") and the second one topological sorting and just count paths between each node separately and multiply them. First part could be done much easily using the machinery of part2 but I wanted to use my favourite object transfer matrices for the solution. Second part runs in about 0.09 seconds.
nushell
I'm still travelling, so another phone attempt. Jet lag says sleep, so just part 1 for now:
C++
Dynamic programming and recursion - it's the AoC classic. Nothing tricky here, which is a relief after yesterday.
No sign of Dijkstra's yet, which is a surprise. Maybe it'll be tomorrow's puzzle? 25th is usually an open goal if you've done the rest of the puzzles, but I don't know if that applies to the new shorter format.
Rust
Somehow got the right answer for part 1 iteratively, but it wasn't actually correct at all, so switched to the standard recursion + memoisation. Gotta love just chucking an iterator into the value type of a
HashMapand going BRRRR (1.2 ms).::: spoiler solution
:::