From f070b6cff23e3db91088285ad922d6dcd24aef70 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Fri, 2 Dec 2022 13:10:24 +0200 Subject: Day 2 - Lots of room for improment on the game modelling --- 2022/src/bin/day_2.rs | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 2022/src/bin/day_2.rs (limited to '2022/src/bin') diff --git a/2022/src/bin/day_2.rs b/2022/src/bin/day_2.rs new file mode 100644 index 0000000..deb5294 --- /dev/null +++ b/2022/src/bin/day_2.rs @@ -0,0 +1,167 @@ +use nom::{ + branch::alt, + character::complete::{char as nom_char, line_ending}, + 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 game_log_part_1 = GameLog::parser(&input).unwrap().1; + dbg!(game_log_part_1.total_score()); + + let game_log_part_2 = GameLog::parser_part_2(&input).unwrap().1; + dbg!(game_log_part_2.total_score()); + Ok(()) +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct GameLog { + moves: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +struct GameRound { + opponent: Move, + me: Move, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +enum Move { + Rock, + Paper, + Scissors, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +enum GameResult { + Win, + Lose, + Draw, +} + +impl GameLog { + fn parser(input: &str) -> IResult<&str, GameLog> { + map(separated_list1(line_ending, GameRound::parser), |moves| { + GameLog { moves } + })(input) + } + + fn parser_part_2(input: &str) -> IResult<&str, GameLog> { + map( + separated_list1(line_ending, GameRound::parser_part_2), + |moves| GameLog { moves }, + )(input) + } + + fn total_score(&self) -> u32 { + self.moves.iter().map(|m| m.score()).sum() + } +} + +impl GameRound { + fn parser(input: &str) -> IResult<&str, GameRound> { + map( + tuple((Move::opponent_parser, nom_char(' '), Move::player_parser)), + |(opponent, _, me)| GameRound { opponent, me }, + )(input) + } + + fn parser_part_2(input: &str) -> IResult<&str, GameRound> { + map( + tuple((Move::opponent_parser, nom_char(' '), GameResult::parser)), + |(opponent, _, result)| { + use GameResult::*; + use Move::*; + + let me = match opponent { + Rock => match result { + Win => Paper, + Draw => Rock, + Lose => Scissors, + }, + Paper => match result { + Win => Scissors, + Draw => Paper, + Lose => Rock, + }, + Scissors => match result { + Win => Rock, + Draw => Scissors, + Lose => Paper, + }, + }; + GameRound { opponent, me } + }, + )(input) + } + + fn score(&self) -> u32 { + let victory_points = match self.me.beats(&self.opponent) { + GameResult::Lose => 0, + GameResult::Draw => 3, + GameResult::Win => 6, + }; + + let throw_points = match self.me { + Move::Rock => 1, + Move::Paper => 2, + Move::Scissors => 3, + }; + + victory_points + throw_points + } +} + +impl Move { + fn opponent_parser(input: &str) -> IResult<&str, Move> { + alt(( + value(Move::Rock, nom_char('A')), + value(Move::Paper, nom_char('B')), + value(Move::Scissors, nom_char('C')), + ))(input) + } + + fn player_parser(input: &str) -> IResult<&str, Move> { + alt(( + value(Move::Rock, nom_char('X')), + value(Move::Paper, nom_char('Y')), + value(Move::Scissors, nom_char('Z')), + ))(input) + } + + fn beats(&self, other: &Move) -> GameResult { + use GameResult::*; + use Move::*; + match self { + Rock => match other { + Rock => Draw, + Paper => Lose, + Scissors => Win, + }, + Paper => match other { + Rock => Win, + Paper => Draw, + Scissors => Lose, + }, + Scissors => match other { + Rock => Lose, + Paper => Win, + Scissors => Draw, + }, + } + } +} + +impl GameResult { + fn parser(input: &str) -> IResult<&str, GameResult> { + alt(( + value(GameResult::Lose, nom_char('X')), + value(GameResult::Draw, nom_char('Y')), + value(GameResult::Win, nom_char('Z')), + ))(input) + } +} -- cgit v1.2.3