mod utils; use utils::read_input; fn main() { let input = read_input(); let turns_both_moves: Vec<_> = input .lines() .map(|xs| { let mut parts = xs.split(' ').take(2).map(Move::parse); (parts.next().unwrap(), parts.next().unwrap()) }) .collect(); let total_score_p1: usize = turns_both_moves .iter() .map(|(them, us)| score(*them, *us)) .sum(); let total_score_p2: usize = turns_both_moves .into_iter() .map(|(them, us)| (them, us.to_outcome())) .map(|(them, outcome)| (them, them.to_get(outcome))) .map(|(them, us)| score(them, us)) .sum(); println!("Part 1: {}", total_score_p1); println!("Part 2: {}", total_score_p2); } fn score(them: Move, us: Move) -> usize { let won_val = match (them.beats(us), us.beats(them)) { (true, false) => 0, (false, true) => 6, (false, false) => 3, (a, b) => unreachable!("they beat us: {}, we beat them: {}", a, b), }; us.value() + won_val } #[derive(Debug, Clone, Copy)] enum Move { Rock, Paper, Scissors, } impl Move { fn parse(inp: &str) -> Self { match inp { "A" => Move::Rock, "B" => Move::Paper, "C" => Move::Scissors, "X" => Move::Rock, "Y" => Move::Paper, "Z" => Move::Scissors, _ => panic!("unrecognised move: {}", inp), } } fn to_outcome(self) -> Outcome { match self { Move::Rock => Outcome::Lose, Move::Paper => Outcome::Draw, Move::Scissors => Outcome::Win, } } fn beats(self, other: Move) -> bool { matches!( (self, other), (Move::Paper, Move::Rock) | (Move::Rock, Move::Scissors) | (Move::Scissors, Move::Paper) ) } fn to_get(self, outcome: Outcome) -> Self { match (self, outcome) { (_, Outcome::Draw) => self, (Move::Rock, Outcome::Win) => Move::Paper, (Move::Paper, Outcome::Win) => Move::Scissors, (Move::Scissors, Outcome::Win) => Move::Rock, (Move::Rock, Outcome::Lose) => Move::Scissors, (Move::Paper, Outcome::Lose) => Move::Rock, (Move::Scissors, Outcome::Lose) => Move::Paper, } } fn value(self) -> usize { match self { Move::Rock => 1, Move::Paper => 2, Move::Scissors => 3, } } } #[derive(Debug, Clone, Copy)] enum Outcome { Win, Draw, Lose, }