day 22
This commit is contained in:
		
							parent
							
								
									0278599411
								
							
						
					
					
						commit
						876ca3398d
					
				|  | @ -214,6 +214,14 @@ dependencies = [ | |||
|  "itertools", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "day-22" | ||||
| version = "0.0.0" | ||||
| dependencies = [ | ||||
|  "indoc", | ||||
|  "itertools", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "deprecate-until" | ||||
| version = "0.1.1" | ||||
|  |  | |||
|  | @ -0,0 +1,12 @@ | |||
| [package] | ||||
| name = "day-22" | ||||
| version = "0.0.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| itertools.workspace = true | ||||
| 
 | ||||
| [dev-dependencies] | ||||
| indoc.workspace = true | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,125 @@ | |||
| use std::collections::{BTreeMap, BTreeSet}; | ||||
| 
 | ||||
| use itertools::Itertools; | ||||
| 
 | ||||
| fn main() { | ||||
|     println!("{}", part1(include_str!("./input.txt"))); | ||||
| } | ||||
| 
 | ||||
| fn part1(input: &str) -> usize { | ||||
|     let mut bricks = input | ||||
|         .lines() | ||||
|         .map(|line| { | ||||
|             let mut ends = line.split('~').map(|part| { | ||||
|                 let mut coords = part.splitn(3, ','); | ||||
|                 let x = coords.next().unwrap().parse::<u16>().unwrap(); | ||||
|                 let y = coords.next().unwrap().parse::<u16>().unwrap(); | ||||
|                 let z = coords.next().unwrap().parse::<u16>().unwrap(); | ||||
| 
 | ||||
|                 (x, y, z) | ||||
|             }); | ||||
|             let start = ends.next().unwrap(); | ||||
|             let end = ends.next().unwrap(); | ||||
| 
 | ||||
|             Brick::new(start, end) | ||||
|         }) | ||||
|         .sorted_by_key(|brick| brick.z.0) | ||||
|         .collect::<Vec<_>>(); | ||||
| 
 | ||||
|     // simulate bricks falling
 | ||||
|     for index in 0..bricks.len() { | ||||
|         let mut max_z = 1; | ||||
|         for check in &bricks[..index] { | ||||
|             if check.overlaps(bricks.get(index).unwrap()) { | ||||
|                 max_z = max_z.max(check.z.1 + 1); | ||||
|             } | ||||
|         } | ||||
|         let brick = bricks.get_mut(index).unwrap(); | ||||
|         brick.z.1 -= brick.z.0 - max_z; | ||||
|         brick.z.0 = max_z; | ||||
|     } | ||||
|     bricks.sort_by_key(|brick| brick.z.0); | ||||
| 
 | ||||
|     let mut supports = (0..bricks.len()) | ||||
|         .map(|i| (i, BTreeSet::new())) | ||||
|         .collect::<BTreeMap<_, _>>(); | ||||
|     let mut supported_by = (0..bricks.len()) | ||||
|         .map(|i| (i, BTreeSet::new())) | ||||
|         .collect::<BTreeMap<_, _>>(); | ||||
| 
 | ||||
|     // find all bricks that support other bricks
 | ||||
|     for (j, upper) in bricks.iter().enumerate() { | ||||
|         for (i, lower) in bricks[..j].iter().enumerate() { | ||||
|             if upper.overlaps(lower) && upper.z.0 == lower.z.1 + 1 { | ||||
|                 supports.get_mut(&i).unwrap().insert(j); | ||||
|                 supported_by.get_mut(&j).unwrap().insert(i); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // count all the bricks for which all the bricks that
 | ||||
|     // it supports have more than one supporter
 | ||||
|     supports | ||||
|         .values() | ||||
|         .filter(|supported| { | ||||
|             supported | ||||
|                 .iter() | ||||
|                 .all(|brick| supported_by.get(brick).unwrap().len() > 1) | ||||
|         }) | ||||
|         .count() | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| struct Brick { | ||||
|     x: (u16, u16), | ||||
|     y: (u16, u16), | ||||
|     z: (u16, u16), | ||||
| } | ||||
| impl Brick { | ||||
|     fn new(start: (u16, u16, u16), end: (u16, u16, u16)) -> Self { | ||||
|         Self { | ||||
|             x: (start.0, end.0), | ||||
|             y: (start.1, end.1), | ||||
|             z: (start.2, end.2), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn overlaps(&self, other: &Self) -> bool { | ||||
|         self.x.1 >= other.x.0 | ||||
|             && other.x.1 >= self.x.0 | ||||
|             && self.y.1 >= other.y.0 | ||||
|             && other.y.1 >= self.y.0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use indoc::indoc; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_part1() { | ||||
|         assert_eq!( | ||||
|             part1(indoc!( | ||||
|                 " | ||||
|                 1,0,1~1,2,1 | ||||
|                 0,0,2~2,0,2 | ||||
|                 0,2,3~2,2,3 | ||||
|                 0,0,4~0,2,4 | ||||
|                 2,0,5~2,2,5 | ||||
|                 0,1,6~2,1,6 | ||||
|                 1,1,8~1,1,9 | ||||
|                 " | ||||
|             )), | ||||
|             5 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_overlap() { | ||||
|         let brick_a = Brick::new((0, 0, 0), (2, 1, 1)); | ||||
|         let brick_b = Brick::new((1, 0, 0), (1, 1, 1)); | ||||
| 
 | ||||
|         assert!(brick_a.overlaps(&brick_b)); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,150 @@ | |||
| use std::collections::{BTreeMap, BTreeSet}; | ||||
| 
 | ||||
| use itertools::Itertools; | ||||
| 
 | ||||
| fn main() { | ||||
|     println!("{}", part2(include_str!("./input.txt"))); | ||||
| } | ||||
| 
 | ||||
| fn part2(input: &str) -> usize { | ||||
|     let mut bricks = input | ||||
|         .lines() | ||||
|         .map(|line| { | ||||
|             let mut ends = line.split('~').map(|part| { | ||||
|                 let mut coords = part.splitn(3, ','); | ||||
|                 let x = coords.next().unwrap().parse::<u16>().unwrap(); | ||||
|                 let y = coords.next().unwrap().parse::<u16>().unwrap(); | ||||
|                 let z = coords.next().unwrap().parse::<u16>().unwrap(); | ||||
| 
 | ||||
|                 (x, y, z) | ||||
|             }); | ||||
|             let start = ends.next().unwrap(); | ||||
|             let end = ends.next().unwrap(); | ||||
| 
 | ||||
|             Brick::new(start, end) | ||||
|         }) | ||||
|         .sorted_by_key(|brick| brick.z.0) | ||||
|         .collect::<Vec<_>>(); | ||||
| 
 | ||||
|     // simulate bricks falling
 | ||||
|     for index in 0..bricks.len() { | ||||
|         let mut max_z = 1; | ||||
|         for check in &bricks[..index] { | ||||
|             if check.overlaps(bricks.get(index).unwrap()) { | ||||
|                 max_z = max_z.max(check.z.1 + 1); | ||||
|             } | ||||
|         } | ||||
|         let brick = bricks.get_mut(index).unwrap(); | ||||
|         brick.z.1 -= brick.z.0 - max_z; | ||||
|         brick.z.0 = max_z; | ||||
|     } | ||||
|     bricks.sort_by_key(|brick| brick.z.0); | ||||
| 
 | ||||
|     let mut supports = (0..bricks.len()) | ||||
|         .map(|i| (i, BTreeSet::new())) | ||||
|         .collect::<BTreeMap<_, _>>(); | ||||
|     let mut supported_by = (0..bricks.len()) | ||||
|         .map(|i| (i, BTreeSet::new())) | ||||
|         .collect::<BTreeMap<_, _>>(); | ||||
| 
 | ||||
|     // find all bricks that support other bricks
 | ||||
|     for (j, upper) in bricks.iter().enumerate() { | ||||
|         for (i, lower) in bricks[..j].iter().enumerate() { | ||||
|             if upper.overlaps(lower) && upper.z.0 == lower.z.1 + 1 { | ||||
|                 supports.get_mut(&i).unwrap().insert(j); | ||||
|                 supported_by.get_mut(&j).unwrap().insert(i); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     supports | ||||
|         .keys() | ||||
|         .map(|index| { | ||||
|             let mut supported_by = supported_by.clone(); | ||||
|             disintigrate(*index, &supports, &mut supported_by) | ||||
|         }) | ||||
|         .sum::<usize>() | ||||
| } | ||||
| 
 | ||||
| fn disintigrate( | ||||
|     index: usize, | ||||
|     supports: &BTreeMap<usize, BTreeSet<usize>>, | ||||
|     supported_by: &mut BTreeMap<usize, BTreeSet<usize>>, | ||||
| ) -> usize { | ||||
|     supports | ||||
|         .get(&index) | ||||
|         .iter() | ||||
|         .map(|supported_bricks| { | ||||
|             supported_bricks | ||||
|                 .iter() | ||||
|                 .map(|supported_brick| { | ||||
|                     supported_by | ||||
|                         .get_mut(supported_brick) | ||||
|                         .unwrap() | ||||
|                         .remove(&index); | ||||
|                     let supporting_bricks = supported_by.get(supported_brick).unwrap(); | ||||
|                     if !supporting_bricks.is_empty() { | ||||
|                         0 | ||||
|                     } else { | ||||
|                         1 + disintigrate(*supported_brick, supports, supported_by) | ||||
|                     } | ||||
|                 }) | ||||
|                 .sum::<usize>() | ||||
|         }) | ||||
|         .sum() | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| struct Brick { | ||||
|     x: (u16, u16), | ||||
|     y: (u16, u16), | ||||
|     z: (u16, u16), | ||||
| } | ||||
| impl Brick { | ||||
|     fn new(start: (u16, u16, u16), end: (u16, u16, u16)) -> Self { | ||||
|         Self { | ||||
|             x: (start.0, end.0), | ||||
|             y: (start.1, end.1), | ||||
|             z: (start.2, end.2), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn overlaps(&self, other: &Self) -> bool { | ||||
|         self.x.1 >= other.x.0 | ||||
|             && other.x.1 >= self.x.0 | ||||
|             && self.y.1 >= other.y.0 | ||||
|             && other.y.1 >= self.y.0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|     use indoc::indoc; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_part2() { | ||||
|         assert_eq!( | ||||
|             part2(indoc!( | ||||
|                 " | ||||
|                 1,0,1~1,2,1 | ||||
|                 0,0,2~2,0,2 | ||||
|                 0,2,3~2,2,3 | ||||
|                 0,0,4~0,2,4 | ||||
|                 2,0,5~2,2,5 | ||||
|                 0,1,6~2,1,6 | ||||
|                 1,1,8~1,1,9 | ||||
|                 " | ||||
|             )), | ||||
|             7 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_overlap() { | ||||
|         let brick_a = Brick::new((0, 0, 0), (2, 1, 1)); | ||||
|         let brick_b = Brick::new((1, 0, 0), (1, 1, 1)); | ||||
| 
 | ||||
|         assert!(brick_a.overlaps(&brick_b)); | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue