diff --git a/src/day02.rs b/src/day02.rs new file mode 100644 index 0000000..adce6ba --- /dev/null +++ b/src/day02.rs @@ -0,0 +1,132 @@ +use std::str::FromStr; + +use aoc_runner_derive::{aoc, aoc_generator}; + +#[derive(Copy, Clone, Debug)] +pub struct InvalidMove; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Move { + Rock, + Paper, + Scissors, +} + +impl Move { + fn shape_score(self) -> u64 { + match self { + Self::Rock => 1, + Self::Paper => 2, + Self::Scissors => 3, + } + } + + fn round_score(self, opp: Self) -> u64 { + if self == opp { + return 3; + } + match (self, opp) { + (Self::Rock, Self::Scissors) => 6, + (Self::Scissors, Self::Paper) => 6, + (Self::Paper, Self::Rock) => 6, + _ => 0, + } + } +} + +impl FromStr for Move { + type Err = InvalidMove; + + fn from_str(s: &str) -> Result { + // X Y and Z are treated as moves because part 1 uses them as moves even though they are + // not. + match s { + "A" | "X" => Ok(Self::Rock), + "B" | "Y" => Ok(Self::Paper), + "C" | "Z" => Ok(Self::Scissors), + _ => Err(InvalidMove), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Outcome { + Lose, + Draw, + Win, +} + +impl Outcome { + fn compute_move(&self, opp: Move) -> Move { + match self { + Outcome::Lose => match opp { + Move::Rock => Move::Scissors, + Move::Paper => Move::Rock, + Move::Scissors => Move::Paper, + }, + Outcome::Draw => opp, + Outcome::Win => match opp { + Move::Rock => Move::Paper, + Move::Paper => Move::Scissors, + Move::Scissors => Move::Rock, + }, + } + } +} + +#[derive(Copy, Clone, Debug)] +pub struct InvalidOutcome; + +impl FromStr for Outcome { + type Err = InvalidOutcome; + + fn from_str(s: &str) -> Result { + match s { + "X" => Ok(Self::Lose), + "Y" => Ok(Self::Draw), + "Z" => Ok(Self::Win), + _ => Err(InvalidOutcome), + } + } +} + +#[aoc_generator(day2, part1)] +pub fn input_generator_part1(input: &str) -> Vec<(Move, Move)> { + input + .lines() + .map(|line| { + let (opp, you) = line.split_once(' ').unwrap(); + (opp.parse().unwrap(), you.parse().unwrap()) + }) + .collect::>() +} + +#[aoc(day2, part1)] +pub fn solve_part1(input: &[(Move, Move)]) -> u64 { + input + .iter() + .map(|&(opp, you)| you.shape_score() + you.round_score(opp)) + .sum() +} + +#[aoc_generator(day2, part2)] +pub fn input_generator_part2(input: &str) -> Vec<(Move, Outcome)> { + input + .lines() + .map(|line| { + let (opp, outcome) = line.split_once(' ').unwrap(); + (opp.parse().unwrap(), outcome.parse().unwrap()) + }) + .collect::>() +} + +#[aoc(day2, part2)] +pub fn solve_part2(input: &[(Move, Outcome)]) -> u64 { + input + .iter() + .map(|&(opp, outcome)| { + let you = outcome.compute_move(opp); + you.shape_score() + you.round_score(opp) + }) + .sum() +} diff --git a/src/lib.rs b/src/lib.rs index 5d1048b..4256064 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ use aoc_runner_derive::aoc_lib; pub mod day01; +pub mod day02; aoc_lib! { year = 2022 }