diff --git a/2023/rust/src/day2.rs b/2023/rust/src/day2.rs index ae847f4..7245575 100644 --- a/2023/rust/src/day2.rs +++ b/2023/rust/src/day2.rs @@ -1,25 +1,19 @@ -use std::cmp::{max, min}; - -use crate::prelude::*; - -extern crate nom; - mod prelude; - +extern crate nom; +use crate::prelude::*; use nom::{ branch::alt, - bytes::complete::{tag, take_while_m_n}, + 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)) } -type Solution = usize; - #[derive(Debug, PartialEq, Clone)] enum Reveal { Red(usize), @@ -27,68 +21,15 @@ enum Reveal { Blue(usize), } -#[derive(Debug, PartialEq)] -struct RevealGroup { - red: Option, - green: Option, - blue: Option, -} - -impl RevealGroup { - fn power(&self) -> usize { - println!("reveal group power for {:?}", self); - self.red.unwrap_or(0) * self.green.unwrap_or(0) * self.blue.unwrap_or(0) - } -} - -impl From> for RevealGroup { - fn from(value: Vec) -> Self { - // TODO: this obviously won't work if the vector contains multiple reveals of the same kind - // there's probably a simpler way to parse it out - let mut result = Self { - red: None, - blue: None, - green: None, - }; - for v in value { - match v { - Reveal::Red(v) => result.red = Some(v), - Reveal::Green(v) => result.green = Some(v), - Reveal::Blue(v) => result.blue = Some(v), - } - } - result - } -} - #[derive(Debug, PartialEq)] struct Game { id: usize, - reveal_groups: Vec, -} - -impl Game { - fn made_possible(&self) -> RevealGroup { - let mut red = 0; - let mut green = 0; - let mut blue = 0; - for rg in &self.reveal_groups { - red = max(rg.red.unwrap_or(0), red); - green = max(rg.green.unwrap_or(0), green); - blue = max(rg.blue.unwrap_or(0), blue); - } - RevealGroup { - red: Some(red), - green: Some(green), - blue: Some(blue), - } - } + reveals: Vec, } +// parser fn int(input: &str) -> IResult<&str, usize> { - map_res(take_while_m_n(1, 16, |c: char| c.is_numeric()), |s| { - usize::from_str_radix(s, 10) - })(input) + map_res(take_while(char::is_numeric), str::parse)(input) } fn reveal(input: &str) -> IResult<&str, Reveal> { @@ -100,40 +41,44 @@ fn reveal(input: &str) -> IResult<&str, Reveal> { ))(input) } -fn reveal_group(input: &str) -> IResult<&str, RevealGroup> { - let (input, reveals) = separated_list0(tag(", "), reveal)(input)?; - Ok((input, RevealGroup::from(reveals))) -} - fn game(input: &str) -> IResult<&str, Game> { let (input, id) = int(tag("Game ")(input)?.0)?; - let (input, reveal_groups) = separated_list0(tag("; "), reveal_group)(tag(": ")(input)?.0)?; + let (input, reveals) = + separated_list0(alt((tag(", "), tag("; "))), reveal)(tag(": ")(input)?.0)?; + Ok((input, Game { id, reveals })) +} - Ok((input, Game { id, reveal_groups })) +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 Day2 {} - impl AoCSolution for Day2 { type Input = String; - type Solution = Solution; + type Solution = usize; fn part1(input: Self::Input) -> Self::Solution { - const MAX_RED: Solution = 12; - const MAX_GREEN: Solution = 13; - const MAX_BLUE: Solution = 14; - - let valid_reveal_group = |rg: &RevealGroup| { - rg.red.unwrap_or(0) <= MAX_RED - && rg.green.unwrap_or(0) <= MAX_GREEN - && rg.blue.unwrap_or(0) <= MAX_BLUE + 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.reveal_groups.iter().all(valid_reveal_group)) + .filter(|g| g.reveals.iter().all(valid)) .map(|g| g.id) .sum() } @@ -141,7 +86,7 @@ impl AoCSolution for Day2 { fn part2(input: Self::Input) -> Self::Solution { input .lines() - .map(|s| game(s).unwrap().1.made_possible().power()) + .map(|s| game(s).unwrap().1.possible_power()) .sum() } } diff --git a/2023/rust/src/prelude.rs b/2023/rust/src/prelude.rs index 73f6745..929ebf1 100644 --- a/2023/rust/src/prelude.rs +++ b/2023/rust/src/prelude.rs @@ -4,8 +4,6 @@ pub use std::io::Read; use std::path::{Path, PathBuf}; use std::{env, io}; -pub type Reader = Box; - #[derive(Debug)] enum InputFileError { VarError(env::VarError),