advent-of-code/2023/rust/src/day2.rs

141 lines
3.4 KiB
Rust

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<usize>,
green: Option<usize>,
blue: Option<usize>,
}
impl From<Vec<Reveal>> for RevealGroup {
fn from(value: Vec<Reveal>) -> 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<RevealGroup>,
}
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);
}
}