diff --git a/day3/src/part1.rs b/day3/src/part1.rs index c78b131..a752836 100644 --- a/day3/src/part1.rs +++ b/day3/src/part1.rs @@ -1,55 +1,110 @@ -use regex::Regex; +use regex::{Match, Regex}; +use std::{fmt::Display, num::ParseIntError}; -pub fn main(input: &str) -> i32 { - todo!(); +#[derive(Debug)] +struct Symbol { + value: char, + row: usize, + col: usize, +} + +impl Display for Symbol { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: ({},{})", self.value, self.row + 1, self.col + 1) + } } #[derive(Debug)] -enum Engine { - Number { - value: u32, - line: usize, - start: usize, - end: usize, - }, - Symbol { - value: char, - line: usize, - pos: usize, - }, +struct Number { + value: u32, + row: usize, + start: usize, + end: usize, } -fn get_numbers(index: usize, line: &str) -> Vec { - Regex::new(r"\d+") - .unwrap() - .find_iter(line) - .filter_map(|m| match m.as_str().parse() { - Ok(value) => Some(Engine::Number { - value, - line: index, - start: m.start(), - end: m.end(), - }), - _ => None, +impl Display for Number { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{0}: ({1},{2}) -> ({1},{3})", + self.value, + self.row + 1, + self.start + 1, + self.end + 1, + ) + } +} + +impl Number { + fn valid(&self, symbols: &[Symbol]) -> bool { + let adjacent: Vec = symbols + .iter() + .filter_map(|m| { + let start = if self.row > 1 { self.row - 1 } else { 1 }; + let end = self.row + 1; + if (start..=end).contains(&m.row) { + Some(m.col) + } else { + None + } + }) + .collect(); + let start = if self.start > 1 { self.start - 1 } else { 1 }; + let end = self.end + 1; + (start..=end).any(|m| adjacent.contains(&m)) + } +} + +impl TryFrom> for Number { + type Error = ParseIntError; + + fn try_from(value: Match) -> Result { + Ok(Self { + value: value.as_str().parse()?, + row: 0, + start: value.start(), + end: value.end(), }) - .collect() + } } -fn get_symbols(index: usize, line: &str) -> Vec { - line.chars() - .enumerate() - .filter_map(|(j, m)| { - if !m.is_ascii_digit() && m != '.' { - Some(Engine::Symbol { - value: m, - line: index, - pos: j, - }) +fn get_symbols(input: &str) -> Vec { + let mut items: Vec = Vec::new(); + for (row, line) in input.lines().enumerate() { + for (col, value) in line.chars().enumerate() { + if !value.is_ascii_digit() && value != '.' { + items.push(Symbol { value, row, col }) + } + } + } + items +} + +fn get_numbers(input: &str) -> Vec { + let rstring = r"(\d)+"; + let mut items: Vec = Vec::new(); + for (row, line) in input.lines().enumerate() { + for item in Regex::new(rstring).unwrap().find_iter(line) { + let mut number = Number::try_from(item).unwrap(); + number.row = row; + items.push(number); + } + } + items +} + +pub fn main(input: &str) -> u32 { + let symbols = get_symbols(input); + get_numbers(input) + .iter() + .filter_map(|m| { + if m.valid(&symbols) { + Some(m.value) } else { None } }) - .collect() + .sum() } #[cfg(test)]