1
0
Fork 0
advent-of-code/2023/src/bin/03.rs

124 lines
3.9 KiB
Rust

advent_of_code::solution!(3);
use std::collections::BTreeMap;
type PartList = BTreeMap<(usize, usize, char), Vec<u32>>;
fn parse(input: &str) -> Vec<Vec<char>> {
input
.lines()
.filter_map(|line| {
if !line.is_empty() {
Some(line.chars().collect::<Vec<char>>())
} else {
None
}
})
.collect()
}
fn associate_parts(input: &str) -> PartList {
let parsed_input = parse(input);
let mut result: PartList = BTreeMap::new();
for (line_index, line) in parsed_input.iter().enumerate() {
let mut parse_end = 0;
for (index, c) in line.iter().enumerate() {
if index < parse_end {
continue;
}
if c.is_ascii_digit() {
let mut n: Vec<char> = vec![];
n.push(*c);
if index + 1 < line.len() && line[index + 1].is_ascii_digit() {
n.push(line[index + 1]);
if index + 2 < line.len() && line[index + 2].is_ascii_digit() {
n.push(line[index + 2]);
}
}
let part_num = n
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("")
.parse::<u32>()
.unwrap();
let mut adjacent: Vec<(usize, usize)> = vec![];
let mut left_side = index;
if index > 1 {
left_side -= 1;
}
let mut right_side = index + n.len() - 1;
if right_side < line.len() - 1 {
right_side += 1;
}
parse_end = right_side;
let mut top_side = line_index;
if top_side > 1 {
top_side -= 1;
}
let mut bottom_side = line_index;
if bottom_side + 1 <= parsed_input.len() - 1 {
bottom_side += 1;
}
adjacent.push((line_index, left_side));
adjacent.push((line_index, right_side));
for col in left_side..=right_side {
adjacent.push((top_side, col));
adjacent.push((bottom_side, col));
}
if let Some(part_coord) = adjacent.iter().find(|coord| {
!parsed_input[coord.0][coord.1].is_ascii_digit()
&& parsed_input[coord.0][coord.1] != '.'
}) {
let hash_key = (
part_coord.0,
part_coord.1,
parsed_input[part_coord.0][part_coord.1],
);
if !result.contains_key(&hash_key) {
result.insert(hash_key, vec![]);
}
let plist = result.get_mut(&hash_key).unwrap();
plist.push(part_num);
}
}
}
}
result
}
pub fn part_one(input: &str) -> Option<u32> {
let mut sum: u32 = 0;
for (_coord, plist) in associate_parts(input).iter() {
sum += plist.iter().sum::<u32>();
}
Some(sum)
}
pub fn part_two(input: &str) -> Option<u32> {
let mut sum: u32 = 0;
for (coord, plist) in associate_parts(input).iter() {
if coord.2 == '*' && plist.len() == 2 {
sum += plist.iter().product::<u32>();
}
}
Some(sum)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(4361));
}
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(467835));
}
}