104 lines
2.9 KiB
Rust
104 lines
2.9 KiB
Rust
#![feature(test, try_blocks)]
|
|
extern crate test;
|
|
|
|
use aoc2023::{
|
|
boilerplate,
|
|
common::*,
|
|
position::{Position2D, PositionND},
|
|
};
|
|
use itertools::Itertools;
|
|
|
|
const DAY: usize = 3;
|
|
type I = i32;
|
|
type Grid<'a> = Vec<&'a [u8]>;
|
|
type Region = (usize, (usize, usize));
|
|
type Parsed<'a> = (Grid<'a>, Vec<Vec<Region>>);
|
|
|
|
fn parse_input(raw: &str) -> Parsed {
|
|
let grid = raw.lines().map(|l| l.as_bytes()).collect_vec();
|
|
let number_positions = grid
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(x, l)| {
|
|
l.iter()
|
|
.enumerate()
|
|
.filter_map(move |(y, c)| c.is_ascii_digit().then_some((x, (y, y))))
|
|
.coalesce(
|
|
|(x1, (y11, y12)), (x2, (y21, y22))| {
|
|
if y12 + 1 == y21 {
|
|
Ok((x1, (y11, y22)))
|
|
} else {
|
|
Err(((x1, (y11, y12)), (x2, (y21, y22))))
|
|
}
|
|
},
|
|
)
|
|
.collect()
|
|
})
|
|
.collect();
|
|
(grid, number_positions)
|
|
}
|
|
|
|
fn parse_at(grid: &Grid, (x, (y1, y2)): Region) -> usize {
|
|
String::from_utf8_lossy(&grid[x][y1..=y2]).parse().unwrap()
|
|
}
|
|
|
|
fn part1((grid, number_positions): &Parsed) -> usize {
|
|
number_positions
|
|
.iter()
|
|
.flatten()
|
|
.cloned()
|
|
.filter_map(|(x, (y1, y2))| {
|
|
let start = PositionND([x as I, y1 as I]);
|
|
let end = PositionND([x as I, y2 as I]);
|
|
start
|
|
.neighbors()
|
|
.into_iter()
|
|
.chain(end.neighbors())
|
|
.any(|PositionND([x, y])| {
|
|
!matches!(grid.get(x as usize).and_then(|ys| ys.get(y as usize)), Some(b'0'..=b'9' | b'.') | None)
|
|
})
|
|
.then(|| parse_at(grid, (x, (y1, y2))))
|
|
})
|
|
.sum()
|
|
}
|
|
|
|
fn part_of(PositionND([_, y]): Position2D<I>, (_, (y1, y2)): &Region) -> bool {
|
|
(y1..=y2).contains(&&(y as usize))
|
|
}
|
|
|
|
fn part2((grid, number_positions): &Parsed) -> usize {
|
|
grid.iter()
|
|
.enumerate()
|
|
.flat_map(|(x, ys)| ys.iter().enumerate().filter_map(move |(y, &b)| (b == b'*').then_some(PositionND([x as I, y as I]))))
|
|
.filter_map(|p| {
|
|
let neighbors = p.neighbors();
|
|
number_positions[(p.0[0].dec() as usize)..=(p.0[0].inc() as usize)]
|
|
.iter()
|
|
.flatten()
|
|
.filter_map(|&np| neighbors.iter().find_map(|&n| part_of(n, &np).then(|| parse_at(grid, np))))
|
|
.collect_tuple()
|
|
})
|
|
.map(|(a, b)| a * b)
|
|
.sum()
|
|
}
|
|
|
|
boilerplate! {
|
|
TEST_INPUT == "467..114..
|
|
...*......
|
|
..35..633.
|
|
......#...
|
|
617*......
|
|
.....+.58.
|
|
..592.....
|
|
......755.
|
|
...$.*....
|
|
.664.598.."
|
|
for tests: {
|
|
part1: { TEST_INPUT => 4361 },
|
|
part2: { TEST_INPUT => 467835 },
|
|
},
|
|
bench1 == 536202,
|
|
bench2 == 78272573,
|
|
bench_parse: |(g, ns): &Parsed| (g.len(), ns.len()) => (140, 140),
|
|
}
|