diff options
Diffstat (limited to '2023/src/bin')
-rw-r--r-- | 2023/src/bin/day_22.rs | 122 |
1 files changed, 117 insertions, 5 deletions
diff --git a/2023/src/bin/day_22.rs b/2023/src/bin/day_22.rs index 3619b83..750f975 100644 --- a/2023/src/bin/day_22.rs +++ b/2023/src/bin/day_22.rs @@ -11,8 +11,11 @@ use std::fs; fn main() -> Result<(), Box<dyn std::error::Error>> { let input = fs::read_to_string("inputs/day_22.txt")?; - let parsed = BrickPile::parser(&input).unwrap().1; - dbg!(&parsed); + let pile = BrickPile::parser(&input).unwrap().1; + let settled_pile = pile.settle(); + let brickfall_sum = settled_pile.brickfall_sum(); + dbg!(&brickfall_sum.count_disintegratable_blocks()); + dbg!(&brickfall_sum.sum_brickfalls()); Ok(()) } @@ -21,24 +24,102 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { struct BrickPile(Vec<Brick>); #[derive(Debug)] +struct SettledBrickPile { + bricks: Vec<Brick>, + settled_count: usize, +} + +#[derive(Debug, Clone)] struct Brick { - a: Point3<u32>, - b: Point3<u32>, + bottom: Point3<u32>, // the lowest z will always be here. The top might still have the same z. + top: Point3<u32>, } +#[derive(Debug)] +struct BrickfallSum(Vec<usize>); + impl BrickPile { fn parser(input: &str) -> IResult<&str, Self> { map(separated_list1(line_ending, Brick::parser), BrickPile)(input) } + + fn settle(&self) -> SettledBrickPile { + let mut settled_bricks = self.0.clone(); + let mut has_fallen = vec![false; settled_bricks.len()]; + + let mut all_settled = false; + + while !all_settled { + all_settled = true; + for self_i in 0..settled_bricks.len() { + let this_brick_is_resting_on_something = settled_bricks[self_i] + .is_resting_on_ground() + || (0..settled_bricks.len()).any(|other_i| { + self_i != other_i + && settled_bricks[self_i].is_resting_on_other(&settled_bricks[other_i]) + }); + + if !this_brick_is_resting_on_something { + settled_bricks[self_i].fall_one(); + has_fallen[self_i] = true; + all_settled = false; + } + } + } + + SettledBrickPile { + bricks: settled_bricks, + settled_count: has_fallen.iter().filter(|f| **f).count(), + } + } } impl Brick { fn parser(input: &str) -> IResult<&str, Self> { map( separated_pair(point_parser, tag("~"), point_parser), - |(a, b)| Brick { a, b }, + |(a, b)| { + if a.z < b.z { + Brick { bottom: a, top: b } + } else { + Brick { top: a, bottom: b } + } + }, )(input) } + + fn min_x(&self) -> u32 { + self.bottom.x.min(self.top.x) + } + + fn max_x(&self) -> u32 { + self.bottom.x.max(self.top.x) + } + + fn min_y(&self) -> u32 { + self.bottom.y.min(self.top.y) + } + + fn max_y(&self) -> u32 { + self.bottom.y.max(self.top.y) + } + + fn is_resting_on_ground(&self) -> bool { + self.bottom.z == 1 + } + + fn is_resting_on_other(&self, other: &Self) -> bool { + self.bottom.z == other.top.z + 1 + && self.min_x() <= other.max_x() + && other.min_x() <= self.max_x() + && self.min_y() <= other.max_y() + && other.min_y() <= self.max_y() + } + + fn fall_one(&mut self) { + self.bottom.z -= 1; + self.top.z -= 1; + } } fn point_parser(input: &str) -> IResult<&str, Point3<u32>> { @@ -47,3 +128,34 @@ fn point_parser(input: &str) -> IResult<&str, Point3<u32>> { |(x, _, y, _, z)| Point3::new(x, y, z), )(input) } + +impl SettledBrickPile { + fn brickfall_sum(&self) -> BrickfallSum { + BrickfallSum( + (0..self.bricks.len()) + .map(|self_i| { + self.count_bricks_that_would_fall_if_this_one_is_disintegrated(self_i) + }) + .collect(), + ) + } + + fn count_bricks_that_would_fall_if_this_one_is_disintegrated(&self, i: usize) -> usize { + let mut unsettled_bricks = self.bricks.clone(); + unsettled_bricks.remove(i); + let unsettled_bricks = BrickPile(unsettled_bricks); + + let resettled = unsettled_bricks.settle(); + resettled.settled_count + } +} + +impl BrickfallSum { + fn count_disintegratable_blocks(&self) -> usize { + self.0.iter().filter(|fallen| **fallen == 0).count() + } + + fn sum_brickfalls(&self) -> usize { + self.0.iter().sum() + } +} |