diff --git a/22/src/main.rs b/22/src/main.rs index cdd6156..cde4a58 100644 --- a/22/src/main.rs +++ b/22/src/main.rs @@ -68,16 +68,6 @@ impl std::fmt::Debug for BrickBlock { } impl BrickBlock { - fn map_into(&self, mut map: BlockMap) -> BlockMap { - // loop over the (inclusive) bounding coordinates and add them all to the map - map.slice_mut(s![ - std::cmp::min(self.c1.x, self.c2.x)..std::cmp::max(self.c1.x, self.c2.x) + 1, - std::cmp::min(self.c1.y, self.c2.y)..std::cmp::max(self.c1.y, self.c2.y) + 1, - std::cmp::min(self.c1.z, self.c2.z)..std::cmp::max(self.c1.z, self.c2.z) + 1 - ]) - .fill(Some(self.to_owned())); - map - } fn bottom_z_plane(&self) -> usize { std::cmp::min(self.c1.z, self.c2.z) } @@ -136,9 +126,9 @@ impl BlockPile { // loop over the (inclusive) bounding coordinates and remove them all from the map self.block_map .slice_mut(s![ - std::cmp::min(block.c1.x, block.c2.x)..std::cmp::max(block.c1.x, block.c2.x) + 1, - std::cmp::min(block.c1.y, block.c2.y)..std::cmp::max(block.c1.y, block.c2.y) + 1, - std::cmp::min(block.c1.z, block.c2.z)..std::cmp::max(block.c1.z, block.c2.z) + 1 + block.bottom_x_plane()..block.top_x_plane() + 1, + block.bottom_y_plane()..block.top_y_plane() + 1, + block.bottom_z_plane()..block.top_z_plane() + 1, ]) .fill(None); self.blocks.remove(self.blocks.iter().position(|b| b == block).unwrap()); @@ -147,9 +137,9 @@ impl BlockPile { // loop over the (inclusive) bounding coordinates and remove them all from the map self.block_map .slice_mut(s![ - std::cmp::min(block.c1.x, block.c2.x)..std::cmp::max(block.c1.x, block.c2.x) + 1, - std::cmp::min(block.c1.y, block.c2.y)..std::cmp::max(block.c1.y, block.c2.y) + 1, - std::cmp::min(block.c1.z, block.c2.z)..std::cmp::max(block.c1.z, block.c2.z) + 1 + block.bottom_x_plane()..block.top_x_plane() + 1, + block.bottom_y_plane()..block.top_y_plane() + 1, + block.bottom_z_plane()..block.top_z_plane() + 1, ]) .fill(Some(block.to_owned())); self.blocks.push(block.clone()); @@ -195,11 +185,11 @@ impl BlockPile { block.bottom_y_plane()..block.top_y_plane() + 1, 1..z_plane // don't include our own plane ]); - // find the highest z value + // find the highest top z value of those let block_below = directly_below .indexed_iter() .filter_map(|(idx, v)| if let Some(val) = v { Some((idx, val)) } else { None }) - .max_by(|(_, a), (_, b)| a.top_z_plane().cmp(&b.top_z_plane())); + .max_by_key(|(_idx, v)| v.top_z_plane()); if let Some(block) = block_below { Some(block.1.top_z_plane()) @@ -247,24 +237,22 @@ impl BlockPile { impl From> for BlockPile { fn from(lines: Lines) -> Self { - let mut new: BlockPile = Self { - blocks: lines.map(|line| BrickBlock::from(line.unwrap().as_str())).collect(), - block_map: Array3::from_elem([0, 0, 0], None), - bounds: (0, 0, 0), + let blocks = lines.map(|line| BrickBlock::from(line.unwrap().as_str())).collect_vec(); + let mut bounds = (0, 0, 0); + for block in &blocks { + bounds.0 = std::cmp::max(block.top_x_plane() + 1, bounds.0); + bounds.1 = std::cmp::max(block.top_y_plane() + 1, bounds.1); + bounds.2 = std::cmp::max(block.top_z_plane() + 1, bounds.2); + } + let mut new = BlockPile { + blocks: Vec::new(), + bounds, + block_map: BlockMap::from_elem(bounds, None), graph: Graph::default(), }; - - for block in &new.blocks { - new.bounds.0 = std::cmp::max(block.c1.x + 1, std::cmp::max(block.c2.y + 1, new.bounds.0)); - new.bounds.1 = std::cmp::max(block.c1.y + 1, std::cmp::max(block.c2.y + 1, new.bounds.1)); - new.bounds.2 = std::cmp::max(block.c1.z + 1, std::cmp::max(block.c2.z + 1, new.bounds.2)); + for block in blocks { + new.add_block(&block); } - let mut block_map = BlockMap::from_elem(new.bounds, None); - - for block in &new.blocks { - block_map = block.map_into(block_map); - } - new.block_map = block_map; new } @@ -272,30 +260,36 @@ impl From> for BlockPile { impl Display for BlockPile { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // XZ view - writeln!(f, "XZ: [{}, {}]", self.bounds.0, self.bounds.2)?; for z in (0..self.bounds.2).rev() { - for x in 0..self.bounds.0 { - let y = self.block_map.slice(s![x..x + 1, .., z..z + 1]); - f.write_char(match y.iter().filter(|v| v.is_some()).count() { - 0 => '.', - 1 => '#', - _ => '?', - })?; + let z_plane = self.block_map.slice(s![.., .., z..z+1]); + if z_plane.iter().all(|b| b.is_none()) { continue }; + for i in 0..self.bounds.0 { + // XZ view + let y = z_plane.slice(s![i..i + 1, .., ..]); + f.write_char( + match y.iter().enumerate().find_map(|(idx, val)| val.is_some().then(|| idx)) { + None => ' ', + Some(0) | Some(1) => '█', + Some(2) | Some(3) => '▓', + Some(4) | Some(5) => '▒', + Some(6) | Some(7) => '░', + _ => '░', + }, + )?; } - writeln!(f, " {}", z)?; - } - // YZ view - writeln!(f)?; - writeln!(f, "YZ: [{}, {}]", self.bounds.1, self.bounds.2)?; - for z in (0..self.bounds.2).rev() { + write!(f, " {} ", z)?; for y in 0..self.bounds.1 { - let x = self.block_map.slice(s![.., y..y + 1, z..z + 1]); - f.write_char(match x.iter().filter(|v| v.is_some()).count() { - 0 => '.', - 1 => '#', - _ => '?', - })?; + let x = z_plane.slice(s![.., y..y + 1, ..]); + f.write_char( + match x.iter().enumerate().find_map(|(idx, val)| val.is_some().then(|| idx)) { + None => ' ', + Some(0) | Some(1) => '█', + Some(2) | Some(3) => '▓', + Some(4) | Some(5) => '▒', + Some(6) | Some(7) => '░', + _ => '░', + }, + )?; } writeln!(f, " {}", z)?; } @@ -328,7 +322,6 @@ fn problem2(input: Lines) -> u64 { pile.build_graph(); println!("{}", pile); - println!("block 0 {:?}", pile.blocks[0]); let mut accum = 0; let fixed_nodes = pile @@ -356,19 +349,12 @@ fn problem2(input: Lines) -> u64 { .unique() .count(); // we are looking for the nodes that *will* disintegrate - println!( - "From {}, {} safe, {} disintegrate", - node.index(), - safe_blocks, - pile.graph.node_count() - safe_blocks - ); accum += pile.graph.node_count() - safe_blocks; // put the graph back how it was for neigh in dependents { pile.graph.add_edge(node, neigh, ()); } } - println!("blocks: {} nodes: {}", pile.blocks.len(), pile.graph.node_count()); accum as u64 }