/// --- Part Two --- /// /// The Elf finishes helping with the tent and sneaks back over to you. "Anyway, the second column /// says how the round needs to end: X means you need to lose, Y means you need to end the round in /// a draw, and Z means you need to win. Good luck!" /// /// The total score is still calculated in the same way, but now you need to figure out what shape /// to choose so the round ends as indicated. The example above now goes like this: /// /// In the first round, your opponent will choose Rock (A), and you need the round to end in a /// draw (Y), so you also choose Rock. This gives you a score of 1 + 3 = 4. /// In the second round, your opponent will choose Paper (B), and you choose Rock so you lose /// (X) with a score of 1 + 0 = 1. /// In the third round, you will defeat your opponent's Scissors with Rock for a score of 1 + 6 /// = 7. /// /// Now that you're correctly decrypting the ultra top secret strategy guide, you would get a total /// score of 12. /// /// Following the Elf's instructions for the second column, what would your total score be if /// everything goes exactly according to your strategy guide? use clap::Parser; use itertools::Itertools; use std::fs::File; use std::io::prelude::*; use std::io::BufReader; use std::path::PathBuf; const FILEPATH: &'static str = "examples/input.txt"; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Cli { #[clap(short, long, default_value = FILEPATH)] file: PathBuf, } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] enum RockPaperScissorsKind { Rock, Paper, Scissors, } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] enum GameOutcome { Win, Loss, Draw, } #[derive(Copy, Clone, Debug)] struct GamePrediction { outcome: GameOutcome, opponent: RockPaperScissorsKind, } fn kind_to_value(kind: RockPaperScissorsKind) -> i32 { use RockPaperScissorsKind::*; match kind { Rock => 1, Paper => 2, Scissors => 3, } } fn opp_to_kind(val: char) -> Option { use RockPaperScissorsKind::*; match val { 'A' => Some(Rock), 'B' => Some(Paper), 'C' => Some(Scissors), _ => None, } } fn exp_out_to_outcome(val: char) -> Option { use GameOutcome::*; match val { 'X' => Some(Loss), 'Y' => Some(Draw), 'Z' => Some(Win), _ => None, } } fn outcome_to_value(outcome: GameOutcome) -> i32 { use GameOutcome::*; match outcome { Win => 6, Draw => 3, Loss => 0, } } fn pred_to_player_kind(pred: GamePrediction) -> RockPaperScissorsKind { use GameOutcome::*; use RockPaperScissorsKind::*; match (pred.outcome, pred.opponent) { (Win, Rock) => Paper, (Win, Paper) => Scissors, (Win, Scissors) => Rock, (Loss, Rock) => Scissors, (Loss, Paper) => Rock, (Loss, Scissors) => Paper, (Draw, x) => x, } } fn game_pred_to_value(prediction: GamePrediction) -> i32 { outcome_to_value(prediction.outcome) + kind_to_value(pred_to_player_kind(prediction)) } fn main() { let args = Cli::parse(); let file = File::open(&args.file).unwrap(); let reader = BufReader::new(file); let res: i32 = reader .lines() .map(|l| { l.unwrap() .split(' ') .map(|w| w.parse::().unwrap()) .collect_tuple::<(char, char)>() }) .map(|v| v.unwrap()) .map(|(o_char, out_char)| GamePrediction { outcome: exp_out_to_outcome(out_char).unwrap(), opponent: opp_to_kind(o_char).unwrap(), }) .map(|pred| game_pred_to_value(pred)) .sum(); println!( "The total score if everything goes exactly according to your strategy guide is {}", res ); }