This commit is contained in:
Moritz Hölting 2023-12-22 17:52:57 +01:00
parent 0278599411
commit 876ca3398d
5 changed files with 1498 additions and 0 deletions

8
Cargo.lock generated
View File

@ -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"

12
day-22/Cargo.toml Normal file
View File

@ -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

1203
day-22/src/bin/input.txt Normal file

File diff suppressed because it is too large Load Diff

125
day-22/src/bin/part1.rs Normal file
View File

@ -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));
}
}

150
day-22/src/bin/part2.rs Normal file
View File

@ -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));
}
}