mod prelude; extern crate nom; use crate::prelude::*; use nom::{ branch::alt, bytes::complete::{tag, take_while}, combinator::{map_res, value}, multi::separated_list0, IResult, }; use std::cmp::max; fn main() { Day2::show(day_input(2), day_input(2)) } #[derive(Debug, PartialEq, Clone)] enum Reveal { Red(usize), Green(usize), Blue(usize), } #[derive(Debug, PartialEq)] struct Game { id: usize, reveals: Vec, } // parser fn int(input: &str) -> IResult<&str, usize> { map_res(take_while(char::is_numeric), str::parse)(input) } fn reveal(input: &str) -> IResult<&str, Reveal> { let (input, num) = int(input)?; alt(( value(Reveal::Red(num), tag(" red")), value(Reveal::Green(num), tag(" green")), value(Reveal::Blue(num), tag(" blue")), ))(input) } fn game(input: &str) -> IResult<&str, Game> { let (input, id) = int(tag("Game ")(input)?.0)?; let (input, reveals) = separated_list0(alt((tag(", "), tag("; "))), reveal)(tag(": ")(input)?.0)?; Ok((input, Game { id, reveals })) } impl Game { fn possible_power(&self) -> usize { // TODO: probably the last place to cleanup nicely let mut factors: [usize; 3] = [0, 0, 0]; for r in &self.reveals { match r { Reveal::Red(n) => factors[0] = max(*n, factors[0]), Reveal::Green(n) => factors[1] = max(*n, factors[1]), Reveal::Blue(n) => factors[2] = max(*n, factors[2]), } } factors.iter().fold(1, |a, b| a * b) } } struct Day2 {} impl AoCSolution for Day2 { type Input = String; type Solution = usize; fn part1(input: Self::Input) -> Self::Solution { let valid = |r: &Reveal| match r { Reveal::Red(n) => *n <= 12, Reveal::Green(n) => *n <= 13, Reveal::Blue(n) => *n <= 14, }; input .lines() .map(|s| game(s).unwrap().1) .filter(|g| g.reveals.iter().all(valid)) .map(|g| g.id) .sum() } fn part2(input: Self::Input) -> Self::Solution { input .lines() .map(|s| game(s).unwrap().1.possible_power()) .sum() } } #[cfg(test)] mod tests { use super::*; #[test] fn test() { let input = r#"Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green"#; assert_eq!(Day2::part1(input.into()), 8); assert_eq!(Day2::part2(input.into()), 2286); } }