aoc23/src/bin/day3.rs
2023-12-03 17:00:03 +01:00

86 lines
1.7 KiB
Rust

#![forbid(elided_lifetimes_in_paths, unsafe_code)]
use aoc23::read;
use chumsky::{prelude::*, text::int};
use std::collections::HashMap;
enum Entity {
Void,
Symbol(char),
Number { num: usize, len: usize }
}
impl Entity {
fn len(&self) -> usize {
match self {
Self::Void | Self::Symbol(_) => 1,
Self::Number { len, .. } => *len
}
}
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
choice((
just('.').map(|_| Self::Void),
int(10).map(|num: String| Self::Number {
num: num.parse().unwrap(),
len: num.len()
}),
none_of(['\n']).map(Self::Symbol)
))
}
}
struct Line {
entities: HashMap<usize, Entity>
}
impl Line {
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
Entity::parser().repeated().map(|line| {
let mut col = 0;
let mut entities = HashMap::new();
for ent in line {
let len = ent.len();
entities.insert(col, ent);
col += len;
}
Line { entities }
})
}
}
fn parser() -> impl Parser<char, Vec<Line>, Error = Simple<char>> {
Line::parser()
.then_ignore(just("\n"))
.repeated()
.then_ignore(end())
}
fn main() -> anyhow::Result<()> {
let grid = read("inputs/day3.txt", parser())?;
let mut sum = 0;
for (i, line) in grid.iter().enumerate() {
'entities: for (col, ent) in &line.entities {
let Entity::Number { num, len } = ent else {
continue;
};
// see if adjacent
for search_row in i.saturating_sub(1) ..= i + 1 {
let Some(row) = grid.get(search_row) else {
continue;
};
for search_col in col.saturating_sub(1) ..= col + len {
if let Some(Entity::Symbol(_)) = row.entities.get(&search_col) {
sum += num;
continue 'entities;
}
}
}
}
}
println!("{sum}");
Ok(())
}