day22: cleanup & nice output

This commit is contained in:
Keenan Tims 2023-12-22 04:19:58 -08:00
parent dd91259fe2
commit 3bb3b3d6b6
Signed by: ktims
GPG Key ID: 11230674D69038D4

View File

@ -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<T: BufRead> From<Lines<T>> for BlockPile {
fn from(lines: Lines<T>) -> 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<T: BufRead> From<Lines<T>> 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<T: BufRead>(input: Lines<T>) -> 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<T: BufRead>(input: Lines<T>) -> 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
}