#![warn(clippy::pedantic)] use std::{cmp::max, io::stdin, str::FromStr}; use enum_map::{enum_map, Enum, EnumMap}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)] enum Colour { Red, Green, Blue, } impl FromStr for Colour { type Err = (); fn from_str(s: &str) -> Result { match s { "red" => Ok(Self::Red), "green" => Ok(Self::Green), "blue" => Ok(Self::Blue), _ => Err(()), } } } #[derive(Debug, Clone, PartialEq, Eq)] struct Draw { cubes: EnumMap, } impl Draw { pub fn is_valid(&self) -> bool { let max_values = enum_map! { Colour::Red => 12, Colour::Green => 13, Colour::Blue => 14, }; self.cubes.iter().all(|(c, n)| *n <= max_values[c]) } } impl FromStr for Draw { type Err = (); fn from_str(s: &str) -> Result { let cubes = s .split(", ") .map(|c| { let (n, colour) = c.split_once(' ').unwrap(); let n = n.parse().unwrap(); let colour = colour.parse().unwrap(); (colour, n) }) .collect(); Ok(Draw { cubes }) } } #[derive(Debug, Clone, PartialEq, Eq)] struct Game { draws: Vec, } impl Game { pub fn is_valid(&self) -> bool { self.draws.iter().all(Draw::is_valid) } pub fn minimum_cubes_power(&self) -> usize { self.draws .iter() .map(|draw| draw.cubes) .fold(EnumMap::default(), |mut acc, cubes| { for (c, n) in cubes { acc[c] = max(acc[c], n); } acc }) .values() .product() } } impl FromStr for Game { type Err = (); fn from_str(s: &str) -> Result { let (_, draws) = s.split_once(": ").unwrap(); let draws = draws .split("; ") .map(|draw| draw.parse().unwrap()) .collect(); Ok(Game { draws }) } } fn main() { let games: Vec = stdin() .lines() .map(|l| l.unwrap().parse().unwrap()) .collect(); let valid_game_ids = games .iter() .enumerate() .filter_map(|(i, g)| g.is_valid().then_some(i + 1)); println!("{}", valid_game_ids.sum::()); let powers = games.iter().map(Game::minimum_cubes_power); println!("{}", powers.sum::()); }