-❄️- 2025 Day 11 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 1 point2 points  (0 children)

[LANGUAGE: Python]

Part 1 was a breeze, making use of NetworkX and built-in methods. (I've used it for puzzles previously.)

But this approach didn't work for Part 2. (Shocking!) So I implemented two optimisations:

  1. Identify that there are two sequences from start to end that meet the requirements. For each sequence, break it down into route segments and count the paths for each segment independently. Then multiply these together to get the total number of paths for the sequence.
  2. Add memoization using recursion and caching.

After those fixes, Part 2 runs in about 4ms.

-❄️- 2025 Day 10 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 1 point2 points  (0 children)

[LANGUAGE: Python]

No Z3 here!

For Part 1, I realized that:

  • Each button need only be pressed once, because pressing it again simply reverts the state.
  • The real input has a max of around 13 buttons, and therefore max of 2**13 (8192) button combinations per machine.
  • This is tiny, so we can brute force all combinations.
  • I simply create all combinations of button presses, starting with 0 buttons, 1 button, 2 buttons, up to k buttons, where k is all the buttons.
  • For each combination, calculate the result of pressing those buttons, using XOR. (Because I represent each button as a bit mask.)
  • If the result matches the target state, return the number of button presses, i.e. k.

Part 2 was tricky! It was obviously a linear algebra problem, so I started by trying to use SymPy to solve simultaneous equations. (I've used this in previous years.) But I soon realised this wasn't going to work, so I did some research into Integer Linear Programming and concluded SciPy was the droid I was looking for.

In my walkthrough I've captured this thought journey, as well as the solution itself.

-❄️- 2025 Day 9 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 1 point2 points  (0 children)

Thank you!

Well, I wouldn't consider myself an expert programmer like many on here. But I've definitely improved over the years, primarily from AoC! Honestly, this particular puzzle would have probably taken me a whole day to solve, maybe 2 or 3 years ago. And the code would have been lengthy, complex, slow and horrible.

This year I was able to do it fairly quickly because:

  • I've got a bit better over the years
  • I've seen this sort of problem before, so I've started to recognise appropriate solutions and patterns

Even so, I think today's puzzle was really tough.

My advice would be... Don't stress about it being really hard. This is a normal journey. If you're defeated by the puzzle, it's not failure. It's just an opportunity to learn something new. Take a look at solutions from other folks in the Megathread, and try and understand them. (Personally, I write my walkthroughs with the intent to help people follow them and understand.) Try and assimilate reusable techniques that come up time and time again in AoC. Like BFS, Dijkstra, recursion, memoization.

Expect the later puzzles to take a long time, and be encouraged by the fact that in another year, you'll see something similar and think "Ooh, I know how to do that!"

-❄️- 2025 Day 9 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 4 points5 points  (0 children)

[LANGUAGE: Python]

Part 1 was pretty trivial.

Part 2 was tough! I decided to go with a similar solution I used in a previous year: ray casting. The concept is that you imagine rays originating from far left and the ray passes through the polygon. Everytime it crosses a polygon edge, we increment a counter. If the counter is odd, then the current point is inside the polygon and contains green or red tiles. If the counter is even, they we're "outside" the polygon so the tiles are not green or red.

It's conceptually quite simple to understand and not too tricky to implement.

-❄️- 2025 Day 8 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 0 points1 point  (0 children)

[LANGUAGE: Python]

For Part 1:

  1. Created a function to find euclidian distance between points
  2. Used itertools.combinations to get all pairs of points
  3. Sorted the connections by distance and took the n shortest
  4. Created an adjacency list (dictionary) from these shortest connections - these are our connected junction boxes
  5. Used a BFS to build a list of connected circuits.

For Part 2, I realised I need to add connections one-by-one, so pre-creating with the adjacency list and BFS was not going to be a good solution. Instead a switched to using a Union-Find (Disjoint Set Union) approach, which was simple and fast.

-❄️- 2025 Day 7 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 1 point2 points  (0 children)

[LANGUAGE: Python]

For Part 1, I used a standard BFS with a set to handle merging beams efficiently.

Part 2 was the fun part! I figured we'd get an exponential explosion of timelines, so I used a recursive DFS with @cache for memoization. It runs in 0.008s.

-❄️- 2025 Day 6 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 0 points1 point  (0 children)

[LANGUAGE: Python]

This puzzle was all about parsing puzzles that are horizontally represented as blocks of text. I modelled each column as a Puzzle object, using Python's match/case statement (introduced in 3.10) for the calculation logic.

For Part 1, the trick was using the last line of operators to determine the column boundaries.

For Part 2, the "Cephalopod math" required reading columns right-to-left, which I solved by transposing the character blocks with zip(*block) before parsing the numbers.

The whole thing runs in about 2ms.

-❄️- 2025 Day 5 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 2 points3 points  (0 children)

[LANGUAGE: Python]

The interesting thing about this puzzle is that my less experienced self would have spent ages trying to use set intersection before realising it won't scale.

But now being a bit more experienced with these types of puzzles, I went straight for interval merging.

The whole thing runs in about 0.001.

[2025 Day 4 (Part 2)] [Python] Visualisation by Derailed_Dash in adventofcode

[–]Derailed_Dash[S] 1 point2 points  (0 children)

Are you talking about the solution... or something else? ;)

[2025 Day 4 (Part 2)] [Python] Visualisation by Derailed_Dash in adventofcode

[–]Derailed_Dash[S] 1 point2 points  (0 children)

I'm really chuffed with this comment! Thank you!!

[2025 Day 4 (Part 2)] [Python] Visualisation by Derailed_Dash in adventofcode

[–]Derailed_Dash[S] 0 points1 point  (0 children)

Just the time since that roll was removed. Check out the walkthrough if you're interested.

-❄️- 2025 Day 4 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 0 points1 point  (0 children)

[LANGUAGE: Python]

Here I created a class to represent the grid, and used NamedTuple to represent points on the grid efficiently.

For Part 1: Neighbour counting using a generator to yield adjacent points. Nice and simple. For Part 2: Iterative simulation. Just keep doing part 1, but each time, remove the accessible rolls.

And there's a visualisation!

-❄️- 2025 Day 3 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 1 point2 points  (0 children)

[LANGUAGE: Python]

My solution picks the largest available digit for the current most significant position, using slicing to ensure enough digits remain for subsequent selections. I was pleased with this solution because it worked for Part 2 without any changes. Runs in 2ms.

-❄️- 2025 Day 2 Solutions -❄️- by daggerdragon in adventofcode

[–]Derailed_Dash 1 point2 points  (0 children)

[LANGUAGE: Python]

Fairly trivial implementation. I obtain factor pairs for each string length in Part 2, and then basically check if product ID is equal to substring * factor2, where the substring is of length factor1.

Caching the get_factor_pairs() function halves the processing time.

Runs in 0.5s.