summaryrefslogtreecommitdiff
path: root/2023/src/bin
diff options
context:
space:
mode:
Diffstat (limited to '2023/src/bin')
-rw-r--r--2023/src/bin/day_22.rs122
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()
+ }
+}