Julia's Musings

Advent of Code 2025

My solutions to Advent of Code 2025 (in python)

December 02, 2025

I'm really excited for Advent of Code 2025. Specifically the changes which have been made to the format. Fewer puzzles means I'll actually be able to complete it this year instead of losing interest when it becomes too hard to complete a puzzle on a busy evening. No leaderboard means I'll give my variables sensible names instead of stuff like sm, data1, a and my personal favorite, b.

Here are my solutions with a little bit of writing about them. Using cool new subpages!

Advent of Code 2025 Day 1 ⭐⭐
Part 1
Yay modular arithmetic! This part is probably just setting the groundwork for part 2. I'm splitting up my input into direction and length, taking dial = (dial + direction*length) % 100 and incrementing password whenever dial == 0.

Advent of Code 2025 Day 1 ⭐⭐

Day 1 - Advent of Code 2025
The good news is that they've discovered project management! This has given them the tools they need to prevent their usual Christmas emergency. For example, they now know that the North Pole decorations need to be finished soon so that other critical tasks can start on time.
https://adventofcode.com/2025/day/1
AdventOfCode/Python/2025/01/main.py at 0b6ef73f4b3557d5abe44ecc6e79f7d5ae542f2e
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/0b6ef73f4b3557d5abe44ecc6e79f7d5ae542f2e/Python/2025/01/main.py

Part 1

Yay modular arithmetic! This part is probably just setting the groundwork for part 2. I'm splitting up my input into direction and length, taking dial = (dial + direction*length) % 100 and incrementing password whenever dial == 0.

Works like a charm

Part 2

0x434C49434B is hex for CLICK!

I like this wrinkle a lot. Naively it feels like you should just be able to take (dial + direction*length) % 100 and get the number of clicks, but this has a weird edge case when you start at 0 and move to the left. and possibly some other spooky unknown 👻 edge cases.

Because I wasn't super sure about this haunted method I decided to turn the problem into something I knew would work. length // 100 is the number of times we rotate the entire dial, meaning it is the number of times we pass 0 (or any number). Thankfully we also don't care about rotating the entire dial for getting the new dial number. So we can record our full rotations for the new password and then get rid of them before updating our dial

This puts the problem in a very controllable zone because we know new_dial is on the interval [-99, 198] ([0-99, 99+99]). Which means it could only pass one of 0 or 100 (which are congruent modulo 100). So we check to see if it has passed on of those.

We only need to check these two options because it's impossible for dial_new to increase past 0, and impossible for dial_new to decrease past 100.

After that we just sum all the clicks for each rotation, and we're through the door!

Advent of Code 2025 Day 2 ⭐⭐
I'm already really enjoying not needing to rush through these. I really enjoyed the leaderboard part of AoC as a way to push myself. But it's nice to message a friend back while working on the solution.
Part 1

Advent of Code 2025 Day 2 ⭐⭐

Day 2 - Advent of Code 2025
You get inside and take the elevator to its only other stop: the gift shop. "Thank you for visiting the North Pole!" gleefully exclaims a nearby sign. You aren't sure who is even allowed to visit the North Pole, but you know you can access the lobby through here, and from there you can access the rest of the North Pole base.
https://adventofcode.com/2025/day/2
AdventOfCode/Python/2025/02/main.py at 90b0b79a783c4a5af790b45efd42ebf5ce903c04
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/90b0b79a783c4a5af790b45efd42ebf5ce903c04/Python/2025/02/main.py

I'm already really enjoying not needing to rush through these. I really enjoyed the leaderboard part of AoC as a way to push myself. But it's nice to message a friend back while working on the solution.

Part 1

The good ol' strings masquerading as numbers problem.

I just panicked for a bit because I misread the section on leading zeros. No leading zeros 🕶️, no problems 🕶️

My plan is to take each start_id and find the first invalid_id after it. I'll have greater_half, lesser_half = start_id.split_in_the_middle() I'll then take the lesser half and set it to the greater half, handling the edge case. If it is still less than last_id then it's my first invalid id. I'll then increment both the right and left half by one, recording every invalid id I get until I hit last_id.

