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(|&b| b.is_ascii_uppercase());
14    let amounts = input.iter_signed::<i32>();
15
16    // Dial starts at fifty, not zero.
17    let mut dial = 50;
18    let mut part_one = 0;
19    let mut part_two = 0;
20
21    for (direction, amount) in directions.zip(amounts) {
22        if direction == b'R' {
23            // Right (or positive) turns use normal modulo.
24            part_two += (dial + amount) / 100;
25            dial = (dial + amount) % 100;
26        } else {
27            // To avoid an [off by one error](https://en.wikipedia.org/wiki/Off-by-one_error)
28            // when the dial is already at zero during a left (or negative) turn, we take the
29            // reflected value modulo 100.
30            let reversed = (100 - dial) % 100;
31            part_two += (reversed + amount) / 100;
32            dial = (dial - amount).rem_euclid(100);
33        }
34        // Compute part one simultaneously.
35        part_one += i32::from(dial == 0);
36    }
37
38    (part_one, part_two)
39}
40
41pub fn part1(input: &Input) -> i32 {
42    input.0
43}
44
45pub fn part2(input: &Input) -> i32 {
46    input.1
47}