115 lines
2.5 KiB
Rust
115 lines
2.5 KiB
Rust
#![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<Self, Self::Err> {
|
|
match s {
|
|
"red" => Ok(Self::Red),
|
|
"green" => Ok(Self::Green),
|
|
"blue" => Ok(Self::Blue),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
struct Draw {
|
|
cubes: EnumMap<Colour, usize>,
|
|
}
|
|
|
|
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<Self, Self::Err> {
|
|
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<Draw>,
|
|
}
|
|
|
|
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<Self, Self::Err> {
|
|
let (_, draws) = s.split_once(": ").unwrap();
|
|
let draws = draws
|
|
.split("; ")
|
|
.map(|draw| draw.parse().unwrap())
|
|
.collect();
|
|
Ok(Game { draws })
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let games: Vec<Game> = 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::<usize>());
|
|
|
|
let powers = games.iter().map(Game::minimum_cubes_power);
|
|
|
|
println!("{}", powers.sum::<usize>());
|
|
}
|