109 lines
2.6 KiB
Rust
109 lines
2.6 KiB
Rust
//! Day 3: Gear Ratios
|
|
|
|
use std::collections::{HashMap, HashSet};
|
|
|
|
use itertools::Itertools;
|
|
use once_cell::sync::Lazy;
|
|
use regex::Regex;
|
|
|
|
use crate::util::grid::{NeighborsCfg, Pos};
|
|
|
|
pub const DAY: u8 = 3;
|
|
pub const TITLE: &str = "Gear Ratios";
|
|
|
|
const NCFG: NeighborsCfg = NeighborsCfg {
|
|
diag: true,
|
|
tl: Some(Pos::usize(0, 0)),
|
|
br: None,
|
|
};
|
|
static NUMBERS: Lazy<Regex> = Lazy::new(|| Regex::new(r"\d+").unwrap());
|
|
|
|
pub fn part1(input: Vec<String>) -> String {
|
|
let mut symbol_neighbors = HashSet::new();
|
|
|
|
for (y, line) in input.iter().enumerate() {
|
|
for (x, c) in line.chars().enumerate() {
|
|
if c != '.' && c.is_ascii_punctuation() {
|
|
let p = Pos::usize(x, y);
|
|
p.neighbors(&NCFG).for_each(|p| {
|
|
symbol_neighbors.insert(p);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut sum = 0;
|
|
for (y, line) in input.iter().enumerate() {
|
|
for m in NUMBERS.captures_iter(line) {
|
|
let m = m.get(0).unwrap();
|
|
for x in m.range() {
|
|
let p = Pos::usize(x, y);
|
|
if symbol_neighbors.contains(&p) {
|
|
sum += m.as_str().parse::<u64>().unwrap();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sum.to_string()
|
|
}
|
|
|
|
pub fn part2(input: Vec<String>) -> String {
|
|
let mut numbers = HashMap::new();
|
|
|
|
for (y, line) in input.iter().enumerate() {
|
|
for m in NUMBERS.captures_iter(line) {
|
|
let m = m.get(0).unwrap();
|
|
let n = m.as_str().parse::<u64>().unwrap();
|
|
for x in m.range() {
|
|
let p = Pos::usize(x, y);
|
|
numbers.insert(p, n);
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut gears = 0;
|
|
for (y, line) in input.iter().enumerate() {
|
|
for (x, c) in line.chars().enumerate() {
|
|
if c == '*' {
|
|
let p = Pos::usize(x, y);
|
|
let nx = p
|
|
.neighbors(&NCFG)
|
|
.filter_map(|p| numbers.get(&p))
|
|
.dedup()
|
|
.collect_vec();
|
|
if nx.len() == 2 {
|
|
gears += nx[0] * nx[1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gears.to_string()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn t_example1() {
|
|
assert_eq!(part1(crate::read_example(DAY, 1)), "4361");
|
|
}
|
|
|
|
#[test]
|
|
fn t_part1() {
|
|
assert_eq!(part1(crate::read_input(DAY)), "520135");
|
|
}
|
|
|
|
#[test]
|
|
fn t_example2() {
|
|
assert_eq!(part2(crate::read_example(DAY, 2)), "467835");
|
|
}
|
|
|
|
#[test]
|
|
fn t_part2() {
|
|
assert_eq!(part2(crate::read_input(DAY)), "72514855");
|
|
}
|
|
}
|