diff --git a/src/main.rs b/src/main.rs index df0d807..8e99978 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,11 @@ const DATA: &'static str = include_str!("input.txt"); +// I can use unwrap()/expect() as much as I want here, since for AoC the input data is expected to make sense. + use std::str::FromStr; -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone, Copy)] enum Move { Rock, @@ -13,12 +15,11 @@ enum Move } #[derive(PartialEq, Eq)] -#[repr(i32)] enum Outcome { - Loss = 0, - Draw = 3, - Win = 6 + Loss, + Draw, + Win } impl Outcome @@ -44,7 +45,7 @@ impl Move } } - pub fn did_win(&self, other: &Move) -> Outcome + pub fn did_win_against(&self, other: &Move) -> Outcome { if self == other { Outcome::Draw } else { @@ -66,6 +67,29 @@ impl Move } } } + + pub fn move_for_outcome(&self, outcome: Outcome) -> Move + { + if outcome == Outcome::Draw { *self } + else { + match self { + Self::Rock => { + if outcome == Outcome::Win { Self::Paper } + else { Self::Scissors } + } + + Self::Paper => { + if outcome == Outcome::Win { Self::Scissors } + else { Self::Rock } + } + + Self::Scissors => { + if outcome == Outcome::Win { Self::Rock } + else { Self::Paper } + } + } + } + } } #[derive(Debug)] @@ -89,18 +113,38 @@ impl FromStr for Move { } } +#[derive(Debug)] +enum OutcomeParseFailure +{ + InvalidOutcome, +} + +impl FromStr for Outcome { + type Err = OutcomeParseFailure; + fn from_str(s: &str) -> Result { + match s { + "X" => Ok(Self::Loss), + "Y" => Ok(Self::Draw), + "Z" => Ok(Self::Win), + _ => Err(OutcomeParseFailure::InvalidOutcome) + } + } +} + fn score_for_round(my_move: &Move, other_move: &Move) -> i32 { let mut score = my_move.as_score(); - let outcome = my_move.did_win(other_move); + let outcome = my_move.did_win_against(other_move); score += outcome.as_score(); score } -fn parse_round_and_get_score(round_str: &str) -> Option +// Calling nth() on an iterator consumes the returned element, that's why I'm calling nth(0) several times + +fn parse_round_and_get_score_part1(round_str: &str) -> Option { let mut moves = round_str.split(" "); @@ -111,16 +155,42 @@ fn parse_round_and_get_score(round_str: &str) -> Option &first_move.parse().expect("Expected a valid move"))) } +fn parse_round_and_get_score_part2(round_str: &str) -> Option +{ + let mut moves = round_str.split(" "); + + let opponent_move_str = moves.nth(0)?; // Opponent's move goes first + let expected_outcome_str = moves.nth(0)?; // Expected outcome goes second + + let expected_outcome: Outcome = expected_outcome_str.parse().expect("Expected a valid outcome"); + let opponent_move: Move = opponent_move_str.parse().expect("Expected a valid move"); + + Some(score_for_round(&opponent_move.move_for_outcome(expected_outcome), + &opponent_move)) +} + +#[allow(dead_code)] fn part1() { let mut score = 0; for slice in DATA.split("\n") { - score += parse_round_and_get_score(slice).expect("Input data is not correctly structured"); + score += parse_round_and_get_score_part1(slice).expect("Input data is not correctly structured"); + } + println!("Your total score is {}", score); +} + +fn part2() +{ + let mut score = 0; + for slice in DATA.split("\n") + { + score += parse_round_and_get_score_part2(slice).expect("Input data is not correctly structured"); } println!("Your total score is {}", score); } fn main() { - part1(); + //part1(); + part2(); }