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}