day 22
This commit is contained in:
parent
0278599411
commit
876ca3398d
|
@ -214,6 +214,14 @@ dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day-22"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"indoc",
|
||||||
|
"itertools",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deprecate-until"
|
name = "deprecate-until"
|
||||||
version = "0.1.1"
|
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