summaryrefslogtreecommitdiffstats
path: root/src/day_02.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/day_02.rs')
-rw-r--r--src/day_02.rs170
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)?))
+ }
+}