[Rust/2023/22] Add solution
This commit is contained in:
parent
41bb20f78b
commit
ca9b7cd4d2
7 changed files with 254 additions and 3 deletions
File diff suppressed because one or more lines are too long
203
Rust/2023/22.rs
Normal file
203
Rust/2023/22.rs
Normal file
|
@ -0,0 +1,203 @@
|
|||
#![feature(test)]
|
||||
|
||||
use itertools::Itertools;
|
||||
use rayon::prelude::*;
|
||||
|
||||
type Input = Vec<Brick>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct Brick(Pos3, Pos3);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct Rect(Pos2, Pos2);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct Pos3 {
|
||||
x: usize,
|
||||
y: usize,
|
||||
z: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct Pos2 {
|
||||
x: usize,
|
||||
y: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct Range(usize, usize);
|
||||
|
||||
fn setup(input: &str) -> Input {
|
||||
input
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let (a, b) = line
|
||||
.split('~')
|
||||
.map(|pos| {
|
||||
let (x, y, z) = pos
|
||||
.split(',')
|
||||
.map(|x| x.parse().unwrap())
|
||||
.collect_tuple()
|
||||
.unwrap();
|
||||
Pos3 { x, y, z }
|
||||
})
|
||||
.collect_tuple()
|
||||
.unwrap();
|
||||
Brick(a, b)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl Brick {
|
||||
fn can_support(self, other: Self) -> bool {
|
||||
self.xy_rect().overlaps(other.xy_rect()) && self.1.z < other.0.z
|
||||
}
|
||||
|
||||
fn xy_rect(self) -> Rect {
|
||||
Rect(self.0.xy(), self.1.xy())
|
||||
}
|
||||
|
||||
fn height(self) -> usize {
|
||||
self.1.z - self.0.z + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
fn overlaps(self, other: Self) -> bool {
|
||||
self.x_range().overlaps(other.x_range()) && self.y_range().overlaps(other.y_range())
|
||||
}
|
||||
|
||||
fn x_range(self) -> Range {
|
||||
Range(self.0.x, self.1.x)
|
||||
}
|
||||
|
||||
fn y_range(self) -> Range {
|
||||
Range(self.0.y, self.1.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl Pos3 {
|
||||
fn xy(self) -> Pos2 {
|
||||
Pos2 {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Range {
|
||||
fn overlaps(self, other: Self) -> bool {
|
||||
!(self.1 < other.0 || other.1 < self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct Graph {
|
||||
support_matrix: Vec<Vec<bool>>,
|
||||
support_lst: Vec<Vec<usize>>,
|
||||
support_rev: Vec<Vec<usize>>,
|
||||
unstable: Vec<usize>,
|
||||
}
|
||||
|
||||
fn adj_matrix_to_lists(matrix: &[Vec<bool>]) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
|
||||
let n = matrix.len();
|
||||
let lst = (0..n)
|
||||
.into_par_iter()
|
||||
.map(|i| (0..n).filter(|&j| matrix[i][j]).collect())
|
||||
.collect();
|
||||
let rev = (0..n)
|
||||
.into_par_iter()
|
||||
.map(|i| (0..n).filter(|&j| matrix[j][i]).collect())
|
||||
.collect();
|
||||
(lst, rev)
|
||||
}
|
||||
|
||||
fn build_graph(bricks: &[Brick]) -> Graph {
|
||||
let n = bricks.len();
|
||||
|
||||
let can_support_matrix = bricks
|
||||
.par_iter()
|
||||
.map(|&a| bricks.iter().map(|&b| a.can_support(b)).collect_vec())
|
||||
.collect::<Vec<_>>();
|
||||
let (can_support_lst, can_support_rev) = adj_matrix_to_lists(&can_support_matrix);
|
||||
|
||||
let mut blocked = can_support_rev.iter().map(|x| x.len()).collect_vec();
|
||||
let mut queue = (0..n).filter(|&i| blocked[i] == 0).collect_vec();
|
||||
let mut start_z = vec![0; n];
|
||||
while let Some(p) = queue.pop() {
|
||||
start_z[p] = can_support_rev[p]
|
||||
.iter()
|
||||
.map(|&i| start_z[i] + bricks[i].height())
|
||||
.max()
|
||||
.unwrap_or(1);
|
||||
queue.extend(can_support_lst[p].iter().filter(|&&q| {
|
||||
blocked[q] -= 1;
|
||||
blocked[q] == 0
|
||||
}));
|
||||
}
|
||||
|
||||
let support_matrix = can_support_matrix
|
||||
.into_par_iter()
|
||||
.zip(&start_z)
|
||||
.zip(bricks)
|
||||
.map(|((can_support, &z1), brick)| {
|
||||
can_support
|
||||
.into_iter()
|
||||
.zip(&start_z)
|
||||
.map(|(can_support, &z2)| can_support && z1 + brick.height() == z2)
|
||||
.collect_vec()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (support_lst, support_rev) = adj_matrix_to_lists(&support_matrix);
|
||||
|
||||
let unstable = (0..n).filter(|&i| support_rev[i].len() == 1).collect();
|
||||
|
||||
Graph {
|
||||
support_matrix,
|
||||
support_lst,
|
||||
support_rev,
|
||||
unstable,
|
||||
}
|
||||
}
|
||||
|
||||
fn part1(input: &Input) -> usize {
|
||||
let Graph {
|
||||
support_matrix,
|
||||
unstable,
|
||||
..
|
||||
} = build_graph(input);
|
||||
support_matrix
|
||||
.par_iter()
|
||||
.filter(|x| !unstable.iter().any(|&i| x[i]))
|
||||
.count()
|
||||
}
|
||||
|
||||
fn part2(input: &Input) -> usize {
|
||||
let Graph {
|
||||
support_matrix,
|
||||
support_lst,
|
||||
support_rev,
|
||||
unstable,
|
||||
} = build_graph(input);
|
||||
|
||||
support_matrix
|
||||
.par_iter()
|
||||
.enumerate()
|
||||
.filter(|(_, x)| unstable.iter().any(|&i| x[i]))
|
||||
.map(|(i, _)| {
|
||||
let mut out = 0;
|
||||
let mut blocked = support_rev.iter().map(|x| x.len()).collect_vec();
|
||||
let mut queue = vec![i];
|
||||
while let Some(p) = queue.pop() {
|
||||
out += 1;
|
||||
queue.extend(support_lst[p].iter().filter(|&&q| {
|
||||
blocked[q] -= 1;
|
||||
blocked[q] == 0
|
||||
}));
|
||||
}
|
||||
out - 1
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
aoc::main!(2023, 22, ex: 1);
|
|
@ -287,3 +287,6 @@ path = "2023/20.rs"
|
|||
[[bin]]
|
||||
name = "2023_21"
|
||||
path = "2023/21.rs"
|
||||
[[bin]]
|
||||
name = "2023_22"
|
||||
path = "2023/22.rs"
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::ops::Add;
|
||||
use std::ops::{Add, Sub};
|
||||
|
||||
use num::One;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct Range<T> {
|
||||
|
@ -30,7 +32,34 @@ impl<T> From<std::ops::Range<T>> for Range<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Sub<Output = T> + One> From<Range<T>> for std::ops::RangeInclusive<T> {
|
||||
fn from(value: Range<T>) -> Self {
|
||||
value.start..=value.end - T::one()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Add<Output = T> + One> From<std::ops::RangeInclusive<T>> for Range<T> {
|
||||
fn from(value: std::ops::RangeInclusive<T>) -> Self {
|
||||
let (start, end) = value.into_inner();
|
||||
Self {
|
||||
start,
|
||||
end: end + T::one(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Range<T> {
|
||||
pub fn new(start: T, end: T) -> Self {
|
||||
Self { start, end }
|
||||
}
|
||||
|
||||
pub fn new_inclusive(start: T, end: T) -> Self
|
||||
where
|
||||
T: Add<Output = T> + One,
|
||||
{
|
||||
Self::new(start, end + T::one())
|
||||
}
|
||||
|
||||
pub fn into_std(self) -> std::ops::Range<T> {
|
||||
self.into()
|
||||
}
|
||||
|
@ -60,6 +89,13 @@ impl<T> Range<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn overlaps(&self, other: &Range<T>) -> bool
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
!matches!(self.rel(other), RangeRel::LeftOf | RangeRel::RightOf)
|
||||
}
|
||||
|
||||
pub fn add<N>(&self, n: N) -> Range<<T as Add<N>>::Output>
|
||||
where
|
||||
T: Copy + Add<N>,
|
||||
|
|
7
examples/2023/22/1
Normal file
7
examples/2023/22/1
Normal file
|
@ -0,0 +1,7 @@
|
|||
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
|
1
examples/2023/22/1.1
Normal file
1
examples/2023/22/1.1
Normal file
|
@ -0,0 +1 @@
|
|||
5
|
1
examples/2023/22/1.2
Normal file
1
examples/2023/22/1.2
Normal file
|
@ -0,0 +1 @@
|
|||
7
|
Loading…
Add table
Add a link
Reference in a new issue