125 lines
3.2 KiB
Rust
125 lines
3.2 KiB
Rust
use std::cmp::max;
|
|
use std::fmt::{Display, Formatter, Result};
|
|
use std::vec;
|
|
|
|
use nom::{
|
|
bytes::streaming::tag,
|
|
character::complete::{self, multispace1},
|
|
multi::separated_list1,
|
|
sequence::{terminated, tuple},
|
|
IResult, Parser,
|
|
};
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
struct Coord {
|
|
x: u32,
|
|
y: u32,
|
|
z: u32,
|
|
}
|
|
|
|
impl Display for Coord {
|
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
|
write!(f, "{},{},{}", self.x, self.y, self.z)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
struct LavaBlob {
|
|
coord: Coord,
|
|
number_of_neighbours: u32,
|
|
}
|
|
|
|
type LavaGrid = Vec<Vec<Vec<Option<LavaBlob>>>>;
|
|
|
|
fn parse_input(input: &str) -> IResult<&str, Vec<Coord>> {
|
|
let (input, coords) = separated_list1(
|
|
multispace1,
|
|
tuple((
|
|
terminated(complete::u32, tag(",")),
|
|
terminated(complete::u32, tag(",")),
|
|
complete::u32,
|
|
))
|
|
.map(|(x, y, z)| Coord { x, y, z }),
|
|
)(input)?;
|
|
|
|
Ok((input, coords))
|
|
}
|
|
|
|
fn main() {
|
|
let input_text = include_str!("../test.txt");
|
|
let (_rest, coordinates) = parse_input(input_text).unwrap();
|
|
|
|
// Test the parsing
|
|
println!("Testing the parsing");
|
|
for coord in &coordinates {
|
|
println!("{}", coord);
|
|
}
|
|
println!();
|
|
|
|
let max_grid_value = coordinates
|
|
.iter()
|
|
.map(|&coord| max(max(coord.x, coord.y), coord.z))
|
|
.max()
|
|
.unwrap() as usize;
|
|
let mut lava_grid: LavaGrid =
|
|
vec![vec![vec![None; max_grid_value + 1]; max_grid_value + 1]; max_grid_value + 1];
|
|
|
|
for coord in &coordinates {
|
|
let mut number_of_neighbours = 6;
|
|
let x = coord.x;
|
|
let y = coord.y;
|
|
let z = coord.z;
|
|
|
|
let mut coords_to_check = vec![];
|
|
if x > 0 {
|
|
coords_to_check.push(Coord { x: x - 1, y, z });
|
|
}
|
|
if x < max_grid_value as u32 {
|
|
coords_to_check.push(Coord { x: x + 1, y, z });
|
|
}
|
|
if y > 0 {
|
|
coords_to_check.push(Coord { x, y: y - 1, z });
|
|
}
|
|
if y < max_grid_value as u32 {
|
|
coords_to_check.push(Coord { x, y: y + 1, z });
|
|
}
|
|
if z > 0 {
|
|
coords_to_check.push(Coord { x, y, z: z - 1 })
|
|
}
|
|
if z < max_grid_value as u32 {
|
|
coords_to_check.push(Coord { x, y, z: z + 1 });
|
|
}
|
|
|
|
for coord_to_check in &coords_to_check {
|
|
match lava_grid[coord_to_check.x as usize][coord_to_check.y as usize]
|
|
[coord_to_check.z as usize]
|
|
{
|
|
None => continue,
|
|
Some(mut blob) => {
|
|
number_of_neighbours -= 1;
|
|
blob.number_of_neighbours -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
lava_grid[x as usize][y as usize][z as usize] = Some(LavaBlob {
|
|
coord: coord.clone(),
|
|
number_of_neighbours,
|
|
})
|
|
}
|
|
|
|
let mut surface_area = 0;
|
|
for layer in &lava_grid {
|
|
for row in layer {
|
|
for optional_blob in row {
|
|
match optional_blob {
|
|
None => continue,
|
|
Some(blob) => surface_area += blob.number_of_neighbours,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
println!("Surface area: {}", surface_area);
|
|
}
|