From 5cb5c9b672636fb10d39b24efc06ece47057e224 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Sun, 3 Dec 2023 21:37:55 +0200 Subject: Day 3 --- 2023/src/bin/day_3.rs | 146 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 8 deletions(-) (limited to '2023/src/bin/day_3.rs') diff --git a/2023/src/bin/day_3.rs b/2023/src/bin/day_3.rs index b3a610b..06e1300 100644 --- a/2023/src/bin/day_3.rs +++ b/2023/src/bin/day_3.rs @@ -1,19 +1,149 @@ -use nom::IResult; +use nom::{ + branch::alt, + bytes::complete::tag, + character::complete::{digit1, line_ending, none_of}, + combinator::{map, map_res}, + multi::{many1, separated_list1}, + IResult, +}; use std::fs; fn main() -> Result<(), Box> { - let input = fs::read_to_string("inputs/day_2.txt")?; - let parsed = Example::parser(&input).unwrap().1; - dbg!(&parsed); + let input = fs::read_to_string("inputs/day_3.txt")?; + let parsed = PartInventory::parser(&input).unwrap().1; + dbg!(&parsed.part_number_sum()); + dbg!(&parsed.gear_ratio_sum()); Ok(()) } #[derive(Debug)] -struct Example; +struct PartInventory { + parts: Vec, + symbols: Vec, +} + +#[derive(Debug)] +struct Part { + number: u32, + symbols: Vec, + y: usize, + min_x: usize, + max_x: usize, +} + +#[derive(Debug, Clone)] +struct Symbol { + symbol: char, + parts: Vec, + x: usize, + y: usize, +} + +#[derive(Debug)] +enum LexToken { + Space(usize), + Part(usize, u32), + Symbol(char), +} + +impl PartInventory { + fn parser(input: &str) -> IResult<&str, Self> { + map(LexToken::parser, |tokens| { + let mut parts = Vec::new(); + let mut symbols = Vec::new(); + + for (y, row) in tokens.iter().enumerate() { + let mut x = 0; + for token in row { + match token { + LexToken::Space(_) => {} + LexToken::Part(len, number) => parts.push(Part { + number: *number, + symbols: Vec::new(), + y, + min_x: x, + max_x: x + len - 1, + }), + LexToken::Symbol(symbol) => symbols.push(Symbol { + symbol: *symbol, + parts: Vec::new(), + y, + x, + }), + } + x += token.len(); + } + } + + for part in &mut parts { + part.symbols = symbols + .iter() + .filter(|symbol| part.touches(symbol)) + .map(|symbol| symbol.symbol) + .collect(); + } + + for symbol in &mut symbols { + symbol.parts = parts + .iter() + .filter(|part| part.touches(symbol)) + .map(|part| part.number) + .collect(); + } + + PartInventory { parts, symbols } + })(input) + } + + fn part_number_sum(&self) -> u32 { + self.parts + .iter() + .filter(|part| part.symbols.len() > 0) + .map(|part| part.number) + .sum() + } + + fn gear_ratio_sum(&self) -> u32 { + self.symbols + .iter() + .filter(|symbol| symbol.symbol == '*' && symbol.parts.len() == 2) + .map(|symbol| symbol.parts[0] * symbol.parts[1]) + .sum() + } +} + +impl LexToken { + fn parser(input: &str) -> IResult<&str, Vec>> { + separated_list1( + line_ending, + many1(alt(( + map(many1(tag(".")), |dots| LexToken::Space(dots.len())), + map_res(digit1, |num_s: &str| { + num_s + .parse() + .map(|num_i| LexToken::Part(num_s.len(), num_i)) + }), + map(none_of("\n"), |s| LexToken::Symbol(s)), + ))), + )(input) + } + + fn len(&self) -> usize { + match self { + Self::Space(len) => *len, + Self::Part(len, _) => *len, + Self::Symbol(_) => 1, + } + } +} -impl Example { - fn parser(_input: &str) -> IResult<&str, Self> { - todo!() +impl Part { + fn touches(&self, symbol: &Symbol) -> bool { + let part = self; + symbol.x >= part.min_x.saturating_sub(1) + && symbol.x <= part.max_x.saturating_add(1) + && symbol.y >= part.y.saturating_sub(1) + && symbol.y <= part.y.saturating_add(1) } } -- cgit v1.2.3