2022 day18/rust: add solution
This commit is contained in:
parent
cc61c42178
commit
a330505361
4 changed files with 176 additions and 0 deletions
11
2022/day18/rust/Cargo.toml
Normal file
11
2022/day18/rust/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "rust_2022_18"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
aoc = { path = "../../../common/rust" }
|
||||||
|
petgraph = "0.6.2"
|
||||||
|
strum = "0.24.1"
|
155
2022/day18/rust/src/main.rs
Normal file
155
2022/day18/rust/src/main.rs
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
#![warn(clippy::pedantic)]
|
||||||
|
#![feature(generators)]
|
||||||
|
#![feature(iter_from_generator)]
|
||||||
|
#![feature(let_chains)]
|
||||||
|
|
||||||
|
use petgraph::{algo::tarjan_scc, prelude::GraphMap, Undirected};
|
||||||
|
use std::{io::stdin, iter};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use aoc::vecn::{Direction3, VecN};
|
||||||
|
|
||||||
|
type Position = VecN<3, u64>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
struct Face {
|
||||||
|
position: Position,
|
||||||
|
side: Direction3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Face {
|
||||||
|
fn facing(self) -> Option<Position> {
|
||||||
|
let pos = self.position.try_map(i64::try_from).ok()? + self.side.into();
|
||||||
|
|
||||||
|
pos.try_map(u64::try_from).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inverse(self) -> Option<Face> {
|
||||||
|
Some(Face {
|
||||||
|
position: self.facing()?,
|
||||||
|
side: -self.side,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neighbours(self) -> impl Iterator<Item = (Angle, Face)> {
|
||||||
|
iter::from_generator(move || {
|
||||||
|
let orthogonal_sides =
|
||||||
|
Direction3::iter().filter(move |&side| side != self.side && side != -self.side);
|
||||||
|
|
||||||
|
for side in orthogonal_sides.clone() {
|
||||||
|
yield (
|
||||||
|
Angle::Convex,
|
||||||
|
Face {
|
||||||
|
position: self.position,
|
||||||
|
side,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(facing) = self.facing() {
|
||||||
|
for side in orthogonal_sides.clone() {
|
||||||
|
if let Some(inverse) = (Face {
|
||||||
|
position: facing,
|
||||||
|
side,
|
||||||
|
})
|
||||||
|
.inverse()
|
||||||
|
{
|
||||||
|
yield (Angle::Concave, inverse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for side in orthogonal_sides {
|
||||||
|
if let Some(facing) = (Face {
|
||||||
|
position: self.position,
|
||||||
|
side,
|
||||||
|
})
|
||||||
|
.facing()
|
||||||
|
{
|
||||||
|
yield (
|
||||||
|
Angle::Flat,
|
||||||
|
Face {
|
||||||
|
position: facing,
|
||||||
|
side: self.side,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum Angle {
|
||||||
|
Concave,
|
||||||
|
Convex,
|
||||||
|
Flat,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cubes = stdin().lines().map(|l| l.unwrap().parse().unwrap());
|
||||||
|
let faces =
|
||||||
|
cubes.flat_map(|position| Direction3::iter().map(move |side| Face { position, side }));
|
||||||
|
|
||||||
|
let mut graph = GraphMap::<Face, Angle, Undirected>::new();
|
||||||
|
for face in faces {
|
||||||
|
if let Some(inverse) = face.inverse() {
|
||||||
|
if graph.remove_node(inverse) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.add_node(face);
|
||||||
|
|
||||||
|
for (angle, neighbour_face) in face.neighbours() {
|
||||||
|
if graph.contains_node(neighbour_face) {
|
||||||
|
graph.add_edge(face, neighbour_face, angle);
|
||||||
|
|
||||||
|
if let Angle::Concave = angle {
|
||||||
|
graph.remove_edge(
|
||||||
|
face,
|
||||||
|
Face {
|
||||||
|
position: face.position,
|
||||||
|
side: -neighbour_face.side,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
graph.remove_edge(
|
||||||
|
neighbour_face,
|
||||||
|
Face {
|
||||||
|
position: neighbour_face.position,
|
||||||
|
side: -face.side,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", graph.node_count());
|
||||||
|
|
||||||
|
let sum_outside = tarjan_scc(&graph)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|surface| {
|
||||||
|
graph
|
||||||
|
.all_edges()
|
||||||
|
.filter_map(|(start, end, angle)| {
|
||||||
|
if surface.contains(&start) || surface.contains(&end) {
|
||||||
|
Some(angle)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|angle| match angle {
|
||||||
|
Angle::Concave => -1,
|
||||||
|
Angle::Convex => 1,
|
||||||
|
Angle::Flat => 0,
|
||||||
|
})
|
||||||
|
.sum::<i64>()
|
||||||
|
> 0
|
||||||
|
})
|
||||||
|
.map(|surface| surface.len())
|
||||||
|
.max()
|
||||||
|
.unwrap();
|
||||||
|
println!("{:?}", sum_outside);
|
||||||
|
}
|
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -619,6 +619,15 @@ dependencies = [
|
||||||
"aoc",
|
"aoc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust_2022_18"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"aoc",
|
||||||
|
"petgraph",
|
||||||
|
"strum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
|
|
@ -25,4 +25,5 @@ members = [
|
||||||
"2022/day13/rust",
|
"2022/day13/rust",
|
||||||
"2022/day14/rust",
|
"2022/day14/rust",
|
||||||
"2022/day15/rust",
|
"2022/day15/rust",
|
||||||
|
"2022/day18/rust",
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue