#[derive(Debug)] enum Error { InvalidMove, InvalidOutcome, } #[derive(Clone, PartialEq)] enum Move { Rock, Paper, Scissors } impl Move { fn from_str(input: &str) -> Result { match input { "A"|"X" => Ok(Self::Rock), "B"|"Y" => Ok(Self::Paper), "C"|"Z" => Ok(Self::Scissors), _ => Err(Error::InvalidMove) } } fn beats(&self) -> Move { match self { Move::Rock => Move::Scissors, Move::Paper => Move::Rock, Move::Scissors => Move::Paper, } } fn is_beaten_by(&self) -> Move { match self { Move::Rock => Move::Paper, Move::Paper => Move::Scissors, Move::Scissors => Move::Rock, } } /// I don't really know why, but these moves have different scores fn score(&self) -> u64 { match self { Move::Rock => 1, Move::Paper => 2, Move::Scissors => 3, } } } enum Outcome { Win, Draw, Lose, } impl Outcome { pub fn from_str(input: &str) -> Result { match input { "X" => Ok(Self::Lose), "Y" => Ok(Self::Draw), "Z" => Ok(Self::Win), _ => Err(Error::InvalidOutcome) } } } fn play(player: Move, opponent: Move) -> Outcome { if player.beats() == opponent { Outcome::Win } else if player == opponent { Outcome::Draw } else { Outcome::Lose } } /// decrypt a rock-paper-scissors strategy guide, run through it and calculate the outcome pub fn part_1(input: &str) -> u64 { let mut score = 0; let throws = input.lines(); for throw in throws { let mut throw: Vec<&str> = throw.split_whitespace().take(2).collect(); let player = Move::from_str(throw.pop().unwrap()).unwrap(); let opponent = Move::from_str(throw.pop().unwrap()).unwrap(); score += player.score(); match play(player, opponent) { Outcome::Win => { score += 6; } Outcome::Draw => { score += 3; } Outcome::Lose => {} } } score } /// decrypt a rock-paper-scissors strategy guide, run through it and calculate the outcome pub fn part_2(input: &str) -> u64 { let mut score = 0; let throws = input.lines(); for throw in throws { let mut throw: Vec<&str> = throw.split_whitespace().take(2).collect(); let outcome= Outcome::from_str(throw.pop().unwrap()).unwrap(); let opponent = Move::from_str(throw.pop().unwrap()).unwrap(); let player = match outcome { Outcome::Win => opponent.is_beaten_by(), Outcome::Draw => opponent.clone(), Outcome::Lose => opponent.beats(), }; score += player.score(); match play(player, opponent) { Outcome::Win => { score += 6; } Outcome::Draw => { score += 3; } Outcome::Lose => {} } } score }