Advent of Code 2025
A year ago, one of my friends showed me Advent of Code. However, since there were only a few days left in the event, I decided to wait until the next year to give it a shot. This year, I decided to give it a try, and I'm glad I did.
I will be updating this blog post with my solutions to the puzzles as I complete them. You can find all my solutions on GitHub.
For now, I've opted to use Python to solve the puzzles. However, I may switch to a different language if I decide to learn a new language.
Days
Day 1: Secret Entrance
Part 1
The puzzle involves the use of a dial in a safe. There are 100 numbers ranging from 0 to 99.
We are given a set of instructions in the form of L|R <number>. The L and R indicate the direction to turn the dial, and the <number> indicates the number of turns to make.
Once we finish doing all the operations, the password is the number of times the dial pointed to the number 0.
I opted to start with a data structure to define an instruction.
class Direction(Enum):
L = "L"
R = "R"
class Instruction:
def __init__(self, direction: Direction, distance: int):
self.direction = direction
self.distance = distance
This way, we can easily parse the instructions from the input file.
Next, I created a function to represent a move in the dial. Since we know the dial loops around in both directions, we can model these operations using modular arithmetic:
- Left moves are equivalent to subtracting the distance from the current position,
- Right moves are equivalent to adding the distance to the current position.
def move(position: int, direction: Direction, distance: int) -> int:
if direction == Direction.L:
return (position - distance) % MODULUS
else:
return (position + distance) % MODULUS
We are told that the dial starts at position 50. Now all that's left is to iterate through the instructions and add a counter that checks the position whenever we do a move operation and increments whenever it lands on 0.
def solve(instructions: list[Instruction]) -> int:
position = 50
zero_counter = 0
for instruction in instructions:
position = move(position, instruction)
if position == 0:
zero_counter += 1
return zero_counter
Running the code with the input file, we get the answer to the puzzle is 1081.
Part 2
The puzzle is the same as the previous one, but this time we need to find the number of times the dial passed through the number 0.
The move function has been modified a bit. It now looks like this:
def move(position: int, instruction: Instruction) -> tuple[int, int]:
"""Return (new_position, zero_hits) for a single rotation."""
delta = (
-instruction.distance
if instruction.direction == Direction.L
else instruction.distance
)
end_position = position + delta
zero_hits = count_zero_hits(position, end_position)
return end_position % MODULUS, zero_hits
Now, we first calculate a delta value based on the instruction. Then, we calculate the new position by adding the delta to the current position.
The reason for this is because we need to know the number of times the dial passed through 0. If we calculated just using modulus, we wouldn't be able to count how many times we passed through 0. For example, say an instruction says R300. The modulus would detect that we went over 0, but not how many times.
For this we can use the function count_zero_hits which looks like this:
def count_zero_hits(start: int, end: int) -> int:
"""Count how many clicks land on 0 while moving from start to end."""
if start == end:
return 0
if start < end:
return end // MODULUS - start // MODULUS
return (start - 1) // MODULUS - (end - 1) // MODULUS
This function calculates how many times the dial passed through 0 by using integer division with the modulus.
If the start and end positions are the same, we haven't moved, so we return 0. For positive movement, we calculate end // MODULUS - start // MODULUS. For negative movement, we adjust by subtracting 1 before dividing to account for the direction.
Running the code with the input file, we get the answer to the puzzle is 6689.