d16-None; d17-P1; d18-P1&P2
This commit is contained in:
144
d18/src/a2.rs
144
d18/src/a2.rs
@ -1,5 +1,149 @@
|
||||
use std::{collections::{HashSet, VecDeque, vec_deque}, hash::Hash, thread};
|
||||
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Copy, Clone)]
|
||||
struct Pos {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
|
||||
impl Pos {
|
||||
fn from(x :i32, y :i32, z :i32) -> Self {
|
||||
Pos { x: x, y: y, z: z }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn find_zmax(positions :&HashSet<Pos>) -> Pos {
|
||||
let mut max = Pos::from(0, 0, i32::MIN);
|
||||
positions.iter().for_each(|pos| {if pos.z > max.z { max = *pos; }});
|
||||
max
|
||||
}
|
||||
|
||||
fn find_zmin(positions :&HashSet<Pos>) -> Pos {
|
||||
let mut max = Pos::from(0, 0, i32::MAX);
|
||||
positions.iter().for_each(|pos| {if pos.z < max.z { max = *pos; }});
|
||||
max
|
||||
}
|
||||
|
||||
fn find_ymax(positions :&HashSet<Pos>) -> Pos {
|
||||
let mut max = Pos::from(0, i32::MIN, 0);
|
||||
positions.iter().for_each(|pos| {if pos.y > max.y { max = *pos; }});
|
||||
max
|
||||
}
|
||||
|
||||
fn find_ymin(positions :&HashSet<Pos>) -> Pos {
|
||||
let mut max = Pos::from(0, i32::MAX, 0);
|
||||
positions.iter().for_each(|pos| {if pos.y < max.y { max = *pos; }});
|
||||
max
|
||||
}
|
||||
|
||||
fn find_xmax(positions :&HashSet<Pos>) -> Pos {
|
||||
let mut max = Pos::from(i32::MIN, 0, 0);
|
||||
positions.iter().for_each(|pos| {if pos.x > max.x { max = *pos; }});
|
||||
max
|
||||
}
|
||||
|
||||
fn find_xmin(positions :&HashSet<Pos>) -> Pos {
|
||||
let mut max = Pos::from(i32::MAX, 0, 0);
|
||||
positions.iter().for_each(|pos| {if pos.x < max.x { max = *pos; }});
|
||||
max
|
||||
}
|
||||
|
||||
fn flood_fill(start :Pos, map :&mut HashSet<Pos>, lava :&HashSet<Pos>, min :&Pos, max :&Pos) {
|
||||
|
||||
let mut queue :VecDeque<Pos> = VecDeque::new();
|
||||
queue.push_back(start);
|
||||
|
||||
while !queue.is_empty() {
|
||||
|
||||
let cp = queue.pop_front().unwrap();
|
||||
|
||||
if !(cp.x > min.x && cp.x < max.x && cp.y > min.y && cp.y < max.y && cp.z > min.z && cp.z < max.z) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if map.contains(&cp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if lava.contains(&cp) {
|
||||
continue;
|
||||
}
|
||||
|
||||
map.insert(cp);
|
||||
|
||||
queue.push_back(Pos::from(cp.x - 1, cp.y, cp.z));
|
||||
queue.push_back(Pos::from(cp.x + 1, cp.y, cp.z));
|
||||
queue.push_back(Pos::from(cp.x, cp.y - 1, cp.z));
|
||||
queue.push_back(Pos::from(cp.x, cp.y + 1, cp.z));
|
||||
queue.push_back(Pos::from(cp.x, cp.y, cp.z - 1));
|
||||
queue.push_back(Pos::from(cp.x, cp.y, cp.z + 1));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(inp :Vec<String>) {
|
||||
|
||||
// parse input
|
||||
let tmp :Vec<Vec<i32>> = inp.iter().map(|elem| elem.split(',').map(|num| num.parse::<i32>().unwrap()).collect()).collect();
|
||||
let droplets :HashSet<Pos> = tmp.iter().map(|drop| Pos::from(drop[0], drop[1], drop[2])).collect();
|
||||
|
||||
// highest, lowest, leftmost, rightmost, furthest and nearest droplet
|
||||
// construct a box around the lava at each sides maximum + 2
|
||||
// floodfill from a starting pooint (for example higest_point+1)
|
||||
// go through all filled pixels and check all 6 sides if there is a pixel
|
||||
|
||||
// find edges (treat them as WALL)
|
||||
let z_max = find_zmax(&droplets);
|
||||
let z_min = find_zmin(&droplets);
|
||||
let y_max = find_ymax(&droplets);
|
||||
let y_min = find_ymin(&droplets);
|
||||
let x_max = find_xmax(&droplets);
|
||||
let x_min = find_xmin(&droplets);
|
||||
|
||||
let min_edges = Pos::from(x_min.x - 3, y_min.y - 3, z_min.z - 3);
|
||||
let max_edges = Pos::from(x_max.x + 3, y_max.y + 3, z_max.z + 3);
|
||||
|
||||
let mut filled :HashSet<Pos> = HashSet::new();
|
||||
|
||||
// FloodFill the rest in a new HashSet
|
||||
flood_fill(Pos::from(z_max.x, z_max.y, z_max.z+1), &mut filled, &droplets, &min_edges, &max_edges);
|
||||
|
||||
// check all sides of all flooded pixels. If a side has a LAVA pixel next to it count +1
|
||||
let mut side_counter = 0;
|
||||
|
||||
for dp in &filled {
|
||||
|
||||
// check each side if it is free
|
||||
// if it is free then count up by 1
|
||||
// else dont
|
||||
|
||||
let sides :Vec<Pos> = vec![
|
||||
|
||||
Pos::from(dp.x-1, dp.y, dp.z),
|
||||
Pos::from(dp.x+1, dp.y, dp.z),
|
||||
|
||||
Pos::from(dp.x, dp.y-1, dp.z),
|
||||
Pos::from(dp.x, dp.y+1, dp.z),
|
||||
|
||||
Pos::from(dp.x, dp.y, dp.z-1),
|
||||
Pos::from(dp.x, dp.y, dp.z+1),
|
||||
|
||||
];
|
||||
|
||||
|
||||
for side in sides {
|
||||
if droplets.contains(&side) {
|
||||
side_counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
println!("a2: {}", side_counter);
|
||||
|
||||
}
|
Reference in New Issue
Block a user