diff options
Diffstat (limited to 'src/day_02.rs')
-rw-r--r-- | src/day_02.rs | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/day_02.rs b/src/day_02.rs new file mode 100644 index 0000000..a27fbc8 --- /dev/null +++ b/src/day_02.rs @@ -0,0 +1,170 @@ +use std::str::FromStr; + +use anyhow::{anyhow, Result}; + +use crate::{Problem, Solution}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct Game { + shapes: (Shape, Shape), + outcome: Outcome, + score: usize, +} + +impl Game { + fn new(a: Shape, b: Shape, outcome: Outcome) -> Self { + Self { + shapes: (a, b), + outcome, + score: b as usize + outcome as usize, + } + } +} + +impl From<(Shape, Shape)> for Game { + fn from((a, b): (Shape, Shape)) -> Self { + Self::new(a, b, (a, b).into()) + } +} + +impl From<(Shape, Outcome)> for Game { + fn from((a, outcome): (Shape, Outcome)) -> Self { + Self::new(a, (a, outcome).into(), outcome) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +enum Outcome { + Loss = 0, + Draw = 3, + Win = 6, +} + +impl From<(Shape, Shape)> for Outcome { + fn from((a, b): (Shape, Shape)) -> Self { + match (a, b) { + (Shape::Rock, Shape::Rock) => Outcome::Draw, + (Shape::Rock, Shape::Paper) => Outcome::Win, + (Shape::Rock, Shape::Scissors) => Outcome::Loss, + (Shape::Paper, Shape::Rock) => Outcome::Loss, + (Shape::Paper, Shape::Paper) => Outcome::Draw, + (Shape::Paper, Shape::Scissors) => Outcome::Win, + (Shape::Scissors, Shape::Rock) => Outcome::Win, + (Shape::Scissors, Shape::Paper) => Outcome::Loss, + (Shape::Scissors, Shape::Scissors) => Outcome::Draw, + } + } +} + +impl FromStr for Outcome { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "X" => Ok(Outcome::Loss), + "Y" => Ok(Outcome::Draw), + "Z" => Ok(Outcome::Win), + s => Err(anyhow!("Unknown symbol: {}", s)), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Shape { + Rock = 1, + Paper = 2, + Scissors = 3, +} + +impl From<(Shape, Outcome)> for Shape { + fn from((shape, outcome): (Shape, Outcome)) -> Self { + match (shape, outcome) { + (Shape::Rock, Outcome::Draw) => Shape::Rock, + (Shape::Rock, Outcome::Win) => Shape::Paper, + (Shape::Rock, Outcome::Loss) => Shape::Scissors, + (Shape::Paper, Outcome::Loss) => Shape::Rock, + (Shape::Paper, Outcome::Draw) => Shape::Paper, + (Shape::Paper, Outcome::Win) => Shape::Scissors, + (Shape::Scissors, Outcome::Win) => Shape::Rock, + (Shape::Scissors, Outcome::Loss) => Shape::Paper, + (Shape::Scissors, Outcome::Draw) => Shape::Scissors, + } + } +} + +impl FromStr for Shape { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "A" | "X" => Ok(Shape::Rock), + "B" | "Y" => Ok(Shape::Paper), + "C" | "Z" => Ok(Shape::Scissors), + s => Err(anyhow!("Unknown symbol: {}", s)), + } + } +} + +pub struct Day02; + +impl Problem for Day02 { + const DAY: u8 = 3; + + const INPUT: &'static str = include_str!("../input/day_2.txt"); +} + +impl Solution for Day02 { + type Answer1 = usize; + + type Answer2 = usize; + + fn part_1(input: &str) -> Result<Self::Answer1, anyhow::Error> { + input.lines().try_fold(0, |acc, l| { + let (a, b) = l + .split_once(' ') + .ok_or_else(|| anyhow!("Missing deliminator"))?; + + let a: Shape = a.parse()?; + let b: Shape = b.parse()?; + let game: Game = (a, b).into(); + + Ok(acc + game.score) + }) + } + + fn part_2(input: &str) -> Result<Self::Answer2, anyhow::Error> { + input.lines().try_fold(0, |acc, l| { + let (a, outcome) = l + .split_once(' ') + .ok_or_else(|| anyhow!("Missing deliminator"))?; + + let a: Shape = a.parse()?; + let outcome: Outcome = outcome.parse()?; + let game: Game = (a, outcome).into(); + + Ok(acc + game.score) + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const INPUT: &str = indoc::indoc! {" + A Y + B X + C Z + "}; + + #[test] + fn test_part_1_example() -> Result<()> { + Ok(assert_eq!(15, Day02::part_1(INPUT)?)) + } + + #[test] + fn test_part_2_example() -> Result<()> { + Ok(assert_eq!(12, Day02::part_2(INPUT)?)) + } +} |