diff --git a/src/day22.rs b/src/day22.rs new file mode 100644 index 0000000..6eb2f4d --- /dev/null +++ b/src/day22.rs @@ -0,0 +1,133 @@ +use std::collections::VecDeque; + +use aoc_runner_derive::{aoc, aoc_generator}; +use regex::Regex; + +pub struct Brick { + up: Vec>, + down: Vec>, +} + + +#[aoc_generator(day22)] +fn parse(input: &str) -> Brick { + let re: Regex = Regex::new(r"\d+").unwrap(); + + let mut bricks: Vec<[usize; 6]> = input.lines().map(|line| { + re.captures_iter(line) + .map(|c| c.extract::<0>().0.parse::().unwrap()) + .collect::>().try_into().unwrap() + }).collect::>(); + + let mut heights = [[0; 10]; 10]; + let mut indices = [[usize::MAX; 10]; 10]; + let mut up = vec![Vec::new(); bricks.len()]; + let mut down = vec![Vec::new(); bricks.len()]; + + bricks.sort_unstable_by_key(|b| b[2]); + + for (i, &[x1, y1, z1, x2, y2, z2]) in bricks.iter().enumerate() { + let height = z2 - z1 + 1; + let mut top = 0; + let mut previous = usize::MAX; + + for x in x1..=x2 { + for y in y1..=y2 { + top = top.max(heights[x][y]); + } + } + + for x in x1..=x2 { + for y in y1..=y2 { + if heights[x][y] == top { + let index = indices[x][y]; + if index != previous { + up[index].push(i); + down[i].push(index); + previous = index; + } + } + + heights[x][y] = top + height; + indices[x][y] = i; + } + } + } + + Brick { up , down } +} + +#[aoc(day22, part1)] +fn part1(input: &Brick) -> usize { + let Brick { down, .. } = input; + let mut safe = vec![true; down.len()]; + + for underneath in down { + if underneath.len() == 1 { + safe[underneath[0]] = false; + } + } + + safe.iter().filter(|&&b| b).count() +} + +#[aoc(day22, part2)] +fn part2(input: &Brick) -> usize { + let Brick { up, down } = input; + let mut safe = vec![true; down.len()]; + + for underneath in down { + if underneath.len() == 1 { + safe[underneath[0]] = false; + } + } + + let mut result = 0; + let mut todo = VecDeque::new(); + let mut removed = vec![usize::MAX; down.len()]; + + for (start, &safe) in safe.iter().enumerate() { + if safe { + continue; + } + + todo.push_back(start); + removed[start] = start; + + while let Some(current) = todo.pop_front() { + for &next in &up[current] { + if removed[next] != start && down[next].iter().all(|&i| removed[i] == start) { + result += 1; + removed[next] = start; + todo.push_back(next); + } + } + } + } + + result +} + + +#[cfg(test)] +mod tests { + use super::*; + +const EX: &str = r"1,0,1~1,2,1 +0,0,2~2,0,2 +0,2,3~2,2,3 +0,0,4~0,2,4 +2,0,5~2,2,5 +0,1,6~2,1,6 +1,1,8~1,1,9"; + + #[test] + fn part1_example() { + assert_eq!(part1(&parse(EX)), 5); + } + + #[test] + fn part2_example() { + assert_eq!(part2(&parse(EX)), 7); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 14025a9..68470b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod day22; mod day21; mod day20; mod day19;