1
0
Fork 0
2022/src/bin/day02.rs
2023-01-06 20:00:52 +01:00

153 lines
3.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::str::FromStr;
use aoc_2022::*;
type Input = Vec<Round>;
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<Self, Self::Err> {
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<Self, Self::Err> {
let mut split_str = s.split(' ');
let opponent = split_str.next().unwrap().parse::<Shape>();
let me = split_str.next().unwrap().parse::<Shape>();
Ok(Round {
opponent: opponent?,
me: me?,
})
}
}
fn find_strategy<P>(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<Input, Output> for Day02 {
fn parse_input<P: AsRef<Path>>(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);