use nom::{ branch::alt, bytes::complete::tag, character::complete::{i64 as nom_i64, line_ending, space1}, combinator::map, multi::separated_list1, sequence::tuple, IResult, }; use std::fs; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_2.txt")?; let route = parse_route(&input).unwrap().1; let mut position = Position::default(); for instruction in &route { position.advance(&instruction); } dbg!(position.horizontal.0 * position.depth.0); Ok(()) } #[derive(Debug)] struct Route(Vec); impl<'a> IntoIterator for &'a Route { type Item = &'a Instruction; type IntoIter = std::slice::Iter<'a, Instruction>; fn into_iter(self) -> ::IntoIter { self.0.iter() } } #[derive(Debug)] enum Instruction { Forward(Distance), Up(Aim), Down(Aim), } #[derive( Default, Debug, Clone, Copy, derive_more::Add, derive_more::AddAssign, derive_more::Sub, derive_more::SubAssign, )] struct Distance(i64); #[derive( Default, Debug, Clone, Copy, derive_more::Add, derive_more::AddAssign, derive_more::Sub, derive_more::SubAssign, )] struct Aim(i64); impl std::ops::Mul for Aim { type Output = Distance; fn mul(self, other: Distance) -> Distance { Distance(self.0 * other.0) } } #[derive(Default, Debug)] struct Position { horizontal: Distance, depth: Distance, aim: Aim, } impl Position { fn advance(&mut self, instruction: &Instruction) { match instruction { Instruction::Forward(distance) => { self.horizontal += *distance; self.depth += self.aim * *distance; } Instruction::Down(aim) => self.aim += *aim, Instruction::Up(aim) => self.aim -= *aim, } } } fn parse_route(input: &str) -> IResult<&str, Route> { map(separated_list1(line_ending, parse_instruction), Route)(input) } fn parse_instruction(input: &str) -> IResult<&str, Instruction> { alt((parse_forward, parse_up, parse_down))(input) } fn parse_forward(input: &str) -> IResult<&str, Instruction> { map( tuple((tag("forward"), space1, parse_distance)), |(_, _, distance)| Instruction::Forward(distance), )(input) } fn parse_up(input: &str) -> IResult<&str, Instruction> { map(tuple((tag("up"), space1, parse_aim)), |(_, _, aim)| { Instruction::Up(aim) })(input) } fn parse_down(input: &str) -> IResult<&str, Instruction> { map(tuple((tag("down"), space1, parse_aim)), |(_, _, aim)| { Instruction::Down(aim) })(input) } fn parse_distance(input: &str) -> IResult<&str, Distance> { map(nom_i64, Distance)(input) } fn parse_aim(input: &str) -> IResult<&str, Aim> { map(nom_i64, Aim)(input) }