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