advent_of_code_2022/day_02/src/parser/part_02.rs
2022-12-04 12:41:55 -05:00

95 lines
3.2 KiB
Rust

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<Trick>> {
separated_list1(line_ending, trick_parser)(s)
}
pub(crate) fn parse(inp: &str) -> Vec<usize> {
let (_, tricks): (&str, Vec<Trick>) = 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")
)
}
}