Advent of Code is an annual set of daily programming challenges every December.
Read the challenge for 2025, Day 1
The Problem
We are given a set of instructions on how to turn a dial to unlock a door. Each instruction indicates whether you should turn the dial left or right and by how much. If you rotate the dial below 0 or beyond 99, it loops back on itself. In the first part, we have to find out how many times the dial lands on zero. In the second part, we have to find out how many times the dial passes when rotated 0.
My Solution
I made a cheesy omelette for breakfast and solved this one in my head after reading the challenge in bed. When I hit the afternoon slump at work, I wrote it up!
I needed to get my input into a form I could work with. Initially, I wanted to parse the input, which looks like this
L68
L30
R48
L5
R60
L55
L1
L99
R14
L82
into a struct.
#[derive(Debug)]
enum Dir {
L,
R,
}
#[derive(Debug)]
struct Turn {
dir: Dir,
count: i32,
}
This was not necessary for part one, but I anticipated that the meaning of L and R might change in part two. I was wrong. Instead, it was better to just parse the inputs as positive and negative integers.
So I ended up reworking my solution to part one to use just a vector of signed integers.
Here is that parsing logic to take the raw input and get ints.
fn parse_input(input: &str) -> Result<Vec<i32>, anyhow::Error> {
input.lines().map(parse_line).collect()
}
fn parse_line(line: &str) -> Result<i32, anyhow::Error> {
let (dir, count) = line.split_at(1);
let sign = if dir == "L" {
-1
} else if dir == "R" {
1
} else {
return Err(anyhow!("Invalid direction"));
};
Ok(sign * count.parse::<i32>()?)
}
I called the location that the dial was pointing to idx (index).
With the vector of ints, I iterated over each “turn”. A left (L) turn is negative and a right (R) turn is positive in this set. My first approach used if statements to check for rollover before applying each turn, but this solution got unruly. It also didn’t account for cases where a turn would require more than one full cycle through the dial.
What worked better was to apply the turn by adding the turn to the index and then normalize the rollover that occurred.
fn part_1(turns: &Vec<i32>) -> i32 {
let max_idx = 99;
let min_idx = 0;
let n_indices = 100; // Because we include the 0 as an option
let mut idx = 50;
let mut n_zeros = 0;
for turn in turns {
// Apply, then normalize
idx += turn;
// Handle negative rollover.
while idx < min_idx {
idx += n_indices;
}
// Handle positive rollover
while idx > max_idx {
idx -= n_indices;
}
if idx == 0 {
n_zeros += 1;
}
}
n_zeros
}
For part two, I just needed to change where I incremented the n_zeros. Instead of incrementing when the index was zero, I would increment every time I had to “normalize” because of a rollover.
I made one silly mistake when first solving part two. When I added the zero counting at the rollovers, I kept the check for when the index landed at 0. Because the rollover check counted zeros at wrap-around, keeping the landing check meant zeros got counted twice.
fn part_2(turns: &Vec<i32>) -> i32 {
let max_idx = 99;
let min_idx = 0;
let n_indices = 100; // Because we include the 0 as an option
let mut idx = 50;
let mut n_zeros = 0;
for turn in turns {
// Apply, then normalize
idx += turn;
// Handle negative rollover.
while idx < min_idx {
n_zeros += 1;
idx += n_indices;
}
// Handle positive rollover
while idx > max_idx {
n_zeros += 1;
idx -= n_indices;
}
}
n_zeros
}
With a release build, my solution ran in 74.25µs on my MacBook Pro M2 Max.
2025-12-01T19:39:14.268Z DEBUG [advent_2025::day_01] Day 1
1154
6819
2025-12-01T19:39:14.269Z DEBUG [advent_2025::day_01] Duration 74.25µs
This was a fun way to get started with the month. You can read my full solution here.