Day 18, part 2
This commit is contained in:
parent
ff8870eb3e
commit
813c9f0612
|
@ -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)
|
||||
);
|
||||
}
|
137
src/day18.rs
137
src/day18.rs
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue