Advertisement
saaoijeefhiuh

day 22

Dec 22nd, 2023 (edited)
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.27 KB | None | 0 0
  1. advent_of_code::solution!(22);
  2. use std::cmp::min;
  3. use std::collections::HashSet;
  4.  
  5. #[derive(Debug, PartialEq, Eq, Clone)]
  6. struct Brick {
  7.     start: (u32, u32, u32),
  8.     end: (u32, u32, u32),
  9.     cubes: HashSet<(u32, u32)>,
  10. }
  11.  
  12. impl Brick {
  13.     pub fn parse(c: &str) -> Self {
  14.         let p = |c: &str| -> (u32, u32, u32) {
  15.             let mut w = c.split(",").map(|b| b.parse::<u32>().unwrap());
  16.             (w.next().unwrap(), w.next().unwrap(), w.next().unwrap())
  17.         };
  18.  
  19.         let (l, r) = c.split_once("~").unwrap();
  20.         let (p1, p2) = (p(l), p(r));
  21.  
  22.         Brick::new(p1, p2)
  23.     }
  24.  
  25.     pub fn new(start: (u32, u32, u32), end: (u32, u32, u32)) -> Brick {
  26.         assert!(end.0 >= start.0 && end.1 >= start.1 && end.2 >= start.2);
  27.  
  28.         Brick {
  29.             start: start,
  30.             end: end,
  31.             cubes: (start.0..(end.0 + 1))
  32.                 .map(|i| (start.1..(end.1 + 1)).map(move |j| (i, j)))
  33.                 .flatten()
  34.                 .collect(),
  35.         }
  36.     }
  37.     // distance from ground
  38.     pub fn bottom(&self) -> u32 {
  39.         min(self.start.2, self.end.2)
  40.     }
  41.  
  42.     fn top(&self) -> u32 {
  43.         self.end.2
  44.     }
  45.  
  46.     fn intersects(&self, other: &Brick) -> bool {
  47.         self.cubes.intersection(&(other.cubes)).count() > 0
  48.     }
  49.  
  50.     pub fn drop(&self, on_ground: &Vec<Brick>) -> Brick {
  51.         let c = self.clone();
  52.         let new_floor = on_ground
  53.             .iter()
  54.             .map(|b| if self.intersects(b) { b.top() + 1 } else { 1 })
  55.             .max()
  56.             .unwrap();
  57.  
  58.         let mut new_start = self.start.clone();
  59.         let mut new_end = self.end.clone();
  60.  
  61.         if new_floor < c.bottom() {
  62.             new_end.2 = new_floor + (new_end.2 - new_start.2);
  63.             new_start.2 = new_floor;
  64.         }
  65.  
  66.         Brick::new(new_start, new_end)
  67.     }
  68.  
  69.     pub fn supports(&self, other: &Brick) -> bool {
  70.         other.bottom() == (self.top() + 1) && self.intersects(other)
  71.     }
  72. }
  73.  
  74. fn process(input: &str) -> (Vec<Brick>, Vec<usize>, Vec<Vec<bool>>) {
  75.     let bricks: Vec<Brick> = input.lines().map(|l| Brick::parse(l)).collect();
  76.  
  77.     let max_h = bricks.iter().map(|b| b.bottom()).max().unwrap();
  78.  
  79.     let dropped = (2..max_h + 1).fold(
  80.         bricks
  81.             .clone()
  82.             .into_iter()
  83.             .filter(|b| b.bottom() == 1)
  84.             .collect::<Vec<Brick>>(),
  85.         |mut on_ground, h| {
  86.             // look at bricks that start at this level and move them down
  87.             // as far as they can travel
  88.             let dropped = bricks
  89.                 .iter()
  90.                 .filter(|b| b.bottom() == h)
  91.                 .map(|b| b.drop(&on_ground))
  92.                 .collect::<Vec<Brick>>();
  93.  
  94.             dropped.into_iter().for_each(|b| {
  95.                 on_ground.push(b);
  96.             });
  97.  
  98.             on_ground
  99.         },
  100.     );
  101.  
  102.     // find which blocks support which others: i supports j
  103.     let supports: Vec<Vec<bool>> = (0..dropped.len())
  104.         .map(|i| {
  105.             (0..dropped.len())
  106.                 .map(|j| {
  107.                     if i == j {
  108.                         false
  109.                     } else {
  110.                         dropped[i].supports(&dropped[j])
  111.                     }
  112.                 })
  113.                 .collect::<Vec<bool>>()
  114.         })
  115.         .collect();
  116.  
  117.     let r: Vec<usize> = (0..dropped.len())
  118.         .filter(|i| {
  119.             // block can be removed if it supports nothing
  120.             // or the things it supports are also supported by something else
  121.             supports[*i]
  122.                 .iter()
  123.                 .enumerate()
  124.                 .filter(|(_, s)| **s)
  125.                 .filter(|(j, _)| (0..dropped.len()).filter(|k| supports[*k][*j]).count() == 1)
  126.                 .count()
  127.                 == 0
  128.         })
  129.         .collect();
  130.  
  131.     (dropped, r, supports)
  132. }
  133.  
  134. pub fn part_one(input: &str) -> Option<usize> {
  135.     let (_, removable, _) = process(input);
  136.  
  137.     Some(removable.iter().count())
  138. }
  139.  
  140. pub fn part_two(input: &str) -> Option<usize> {
  141.     let (dropped, removable, supports) = process(input);
  142.  
  143.     let supported_by: Vec<Vec<usize>> = (0..dropped.len())
  144.         .map(|i| (0..dropped.len()).filter(|j| supports[*j][i]).collect())
  145.         .collect();
  146.  
  147.     Some(
  148.         (0..dropped.len())
  149.             .filter(|i| !removable.contains(i))
  150.             .map(|i| {
  151.                 // if i is removed, find those that fall, and continue the process
  152.                 ((i + 1)..dropped.len())
  153.                     .fold(vec![], |mut fall, j| {
  154.                         // find the number of bricks supporting j once i has been removed
  155.                         if dropped[j].bottom() > 1
  156.                             && supported_by[j]
  157.                                 .iter()
  158.                                 // count the number of remaining blocks that support j
  159.                                 .filter(|&k| *k != i && !fall.contains(k))
  160.                                 .count()
  161.                                 == 0
  162.                         {
  163.                             // nothing supporting j - it will collapse
  164.                             fall.push(j);
  165.                         }
  166.                         fall
  167.                     })
  168.                     .len()
  169.             })
  170.             .sum::<usize>(),
  171.     )
  172. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement