use nom::{ branch::alt, bytes::complete::tag, character::complete::{i64 as nom_i64, line_ending, space1}, combinator::{map, value}, 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)] struct Instruction { direction: Direction, distance: Distance, } #[derive(Debug, Clone)] enum Direction { Forward, Up, Down, } #[derive( Default, Debug, Clone, Copy, derive_more::Add, derive_more::AddAssign, derive_more::Sub, derive_more::SubAssign, )] struct Distance(i64); #[derive(Default, Debug)] struct Position { horizontal: Distance, depth: Distance, } impl Position { fn advance(&mut self, instruction: &Instruction) { match instruction.direction { Direction::Forward => self.horizontal += instruction.distance, Direction::Down => self.depth += instruction.distance, Direction::Up => self.depth -= instruction.distance, } } } 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> { map( tuple((parse_direction, space1, parse_distance)), |(direction, _, distance)| Instruction { direction, distance, }, )(input) } fn parse_direction(input: &str) -> IResult<&str, Direction> { alt(( value(Direction::Forward, tag("forward")), value(Direction::Up, tag("up")), value(Direction::Down, tag("down")), ))(input) } fn parse_distance(input: &str) -> IResult<&str, Distance> { map(nom_i64, Distance)(input) }