diff --git a/samples/day03.txt b/samples/day03.txt new file mode 100644 index 0000000..b20187f --- /dev/null +++ b/samples/day03.txt @@ -0,0 +1,10 @@ +467..114.. +...*...... +..35..633. +......#... +617*...... +.....+.58. +..592..... +......755. +...$.*.... +.664.598.. diff --git a/src/bin/day03.rs b/src/bin/day03.rs new file mode 100644 index 0000000..e972612 --- /dev/null +++ b/src/bin/day03.rs @@ -0,0 +1,159 @@ +use std::{cmp, collections::HashMap}; + +use aoc_2023::*; + +type Output1 = i32; +type Output2 = Output1; + +struct Day03 { + lines: Vec, +} +impl Solution for Day03 { + fn new>(pathname: P) -> Self { + Self { + lines: file_to_lines(pathname), + } + } + + fn part_1(&mut self) -> Output1 { + let symbols = self + .lines + .iter() + .enumerate() + .flat_map(|(y, line)| { + line.chars().enumerate().filter_map(move |(x, c)| { + if c != '.' && !c.is_ascii_digit() { + Some(((y + 1, x + 1), c)) + } else { + None + } + }) + }) + .collect::>(); + let numbers = self + .lines + .iter() + .enumerate() + .flat_map(|(y, line)| { + let mut nums = vec![]; + + let mut start = line.len(); + let mut num = 0; + for (x, c) in line.chars().enumerate() { + if c.is_ascii_digit() { + start = cmp::min(start, x); + num = num * 10 + c.to_digit(10).unwrap() as i32; + } else { + nums.push((y + 1, start + 1, x + 1, num)); + + start = line.len(); + num = 0; + } + } + + if start != line.len() { + nums.push((y + 1, start + 1, line.len() + 1, num)); + } + + nums + }) + .collect_vec(); + + numbers + .iter() + .filter_map(|(y, start, x, num)| { + if symbols.contains_key(&(*y, start - 1)) + || symbols.contains_key(&(*y, *x)) + || (*start - 1..=*x).any(|xx| { + symbols.contains_key(&(y - 1, xx)) || symbols.contains_key(&(y + 1, xx)) + }) + { + Some(*num) + } else { + None + } + }) + .sum() + } + + fn part_2(&mut self) -> Output2 { + let symbols = self + .lines + .iter() + .enumerate() + .flat_map(|(y, line)| { + line.chars().enumerate().filter_map(move |(x, c)| { + if c == '*' { + Some(((y + 1, x + 1), c)) + } else { + None + } + }) + }) + .collect::>(); + + let mut symbol_counters: HashMap<(usize, usize), Vec> = HashMap::new(); + + let numbers = self + .lines + .iter() + .enumerate() + .flat_map(|(y, line)| { + let mut nums = vec![]; + + let mut start = line.len(); + let mut num = 0; + for (x, c) in line.chars().enumerate() { + if c.is_ascii_digit() { + start = cmp::min(start, x); + num = num * 10 + c.to_digit(10).unwrap() as i32; + } else if start != line.len() { + nums.push((y + 1, start + 1, x + 1, num)); + + start = line.len(); + num = 0; + } + } + + if start != line.len() { + nums.push((y + 1, start + 1, line.len() + 1, num)); + } + + nums + }) + .collect_vec(); + + numbers.iter().for_each(|(y, start, x, num)| { + let mut possible_gears = vec![(*y, start - 1), (*y, *x)]; + + (*start - 1..=*x).for_each(|xx: usize| { + possible_gears.push((y - 1, xx)); + possible_gears.push((y + 1, xx)); + }); + + for (y, x) in possible_gears { + if symbols.contains_key(&(y, x)) { + symbol_counters.entry((y, x)).or_default().push(*num); + break; + } + } + }); + + symbol_counters + .values() + .filter_map(|nums| { + if nums.len() == 2 { + Some(nums.iter().product1::().unwrap()) + } else { + None + } + }) + .sum() + } +} + +fn main() -> Result<()> { + Day03::main() +} + +test_sample!(day_03, Day03, 4361, 467835);