diff --git a/src/bin/day02.rs b/src/bin/day02.rs index 831a32a..e650824 100644 --- a/src/bin/day02.rs +++ b/src/bin/day02.rs @@ -3,11 +3,12 @@ use std::str::FromStr; use aoc_2022::*; use color_eyre::eyre::Result; +use itertools::Itertools; use thiserror::Error; use tracing::*; use tracing_subscriber::EnvFilter; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Shape { Rock, Paper, @@ -28,7 +29,7 @@ impl Shape { enum ShapeError { #[error("empty string given")] Empty, - + #[error("unknown shape ‹{0}›")] UnknownShape(String), } @@ -85,20 +86,53 @@ impl FromStr for Round { } } +fn find_strategy

(predicate: P) -> (usize, (Shape, Shape)) +where + P: FnMut(&(usize, (Shape, Shape))) -> bool, +{ + // R P S + // R 3 0 6 + // P 6 3 0 + // S 0 6 3 + vec![ + // Loss + (Shape::Rock, Shape::Paper), + (Shape::Paper, Shape::Scissors), + (Shape::Scissors, Shape::Rock), + // Draw + (Shape::Rock, Shape::Rock), + (Shape::Paper, Shape::Paper), + (Shape::Scissors, Shape::Scissors), + // Win + (Shape::Rock, Shape::Scissors), + (Shape::Paper, Shape::Rock), + (Shape::Scissors, Shape::Paper), + ] + .into_iter() + .enumerate() + .find_or_first(predicate) + .unwrap() +} + +fn find_result(strategy: &(Shape, Shape)) -> i32 { + 3 * (find_strategy(|&(_, st)| st == *strategy).0 as i32 / 3) +} + +fn find_result_for_outcome(opponent: Shape, outcome: Outcome) -> i32 { + let range = match outcome { + Outcome::Lose => 0..3, + Outcome::Draw => 3..6, + Outcome::Win => 6..9, + }; + let (i, (shape, _)) = find_strategy(|&(i, (_, op))| range.contains(&i) && op == opponent); + + 3 * (i as i32 / 3) + shape.score() +} + impl Round { fn score(&self) -> i32 { let shape_score = self.me.score(); - - let result_score = match (self.me, self.opponent) { - (Shape::Scissors, Shape::Paper) => 6, - (Shape::Paper, Shape::Rock) => 6, - (Shape::Rock, Shape::Scissors) => 6, - (Shape::Paper, Shape::Scissors) => 0, - (Shape::Rock, Shape::Paper) => 0, - (Shape::Scissors, Shape::Rock) => 0, - _ => 3, - }; - + let result_score = find_result(&(self.me, self.opponent)); shape_score + result_score } @@ -111,23 +145,7 @@ impl Round { } fn expected_score(&self) -> i32 { - let result_score = match self.expected_outcome() { - Outcome::Lose => 0, - Outcome::Draw => 3, - Outcome::Win => 6, - }; - - let shape_score = match (self.expected_outcome(), self.opponent) { - (Outcome::Lose, Shape::Rock) => Shape::Scissors.score(), - (Outcome::Lose, Shape::Paper) => Shape::Rock.score(), - (Outcome::Lose, Shape::Scissors) => Shape::Paper.score(), - (Outcome::Win, Shape::Rock) => Shape::Paper.score(), - (Outcome::Win, Shape::Paper) => Shape::Scissors.score(), - (Outcome::Win, Shape::Scissors) => Shape::Rock.score(), - _ => self.opponent.score(), - }; - - result_score + shape_score + find_result_for_outcome(self.opponent, self.expected_outcome()) } }