124 lines
3.9 KiB
Rust
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));
|
|
}
|
|
}
|