The edge cases we need to handle are (1) when the string is of odd length, and (2) when the lesser_half is greater than the greater_half. For first case we simply set greater_half to the closest power of 10. For the second case we increment greater_half.

Worked like a charm. And I'm pretty happy with how my code looks.

Part 2

Okay, the generalization here is going from halves to n sections, where 2 <= n <= len(end_id).

Most of the work here is generalizing our edge cases. The first edge case goes from "when the string is of odd length" to "when n does not divide the length of the string." In order to solve this I'm just running an exhaustive search on all lengths of strings from len(start_id) to len(end_id) for each n.

If we call the left-most section the greatest_sect then our second case can be generalized to "is str(greatest_sect)*n less than start_id. Because if it is we don't include it and skip to the next invalid id.

After checking both of those we do what we did before and iterate until we're over end_id.

This also worked like a charm! I had a couple annoying things I needed to debug. Namely I used len(start_id) // n instead of n itself when computing greatest_sect*n. The other error I had was not checking if the starting position was already past end_id which was an edge case I hadn't considered.

Oh I also converted from a list of invalid ids to a set because I didn't want to try to filter out duplicates.

Extra fun

Before pushing my code I'm going to add my part 1 solution to my part 2.

oh that was far easier than I thought it would be. Three line change which was the first thing I tried.

I just added this anywhere I add to my p2 invalid_ids set.

Advent of Code 2025 Day 3 ⭐⭐
I want you to know that I add the stars to the title only after I complete it
Part 1

Advent of Code 2025 Day 3 ⭐⭐

Day 3 - Advent of Code 2025
You descend a short staircase, enter the surprisingly vast lobby, and are quickly cleared by the security checkpoint. When you get to the main elevators, however, you discover that each one has a red light above it: they're all offline.
https://adventofcode.com/2025/day/3
AdventOfCode/Python/2025/03/main.py at c700ff9bb6a396027970c147041d2528acac6734
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/c700ff9bb6a396027970c147041d2528acac6734/Python/2025/03/main.py

I want you to know that I add the stars to the title only after I complete it

Part 1

I'm anticipating Part 2 a little too much due to this being a pretty easy start. We just need to find the greatest-leftmost digit and then find the greatest digit to the right of that.

I'm going to implement it easy-style knowing that I'll need to change everything dramatically for part 2.

