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>>>; fn parse_input(input: &str) -> IResult<&str, Vec> { 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); }