diff --git a/2023/rust/Cargo.lock b/2023/rust/Cargo.lock index 6050022..5947985 100644 --- a/2023/rust/Cargo.lock +++ b/2023/rust/Cargo.lock @@ -5,3 +5,28 @@ version = 3 [[package]] name = "aoc2023" version = "1.0.0" +dependencies = [ + "nom", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] diff --git a/2023/rust/Cargo.toml b/2023/rust/Cargo.toml index 744b15a..3b3df52 100644 --- a/2023/rust/Cargo.toml +++ b/2023/rust/Cargo.toml @@ -103,3 +103,4 @@ name = "day25" path = "src/day25.rs" [dependencies] +nom = "7.1.3" diff --git a/2023/rust/src/day2.rs b/2023/rust/src/day2.rs new file mode 100644 index 0000000..591de41 --- /dev/null +++ b/2023/rust/src/day2.rs @@ -0,0 +1,140 @@ +use crate::prelude::*; + +extern crate nom; + +mod prelude; + +use nom::{ + branch::alt, + bytes::complete::{tag, take_while_m_n}, + combinator::{map_res, value}, + multi::separated_list0, + IResult, +}; + +fn main() { + Day2::show(day_input(2), day_input(2)) +} + +type Solution = usize; + +#[derive(Debug, PartialEq, Clone)] +enum Reveal { + Red(usize), + Green(usize), + Blue(usize), +} + +#[derive(Debug, PartialEq)] +struct RevealGroup { + red: Option, + green: Option, + blue: Option, +} + +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, +} + +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) +} + +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 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> { + println!("that belle"); + let (input, id) = int(tag("Game ")(input)?.0)?; + let (input, reveal_groups) = separated_list0(tag("; "), reveal_group)(tag(": ")(input)?.0)?; + + println!("{id} {:?}", reveal_groups); + Ok((input, Game { id, reveal_groups })) +} + +struct Day2 {} +impl Day2 {} + +impl AoCSolution for Day2 { + type Input = String; + type Solution = Solution; + + 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 + }; + + input + .lines() + .map(|s| game(s).unwrap().1) + .filter(|g| g.reveal_groups.iter().all(valid_reveal_group)) + .map(|g| g.id) + .sum() + } + + fn part2(input: Self::Input) -> Self::Solution { + return 0; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + assert_eq!( + Day2::part1( + 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"# + .into() + ), + 8 + ); + assert_eq!(Day2::part2(r#""#.into()), 0); + } +}