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;
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();
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 (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<Vec<Vec<bool>>>) -> usize {
pub fn surface_area(droplet: &Vec<Vec<Vec<Material>>>) -> 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<Vec<Vec<bool>>>,
droplet: &Vec<Vec<Vec<Material>>>,
lines: &Vec<(usize, usize, Vec<usize>)>,
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<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
}
}