use crate::parser::{against_hand_parser, result_expected_parser, Hand, ResultExpected, Trick}; use nom::character::complete::{char, line_ending}; use nom::multi::separated_list1; use nom::sequence::separated_pair; use nom::IResult; fn trick_parser(s: &str) -> IResult<&str, Trick> { let (rest, hands): (&str, (Hand, ResultExpected)) = separated_pair(against_hand_parser, char(' '), result_expected_parser)(s)?; Ok((rest, hands.into())) } fn sequence_parser(s: &str) -> IResult<&str, Vec> { separated_list1(line_ending, trick_parser)(s) } pub(crate) fn parse(inp: &str) -> Vec { let (_, tricks): (&str, Vec) = sequence_parser(inp).expect("Couldn't parse input"); tricks.iter().map(|trick| trick.score()).collect() } #[cfg(test)] mod tests { use super::*; use crate::parser::{draw_expected, loss_expected, win_expected}; #[test] fn win_expected_parsed() { assert_eq!(Ok(("", ResultExpected::Win)), win_expected("Z")) } #[test] fn draw_expected_parsed() { assert_eq!(Ok(("", ResultExpected::Draw)), draw_expected("Y")) } #[test] fn loss_expected_parsed() { assert_eq!(Ok(("", ResultExpected::Lose)), loss_expected("X")) } macro_rules! param_test { ($($name:ident: $input:literal , $against:expr , $result:expr , $thrown:expr;)*) => { $(#[test] fn $name() { assert_eq!( Ok(( "", Trick { thrown: $thrown, against: $against } )), trick_parser($input) ) })* }; } param_test!( rock_thrown_loss_expected: "A X" , Hand::Rock , ResultExpected::Lose , Hand::Scissors; rock_thrown_draw_expected: "A Y", Hand::Rock, ResultExpected::Draw, Hand::Rock; rock_thrown_win_expected: "A Z", Hand::Rock, ResultExpected::Win, Hand::Paper; paper_thrown_loss_expected: "B X" , Hand::Paper , ResultExpected::Lose , Hand::Rock; paper_thrown_draw_expected: "B Y", Hand::Paper, ResultExpected::Draw, Hand::Paper; paper_thrown_win_expected: "B Z", Hand::Paper, ResultExpected::Win, Hand::Scissors; scissors_thrown_loss_expected: "C X" , Hand::Scissors , ResultExpected::Lose , Hand::Paper; scissors_thrown_draw_expected: "C Y", Hand::Scissors, ResultExpected::Draw, Hand::Scissors; scissors_thrown_win_expected: "C Z", Hand::Scissors, ResultExpected::Win, Hand::Rock; ); #[test] fn example_sequence_parsed() { assert_eq!( Ok(( "", vec![ Trick { against: Hand::Rock, thrown: Hand::Rock, }, Trick { against: Hand::Paper, thrown: Hand::Rock, }, Trick { against: Hand::Scissors, thrown: Hand::Rock, } ] )), sequence_parser("A Y\nB X\nC Z") ) } }