Everything worked. I had a slight hiccup because I used a max function on a list of tuples with (battery_value, index) which gave me the rightmost-greatest value. fixed by simply using negative index. (which isn't great practice but I'm going to burn it down in part 2 I'm sure.

Part 2

This is better than I expected. I'm pretty certain my solution generalizes with the knowledge that I have to keep enough digits to the right to pick the rest of my numbers.

That didn't mean it was pleasant to implement. But it worked! I spent most of the time getting this range function range((-1*num_on)+1,1)) which in part 2 is just range(-11,1). I spent a bunch of time on it because using negative values for python splicing is not good for generalization. That's because of how list[:0] behaves. So I had to make a special case for that. Otherwise it was a fun and simple to implement problem!

Clean Up

My code is almost generalized enough to clean this up, so I'm going to take the extra step to make everything nice. That means making my part 2 implementation into a function call which takes the number of batteries to turn on, and getting rid of my silly negative python splicing in favor of using positive numbers.

Absolutely painless, just changed from

To

through a function definition on top and we're good to go!

Advent of Code 2025 Day 4 ⭐⭐
Part 1
I don't have any immediate guesses at part 2, so I'm going to implement this the really simple way. I'll make a set of all the rolls of paper, and then just check all 8 adjacent spaces.

Advent of Code 2025 Day 4 ⭐⭐

Day 4 - Advent of Code 2025
Decorating here will be easy: they can make their own decorations. What you really need is a way to get further into the North Pole base while the elevators are offline.
https://adventofcode.com/2025/day/4
AdventOfCode/Python/2025/04/main.py at 09d3f25b092e86df8be55114ddecb547a9c75c13
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/09d3f25b092e86df8be55114ddecb547a9c75c13/Python/2025/04/main.py

Part 1

I don't have any immediate guesses at part 2, so I'm going to implement this the really simple way. I'll make a set of all the rolls of paper, and then just check all 8 adjacent spaces.

Part 2

I'm pretty positive I can just iterate my part1 solution, but I'd rather propagate the removals than recompute it every time. So I'm going to update my set to a map with adjacent counts and then remove rolls of paper iteratively.

Relatively easy to implement. Though I spent more time than I care to admit debugging why my number was wrong. The answer was that I was printing the remaining rolls of paper, rather than the number of rolls removed. Now I'm using starting_rolls - ending_rolls for rolls removed, rather than manually counting them. Which I'm a fan of.

Advent of Code 2025 Day 5 ⭐⭐
Part 1
large ranges, and checking if numbers are in the ranges. Doesn't seem too awful, but I'll spend some time sorting and merging the intervals.

Advent of Code 2025 Day 5 ⭐⭐

Day 5 - Advent of Code 2025
As the forklifts break through the wall, the Elves are delighted to discover that there was a cafeteria on the other side after all.
https://adventofcode.com/2025/day/5
AdventOfCode/Python/2025/05/main.py at 403bd0d4e32838e69dd686900ca738538ea8301d
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/403bd0d4e32838e69dd686900ca738538ea8301d/Python/2025/05/main.py

Part 1

large ranges, and checking if numbers are in the ranges. Doesn't seem too awful, but I'll spend some time sorting and merging the intervals.

Merged and sorted my intervals! Now to check if a value is in the ranges. I'm going to do a binary search on the start of the ranges, and then check the end of the range.

Part 2

Well all that work paid off, this should be relatively easy.

It was.

I still don't know how to write pretty parsing code on these inputs with two different sections. but the solution itself is nice so I'll call it good.

Day 4 and 5 have both been heads-down with relatively simple solutions, and not a ton to play with. I'm guessing we'll continue the dead-simple write ups for a couple days before we hit the problems which make me want to assume the fetal position.

Advent of Code 2025 Day 6 ⭐⭐
Part 1
I'm doing this just after day 5, and I was just complaining about parsing problems...

Advent of Code 2025 Day 6 ⭐⭐

Day 6 - Advent of Code 2025
After helping the Elves in the kitchen, you were taking a break and helping them re-enact a movie scene when you over-enthusiastically jumped into the garbage chute!
https://adventofcode.com/2025/day/6
AdventOfCode/Python/2025/06/main.py at 4d49abf0ac1a8d300d45ead9831cf2447d555fd5
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/4d49abf0ac1a8d300d45ead9831cf2447d555fd5/Python/2025/06/main.py

Part 1

I'm doing this just after day 5, and I was just complaining about parsing problems...

I'm just going to zip each new list and feel like a lisp programmer.

I'm not super happy with my solution for part 1, but it works! Time for part 2...

Part 2

The good news is I can use my part1 solution code. The bad news is that I'm in parsing hell.

I'm going to take advantage of my part1 solution for evaluating problems, and shove everything in tuples. Otherwise I'm just going to read my array columnwise. Maybe if I'm lucky the compiler figures out how to store this stuff in memory efficiently.

Great so that worked flawlessly, and I hate everything about my code.

Clean Up*

I'm not actually cleaning anything up. But I wanted to see how others tackled the problem because I am quite displeased with the readability of my code.

https://old.reddit.com/r/adventofcode/comments/1pfguxk/2025_day_6_solutions/nsk9az5/

This solution from reddit is giving me some nice inspiration with map(str.split, input), and the builtin eval function. Otherwise I find this solution to be a bit too code-golfy. I'm not a huge fan of the zip(*A) rotation as it isn't super readable, but a good variable name or comment would solve it.

Half of the days done 🎉
Probably a third of the work done 🙈

Advent of Code 2025 Day 7 ⭐⭐
Part 1
TIL what a Tachyon Particle is: Wikipedia link. TL;DR it's a faster than light particle

Advent of Code 2025 Day 7 ⭐⭐

Day 7 - Advent of Code 2025
You thank the cephalopods for the help and exit the trash compactor, finding yourself in the familiar halls of a North Pole research wing.
https://adventofcode.com/2025/day/7
AdventOfCode/Python/2025/07/main.py at 4c8219692642dcf3ae256c4a7fa58e9e3ea67f41
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/4c8219692642dcf3ae256c4a7fa58e9e3ea67f41/Python/2025/07/main.py#

Part 1

TIL what a Tachyon Particle is: Wikipedia link. TL;DR it's a faster than light particle

The puzzle input looks like a Christmas Tree to me 🎄

I really like the setup for this problem. My immediate thought is to simply create a queue of different beams and manually go through each square of the grid.

I have a nagging feeling that there is a more fun way to represent the data though. Specifically a beam exists in a line until it hits a splitter. So I might prefer to record where each splitter is by column. That way I can just go down the list. I think this may hinder me in Part 2 if the beams start moving any way else but down. But I think the solution seems more interesting to implement.

Hopefully this is at all helpful...

Works on the test input! And works on the input. Nice.

I think the code for this part is fine

Part 2

I don't think this is the worst possible twist...

This graph is a beautiful directed acyclic graph. I know that for any given node the number of multiverses it is used in is equal to the sum of multiverses each incoming node is a part of. I should be able to keep track of that number for each node. And part1 tells me that should be relatively doable.

Splitter is starting to not look like a word to me...

Part 1 was really nice to do iteratively, but I'm thinking Part 2 would be much easier if I implemented it recursively so that I can do a bottom up sum of the multiverses.

At this point I've spent far too long trying to implement Part2 iteratively when I already have a recursive solution in my brain.

I implemented Part 2 recursively and it finished way faster than I expected it to. And it is correct! Wonderful.

I should have just jumped straight to the recursive solution to Part2. I was acting a bit too allergic to recursion for today. Happy to have learned that though. One of my favorite days so far.

I think it's sort of poetic that we never got "Advent of Code 2025 day 25." At least we got all the other ones.

Advent of Code 2025 Day 8 ⭐⭐
Part 1
The first thing that jumps out at me is we're working with 3d coordinates. Normally when dealing with 2d coordinates I will use Complex numbers, as they are much more ergonomic to work with. After doing some research it looks like I will have to go back to tuples.

Advent of Code 2025 Day 8 ⭐⭐

Day 8 - Advent of Code 2025
Equipped with a new understanding of teleporter maintenance, you confidently step onto the repaired teleporter pad.
https://adventofcode.com/2025/day/8
AdventOfCode/Python/2025/08/main.py at c527691e98f3c1a90cf968327b1da316febf48d9
AdventOfCode - My attempts at Advent of Code
https://winry.woach.me/Julia/AdventOfCode/src/commit/c527691e98f3c1a90cf968327b1da316febf48d9/Python/2025/08/main.py#

Part 1

The first thing that jumps out at me is we're working with 3d coordinates. Normally when dealing with 2d coordinates I will use Complex numbers, as they are much more ergonomic to work with. After doing some research it looks like I will have to go back to tuples.

I'm hesitant to brute force the distance between all points, but closest points is a pain to implement, and I only need to compute the distances once and then I can just begin linking junction boxes, which I think is the meat and potatoes of this problem.

I wrote my solution with sets, and then remembered that sets aren't hashable. Soo hopefully I didn't make any assumptions that will stop me from using frozensets.

My solution is pretty slow. Like 20 seconds slow. But it worked. Let's see what Part 2 has in store.

Part 2

Okay so more of the same thing.

It works easily on the test input.

Oh wow! I expected this to take much longer but it was only about 50ms slower. All the time my solution is taking is actually to compute the distances

Some cleanup

I decided to look and see if anyone has any cute solutions to computing the distances but I'm not seeing much. Favorite so far is math.dist(*p) to compute the distances. Integrated that into my solution, but it didn't speed things up much. A lot of these solutions are simply me but stronger.

Looks like the solution is itertools. Lots of the comments on the reddit have the following code snippet

This speeds up my code from 18 seconds to 1 second. I've left my old solution commented out in my code.

I really need to learn itertools ;-;

I'll add these as I do them 👏👏

Subscribe to Julia's Musings
to get updates in Reader, RSS, or via Bluesky Feed

advent-of-code
programming