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}