Skip to main content

aoc/year2025/
day01.rs

1//! # Secret Entrance
2//!
3//! Computes both parts together. Part two left (or negative) turns are easier to handle
4//! if we first "reverse" the dial, then treat it as a right turn. The [`rem_euclid`] method
5//! is a modulo operator that handles negative values. For example `-1.rem_euclid(100)` is 99.
6//!
7//! [`rem_euclid`]: https://doc.rust-lang.org/std/primitive.i32.html#method.rem_euclid
8use crate::util::parse::*;
9
10type Input = (i32, i32);
11
12pub fn parse(input: &str) -> Input {
13    let directions = input.bytes().filter(u8::is_ascii_uppercase);
14    let amounts = input.iter_signed::<i32>();
15
16    // Dial starts at fifty, not zero.
17    let (_, part_one, part_two) = directions.zip(amounts).fold(
18        (50, 0, 0),
19        |(dial, part_one, part_two), (direction, amount)| {
20            let (dial, zeros) = if direction == b'R' {
21                // Right (or positive) turns use normal modulo.
22                let total = dial + amount;
23                (total % 100, total / 100)
24            } else {
25                // To avoid an off-by-one error when the dial is already at zero during a left
26                // (or negative) turn, take the reflected value modulo 100.
27                let reversed = (100 - dial) % 100;
28                ((dial - amount).rem_euclid(100), (reversed + amount) / 100)
29            };
30
31            (dial, part_one + i32::from(dial == 0), part_two + zeros)
32        },
33    );
34
35    (part_one, part_two)
36}
37
38pub fn part1(input: &Input) -> i32 {
39    input.0
40}
41
42pub fn part2(input: &Input) -> i32 {
43    input.1
44}