2022-12-03 08:53:34 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
enum Error {
|
|
|
|
|
InvalidMove,
|
|
|
|
|
InvalidOutcome,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq)]
|
|
|
|
|
enum Move {
|
|
|
|
|
Rock,
|
|
|
|
|
Paper,
|
|
|
|
|
Scissors
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Move {
|
|
|
|
|
fn from_str(input: &str) -> Result<Self, Error> {
|
|
|
|
|
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<Self, Error> {
|
|
|
|
|
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();
|
2022-12-03 09:06:36 +00:00
|
|
|
|
|
|
|
|
let outcome= Outcome::from_str(throw.pop().unwrap()).unwrap();
|
2022-12-03 08:53:34 +00:00
|
|
|
let opponent = Move::from_str(throw.pop().unwrap()).unwrap();
|
|
|
|
|
|
2022-12-03 09:06:36 +00:00
|
|
|
let player = match outcome {
|
|
|
|
|
Outcome::Win => opponent.is_beaten_by(),
|
2022-12-03 08:53:34 +00:00
|
|
|
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
|
|
|
|
|
}
|