summaryrefslogtreecommitdiff
path: root/2022/src/bin/day_2.rs
diff options
context:
space:
mode:
Diffstat (limited to '2022/src/bin/day_2.rs')
-rw-r--r--2022/src/bin/day_2.rs167
1 files changed, 167 insertions, 0 deletions
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<dyn std::error::Error>> {
+ 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<GameRound>,
+}
+
+#[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)
+ }
+}