// Copyright 2022 Christian Ulrich // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // usage: ./part2 < input use std::convert::TryFrom; use std::io; #[derive(Debug, Clone, Copy)] enum Item { Rock = 1, Paper = 2, Scissors = 3, } enum Outcome { Lose = 0, Draw = 3, Win = 6, } struct Round { me: Item, other: Item, } struct Rounds {} impl TryFrom<&str> for Item { type Error = &'static str; fn try_from(value: &str) -> Result { match value { "A" => Ok(Item::Rock), "B" => Ok(Item::Paper), "C" => Ok(Item::Scissors), _ => Err("invalid value"), } } } impl TryFrom<&str> for Outcome { type Error = &'static str; fn try_from(value: &str) -> Result { match value { "X" => Ok(Outcome::Lose), "Y" => Ok(Outcome::Draw), "Z" => Ok(Outcome::Win), _ => Err("invalid value"), } } } impl Round { pub fn new(me: Item, other: Item) -> Self { Self { me: me, other: other, } } pub fn with_outcome(other: Item, outcome: Outcome) -> Self { let me = match (other, outcome) { (Item::Rock, Outcome::Lose) => Item::Scissors, (Item::Rock, Outcome::Win) => Item::Paper, (Item::Paper, Outcome::Lose) => Item::Rock, (Item::Paper, Outcome::Win) => Item::Scissors, (Item::Scissors, Outcome::Lose) => Item::Paper, (Item::Scissors, Outcome::Win) => Item::Rock, _ => other, }; Self::new(me, other) } fn outcome(&self) -> Outcome { match (self.me, self.other) { (Item::Rock, Item::Paper) => Outcome::Lose, (Item::Rock, Item::Scissors) => Outcome::Win, (Item::Paper, Item::Rock) => Outcome::Win, (Item::Paper, Item::Scissors) => Outcome::Lose, (Item::Scissors, Item::Rock) => Outcome::Lose, (Item::Scissors, Item::Paper) => Outcome::Win, _ => Outcome::Draw, } } pub fn score(&self) -> usize { self.outcome() as usize + self.me as usize } } impl Iterator for Rounds { type Item = Result; fn next(&mut self) -> Option { if let Some(line) = io::stdin().lines().next() { let line = line.unwrap(); if line.len() > 0 { if let Some((left, right)) = line.split_once(' ') { if let (Ok(item), Ok(outcome)) = (Item::try_from(left), Outcome::try_from(right)) { return Some(Ok(Round::with_outcome(item, outcome))); } } return Some(Err("input file contains invalid line")); } } None } } fn main() -> Result<(), &'static str> { let rounds = Rounds {}; let mut result = 0; for round in rounds { result += round?.score(); } println!("{result}"); Ok(()) }