use std::str::FromStr; use aoc_2022::*; type Input = Vec; type Output = i32; #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Shape { Rock, Paper, Scissors, } impl Shape { fn score(&self) -> i32 { match self { Shape::Rock => 1, Shape::Paper => 2, Shape::Scissors => 3, } } } impl FromStr for Shape { type Err = Report; fn from_str(s: &str) -> Result { if s.is_empty() { return Err(eyre!("empty string given")); } match s { "A" | "X" => Ok(Shape::Rock), "B" | "Y" => Ok(Shape::Paper), "C" | "Z" => Ok(Shape::Scissors), _ => Err(eyre!("unknown shape ‹{0}›", s)), } } } #[derive(Debug, Clone, Copy)] enum Outcome { Lose, Draw, Win, } #[derive(Debug, Clone, Copy)] struct Round { opponent: Shape, me: Shape, } impl FromStr for Round { type Err = Report; fn from_str(s: &str) -> Result { let mut split_str = s.split(' '); let opponent = split_str.next().unwrap().parse::(); let me = split_str.next().unwrap().parse::(); Ok(Round { opponent: opponent?, me: me?, }) } } 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 = find_result(&(self.me, self.opponent)); shape_score + result_score } fn expected_outcome(&self) -> Outcome { match self.me { Shape::Rock => Outcome::Lose, Shape::Paper => Outcome::Draw, Shape::Scissors => Outcome::Win, } } fn expected_score(&self) -> i32 { find_result_for_outcome(self.opponent, self.expected_outcome()) } } struct Day02; impl Solution for Day02 { fn parse_input>(pathname: P) -> Input { file_to_structs(pathname) } fn part_1(input: &Input) -> Output { input.iter().map(Round::score).sum() } fn part_2(input: &Input) -> Output { input.iter().map(Round::expected_score).sum() } } fn main() -> Result<()> { Day02::main() } test_sample!(day_02, Day02, 15, 12);