From 813c9f06128d68fdaf6afe9a13e1e4ac890d4b97 Mon Sep 17 00:00:00 2001 From: jazzpi Date: Tue, 20 Dec 2022 17:20:12 +0100 Subject: [PATCH] Day 18, part 2 --- src/bin/d18p2.rs | 10 ++++ src/day18.rs | 137 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 src/bin/d18p2.rs diff --git a/src/bin/d18p2.rs b/src/bin/d18p2.rs new file mode 100644 index 0000000..67cef0f --- /dev/null +++ b/src/bin/d18p2.rs @@ -0,0 +1,10 @@ +use aoc22::{day18, util}; + +pub fn main() { + let droplet = day18::parse_droplet(&util::parse_input()); + + println!( + "Outer surface area: {}", + day18::outer_surface_area(&droplet) + ); +} diff --git a/src/day18.rs b/src/day18.rs index 75bcd90..720733c 100644 --- a/src/day18.rs +++ b/src/day18.rs @@ -1,6 +1,15 @@ +use std::collections::HashSet; + use itertools::Itertools; -pub fn parse_droplet(input: &String) -> Vec>> { +#[derive(Clone, Copy, Debug)] +pub enum Material { + Air, + Lava, + Steam, +} + +pub fn parse_droplet(input: &String) -> Vec>> { let mut cubes: Vec<(usize, usize, usize)> = Vec::new(); for line in input.lines() { @@ -19,19 +28,19 @@ pub fn parse_droplet(input: &String) -> Vec>> { let (x_min, x_max) = cubes.iter().map(|c| c.0).minmax().into_option().unwrap(); let (y_min, y_max) = cubes.iter().map(|c| c.1).minmax().into_option().unwrap(); let (z_min, z_max) = cubes.iter().map(|c| c.2).minmax().into_option().unwrap(); - let x_len = x_max - x_min + 1; - let y_len = y_max - y_min + 1; - let z_len = z_max - z_min + 1; + let x_len = x_max - x_min + 3; + let y_len = y_max - y_min + 3; + let z_len = z_max - z_min + 3; - let mut result = vec![vec![vec![false; z_len]; y_len]; x_len]; + let mut result = vec![vec![vec![Material::Air; z_len]; y_len]; x_len]; for (x, y, z) in cubes { - result[x - x_min][y - y_min][z - z_min] = true; + result[x - x_min + 1][y - y_min + 1][z - z_min + 1] = Material::Lava; } result } -pub fn surface_area(droplet: &Vec>>) -> usize { +pub fn surface_area(droplet: &Vec>>) -> usize { let x_len = droplet.len(); assert!(x_len > 0); let y_len = droplet[0].len(); @@ -100,7 +109,7 @@ enum ArgOrder { } fn surface_area_dir( - droplet: &Vec>>, + droplet: &Vec>>, lines: &Vec<(usize, usize, Vec)>, order: ArgOrder, ) -> usize { @@ -113,11 +122,119 @@ fn surface_area_dir( ArgOrder::XZY => droplet[*a][*c][*b], ArgOrder::YZX => droplet[*c][*a][*b], }; - if last_empty && occupied { + if last_empty && matches!(occupied, Material::Lava) { result += 1; } - last_empty = !occupied; + last_empty = matches!(occupied, Material::Air); } } result } + +pub fn outer_surface_area(droplet: &Vec>>) -> usize { + let x_len = droplet.len(); + assert!(x_len > 0); + let y_len = droplet[0].len(); + assert!(y_len > 0); + let z_len = droplet[0][0].len(); + assert!(z_len > 0); + + let mut next = Vec::new(); + + // top/bottom + for x in 0..x_len { + for y in 0..y_len { + next.push((x, y, 0)); + next.push((x, y, z_len - 1)); + } + } + // left/right + for x in 0..x_len { + for z in 0..z_len { + next.push((x, 0, z)); + next.push((x, y_len - 1, z)); + } + } + // fore/back + for y in 0..y_len { + for z in 0..z_len { + next.push((0, y, z)); + next.push((x_len - 1, y, z)); + } + } + + let mut visited: HashSet<_> = next.iter().map(|c| c.clone()).collect(); + let generators: [Box Option>; 6] = [ + Box::new(|c| go_fore(c)), + Box::new(|c| go_back(c, x_len)), + Box::new(|c| go_left(c)), + Box::new(|c| go_right(c, y_len)), + Box::new(|c| go_up(c)), + Box::new(|c| go_down(c, z_len)), + ]; + + let mut result = 0; + while let Some(n) = next.pop().clone() { + for gen in &generators { + if let Some(c) = gen(&n) { + let occupied = droplet[c.0][c.1][c.2]; + if matches!(occupied, Material::Air) && visited.insert(c) { + next.push(c); + } else if matches!(occupied, Material::Lava) { + result += 1; + } + } + } + } + result +} + +type Coord = (usize, usize, usize); + +fn go_fore(c: &Coord) -> Option { + if c.0 > 0 { + Some((c.0 - 1, c.1, c.2)) + } else { + None + } +} + +fn go_back(c: &Coord, x_len: usize) -> Option { + if c.0 < x_len - 1 { + Some((c.0 + 1, c.1, c.2)) + } else { + None + } +} + +fn go_left(c: &Coord) -> Option { + if c.1 > 0 { + Some((c.0, c.1 - 1, c.2)) + } else { + None + } +} + +fn go_right(c: &Coord, y_len: usize) -> Option { + if c.1 < y_len - 1 { + Some((c.0, c.1 + 1, c.2)) + } else { + None + } +} + +fn go_up(c: &Coord) -> Option { + if c.2 > 0 { + Some((c.0, c.1, c.2 - 1)) + } else { + None + } +} + +fn go_down(c: &Coord, z_len: usize) -> Option { + if c.2 < z_len - 1 { + Some((c.0, c.1, c.2 + 1)) + } else { + None + } +}