use nom::{Parser, IResult}; use nom::character::complete::*; use nom::bytes::complete::*; use nom::sequence::*; use nom::combinator::*; use nom::number::complete as number; use nom::multi::*; struct Game { pub id: u32, pub rounds: Vec } #[derive(Default)] struct Round { pub red: u8, pub green: u8, pub blue: u8 } // feck, i think nom may have been a bit too much for this. fn parse_game(i: &str) -> IResult<&str, Game> { separated_pair( preceded( tag("Game "), digit1.map(|s: &str| s.parse().unwrap())), tag(": "), separated_list1( tag("; "), fold_many0( terminated( separated_pair( digit1.map(|s: &str| s.parse().unwrap()), tag(" "), alpha1), opt(tag(", "))), || Round::default(), |mut r, (n, t)| match t { "red" => {r.red = n; r}, "green" => {r.green = n; r}, "blue" => {r.blue = n; r}, _ => r }))).map(|(n, r)| Game{id: n, rounds: r}).parse(i) } static INPUT: &str = include_str!("input.txt"); fn main() { let valueified = INPUT.split("\n").filter(|s| !s.is_empty()).map(|g| parse_game(g).unwrap().1); let valid_id_sum = valueified.clone().filter(|g| !g.rounds.iter().any(|r| r.red > 12 || r.green > 13 || r.blue > 14)).map(|g| g.id).sum::(); println!("Sum of valid IDs: {valid_id_sum}"); let game_power_sum = valueified.map(|g| { let red = g.rounds.iter().map(|r| r.red).max().unwrap_or(0); let green = g.rounds.iter().map(|r| r.green).max().unwrap_or(0); let blue = g.rounds.iter().map(|r| r.blue).max().unwrap_or(0); red as u32 * green as u32 * blue as u32 }).sum::(); println!("Sum of game powers: {game_power_sum}"); }