2022 day18/rust: add solution

This commit is contained in:
Xiretza 2022-12-19 19:29:01 +01:00
parent cc61c42178
commit a330505361
4 changed files with 176 additions and 0 deletions

View 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
View 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
View file

@ -619,6 +619,15 @@ dependencies = [
"aoc",
]
[[package]]
name = "rust_2022_18"
version = "0.1.0"
dependencies = [
"aoc",
"petgraph",
"strum",
]
[[package]]
name = "rustversion"
version = "1.0.11"

View file

@ -25,4 +25,5 @@ members = [
"2022/day13/rust",
"2022/day14/rust",
"2022/day15/rust",
"2022/day18/rust",
]