Day 18, part 2

This commit is contained in:
jazzpi 2022-12-20 17:20:12 +01:00
parent ff8870eb3e
commit 813c9f0612
2 changed files with 137 additions and 10 deletions

10
src/bin/d18p2.rs Normal file
View File

@ -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)
);
}

View File

@ -1,6 +1,15 @@
use std::collections::HashSet;
use itertools::Itertools; use itertools::Itertools;
pub fn parse_droplet(input: &String) -> Vec<Vec<Vec<bool>>> { #[derive(Clone, Copy, Debug)]
pub enum Material {
Air,
Lava,
Steam,
}
pub fn parse_droplet(input: &String) -> Vec<Vec<Vec<Material>>> {
let mut cubes: Vec<(usize, usize, usize)> = Vec::new(); let mut cubes: Vec<(usize, usize, usize)> = Vec::new();
for line in input.lines() { for line in input.lines() {
@ -19,19 +28,19 @@ pub fn parse_droplet(input: &String) -> Vec<Vec<Vec<bool>>> {
let (x_min, x_max) = cubes.iter().map(|c| c.0).minmax().into_option().unwrap(); 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 (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 (z_min, z_max) = cubes.iter().map(|c| c.2).minmax().into_option().unwrap();
let x_len = x_max - x_min + 1; let x_len = x_max - x_min + 3;
let y_len = y_max - y_min + 1; let y_len = y_max - y_min + 3;
let z_len = z_max - z_min + 1; 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 { 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 result
} }
pub fn surface_area(droplet: &Vec<Vec<Vec<bool>>>) -> usize { pub fn surface_area(droplet: &Vec<Vec<Vec<Material>>>) -> usize {
let x_len = droplet.len(); let x_len = droplet.len();
assert!(x_len > 0); assert!(x_len > 0);
let y_len = droplet[0].len(); let y_len = droplet[0].len();
@ -100,7 +109,7 @@ enum ArgOrder {
} }
fn surface_area_dir( fn surface_area_dir(
droplet: &Vec<Vec<Vec<bool>>>, droplet: &Vec<Vec<Vec<Material>>>,
lines: &Vec<(usize, usize, Vec<usize>)>, lines: &Vec<(usize, usize, Vec<usize>)>,
order: ArgOrder, order: ArgOrder,
) -> usize { ) -> usize {
@ -113,11 +122,119 @@ fn surface_area_dir(
ArgOrder::XZY => droplet[*a][*c][*b], ArgOrder::XZY => droplet[*a][*c][*b],
ArgOrder::YZX => droplet[*c][*a][*b], ArgOrder::YZX => droplet[*c][*a][*b],
}; };
if last_empty && occupied { if last_empty && matches!(occupied, Material::Lava) {
result += 1; result += 1;
} }
last_empty = !occupied; last_empty = matches!(occupied, Material::Air);
} }
} }
result result
} }
pub fn outer_surface_area(droplet: &Vec<Vec<Vec<Material>>>) -> 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<dyn Fn(&Coord) -> Option<Coord>>; 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<Coord> {
if c.0 > 0 {
Some((c.0 - 1, c.1, c.2))
} else {
None
}
}
fn go_back(c: &Coord, x_len: usize) -> Option<Coord> {
if c.0 < x_len - 1 {
Some((c.0 + 1, c.1, c.2))
} else {
None
}
}
fn go_left(c: &Coord) -> Option<Coord> {
if c.1 > 0 {
Some((c.0, c.1 - 1, c.2))
} else {
None
}
}
fn go_right(c: &Coord, y_len: usize) -> Option<Coord> {
if c.1 < y_len - 1 {
Some((c.0, c.1 + 1, c.2))
} else {
None
}
}
fn go_up(c: &Coord) -> Option<Coord> {
if c.2 > 0 {
Some((c.0, c.1, c.2 - 1))
} else {
None
}
}
fn go_down(c: &Coord, z_len: usize) -> Option<Coord> {
if c.2 < z_len - 1 {
Some((c.0, c.1, c.2 + 1))
} else {
None
}
}