use anyhow::anyhow; use std::{ env, fs, ops::{Add, Sub}, str::FromStr, }; #[derive(Debug, PartialEq, Eq)] enum Rotation { Left(u32), Right(u32), } #[derive(Debug)] struct ParseRotationError; impl FromStr for Rotation { type Err = ParseRotationError; fn from_str(s: &str) -> Result { let mut chars = s.chars(); let lr = chars.next().ok_or(ParseRotationError)?; let n: u32 = chars .collect::() .parse() .map_err(|_| ParseRotationError)?; match lr { 'L' => Ok(Self::Left(n)), 'R' => Ok(Self::Right(n)), _ => Err(ParseRotationError), } } } #[derive(Clone, Copy, Debug)] struct Dial(u8); impl Dial { fn new() -> Self { Self(50) } } impl Add for Dial { type Output = Self; fn add(self, rhs: u32) -> Self::Output { let n = self.0 as u32; let m = (n + rhs) % 100; Self(m as u8) } } impl Sub for Dial { type Output = Self; fn sub(self, rhs: u32) -> Self::Output { let n = self.0 as u32; let m = (n + 100 - rhs % 100) % 100; Self(m as u8) } } impl PartialEq for Dial { fn eq(&self, other: &u8) -> bool { self.0 == *other } } fn main() -> anyhow::Result<()> { let mut args = env::args(); let input_path = args.nth(1).ok_or(anyhow!("usage: day1 INPUT"))?; let input = fs::read_to_string(input_path)?; let rotations: Vec = input .split_whitespace() .map(|s| s.parse().map_err(|_| anyhow!("bad rotation: {}", s))) .collect::>()?; println!("rotations: {}", rotations.len()); let mut dial = Dial::new(); let mut zeros = 0; for rot in rotations { println!("dial: {}", dial.0); println!("rotation: {:?}", rot); match rot { Rotation::Left(n) => dial = dial - n, Rotation::Right(n) => dial = dial + n, } if dial == 0 { zeros = zeros + 1; } } println!("zeros: {}", zeros); Ok(()) } #[cfg(test)] mod tests { use super::*; #[test] fn parse_rotation() { assert!("L2" .parse::() .is_ok_and(|rot| rot == Rotation::Left(2))); assert!("R929" .parse::() .is_ok_and(|rot| rot == Rotation::Right(929))); assert!("M1".parse::().is_err()); assert!("L".parse::().is_err()); assert!("2".parse::().is_err()); } #[test] fn dial() { let dial = Dial::new(); assert_eq!(dial + 1, 51); assert_eq!(dial + 50, 0); assert_eq!(dial + 100, 50); assert_eq!(dial + 150, 0); assert_eq!(dial + 2 + 48, 0); assert_eq!(dial + 45 + 60, 55); assert_eq!(dial - 45, 5); assert_eq!(dial - 45 - 10, 95); assert_eq!(dial - 1, 49); assert_eq!(dial - 68, 82); assert_eq!(dial - 68 - 30, 52); assert_eq!(dial - 100, 50); assert_eq!(dial - 998, 52); assert_eq!(dial - 150, 0); assert_eq!(dial - 51, 99); assert_eq!(dial - 50, 0); } }