use nom::{ branch::alt, bytes::complete::tag, character::complete::{alpha1, anychar, line_ending, none_of, one_of}, combinator::{map, map_opt, map_res, opt, peek, value}, multi::{many1, separated_list1}, sequence::pair, IResult, }; use std::fs; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_1.txt")?; let parsed = CalibrationInput::parser(&input).unwrap().1; dbg!(parsed.calibration_sum()); Ok(()) } #[derive(Debug)] struct CalibrationInput(Vec); #[derive(Debug)] struct CalibrationValue(u32); #[derive(Debug)] struct CalibrationDigit(u8); impl CalibrationInput { fn calibration_sum(&self) -> u32 { self.0.iter().map(|d| d.0).sum() } fn parser(input: &str) -> IResult<&str, Self> { map( separated_list1(line_ending, CalibrationValue::parser), CalibrationInput, )(input) } } impl CalibrationValue { fn parser(input: &str) -> IResult<&str, Self> { map( many1(pair( opt(peek(CalibrationDigit::parser)), // peek is to not consume the 'one' in 'twone' none_of("\n"), // this is just to advance the input )), |digits| { let digits: Vec = digits .into_iter() .filter_map(|(d, _)| d.map(|d| d.0 as u32)) .collect(); CalibrationValue(digits[0] * 10 + digits[digits.len() - 1]) }, )(input) } } impl CalibrationDigit { fn parser(input: &str) -> IResult<&str, Self> { map( alt(( map(one_of("0123456789"), |c| { c.to_string().parse::().unwrap() }), value(0, tag("zero")), value(1, tag("one")), value(2, tag("two")), value(3, tag("three")), value(4, tag("four")), value(5, tag("five")), value(6, tag("six")), value(7, tag("seven")), value(8, tag("eight")), value(9, tag("nine")), )), CalibrationDigit, )(input) } }