use core::fmt; use std::{ io::{stdin, Read}, str::FromStr, }; #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum Rps { Rock, Paper, Scissors, } impl Rps { fn outcome_against(&self, other: Rps) -> Outcome { match (self, other) { (Rps::Rock, Rps::Scissors) | (Rps::Paper, Rps::Rock) | (Rps::Scissors, Rps::Paper) => { Outcome::Win } (Rps::Rock, Rps::Rock) | (Rps::Paper, Rps::Paper) | (Rps::Scissors, Rps::Scissors) => { Outcome::Draw } (Rps::Rock, Rps::Paper) | (Rps::Paper, Rps::Scissors) | (Rps::Scissors, Rps::Rock) => { Outcome::Lose } } } fn score(&self) -> u64 { match self { Rps::Rock => 1, Rps::Paper => 2, Rps::Scissors => 3, } } fn with_outcome(&self, outcome: Outcome) -> Rps { match (self, outcome) { (r, Outcome::Draw) => *r, (Rps::Rock, Outcome::Lose) => Rps::Scissors, (Rps::Paper, Outcome::Lose) => Rps::Rock, (Rps::Scissors, Outcome::Lose) => Rps::Paper, (Rps::Rock, Outcome::Win) => Rps::Paper, (Rps::Paper, Outcome::Win) => Rps::Scissors, (Rps::Scissors, Outcome::Win) => Rps::Rock, } } } impl FromStr for Rps { type Err = (); fn from_str(s: &str) -> Result { match s { "A" | "X" => Ok(Rps::Rock), "B" | "Y" => Ok(Rps::Paper), "C" | "Z" => Ok(Rps::Scissors), _ => Err(()), } } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum Outcome { Lose, Draw, Win, } impl Outcome { fn score(&self) -> u64 { match self { Outcome::Lose => 0, Outcome::Draw => 3, Outcome::Win => 6, } } } impl FromStr for Outcome { type Err = (); fn from_str(s: &str) -> Result { match s { "X" => Ok(Outcome::Lose), "Y" => Ok(Outcome::Draw), "Z" => Ok(Outcome::Win), _ => Err(()), } } } fn get_score(s: &str, f: F) -> u64 where F: Fn(Rps, Rhs) -> (Rps, Outcome), Rhs: FromStr, ::Err: fmt::Debug, { s.lines() .map(|line| { let mut parts = line.split_whitespace(); let other: Rps = parts.next().unwrap().parse().unwrap(); let rhs = parts.next().unwrap().parse().unwrap(); let (me, outcome) = f(other, rhs); me.score() + outcome.score() }) .sum() } fn main() { let mut data = String::new(); stdin().read_to_string(&mut data).unwrap(); println!( "{}", get_score(&data, |other, me| (me, me.outcome_against(other))) ); println!( "{}", get_score(&data, |other, outcome| ( other.with_outcome(outcome), outcome )) ); }