feat: day 18
This commit is contained in:
parent
3660e45ae5
commit
4c86a3ddae
5 changed files with 2425 additions and 0 deletions
2176
.aoc-cache/18.txt
Normal file
2176
.aoc-cache/18.txt
Normal file
File diff suppressed because it is too large
Load diff
106
Cargo.lock
generated
106
Cargo.lock
generated
|
@ -35,6 +35,7 @@ dependencies = [
|
|||
"lru-cache",
|
||||
"peg",
|
||||
"petgraph",
|
||||
"rayon",
|
||||
"regex",
|
||||
"time",
|
||||
"ureq",
|
||||
|
@ -135,6 +136,55 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
|
@ -182,6 +232,15 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
|
@ -259,6 +318,15 @@ version = "2.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.5.4"
|
||||
|
@ -277,6 +345,16 @@ dependencies = [
|
|||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.29.0"
|
||||
|
@ -365,6 +443,28 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.0"
|
||||
|
@ -415,6 +515,12 @@ dependencies = [
|
|||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
|
|
|
@ -20,3 +20,4 @@ regex = "1.7.0"
|
|||
petgraph = "0.6.2"
|
||||
peg = "0.8.1"
|
||||
lru-cache = "0.1.2"
|
||||
rayon = "1.6.1"
|
||||
|
|
129
src/bin/day_18.rs
Normal file
129
src/bin/day_18.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
use std::{collections::{HashSet, HashMap}, ops::RangeInclusive};
|
||||
|
||||
use aoc_2022::prelude::*;
|
||||
use rayon::prelude::*;
|
||||
|
||||
type Coord = (isize, isize, isize);
|
||||
|
||||
type Input = Vec<Coord>;
|
||||
|
||||
fn parse(s: &str) -> Result<Input> {
|
||||
let mut coords = vec![];
|
||||
for line in s.lines() {
|
||||
let coord = ints(line);
|
||||
let coord = (coord[0], coord[1], coord[2]);
|
||||
coords.push(coord);
|
||||
}
|
||||
Ok(coords)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
enum Face {
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
}
|
||||
|
||||
#[aoc(day = 18, parse = parse, test_cases = ["day_18.txt"])]
|
||||
fn day_18(input: Input) -> Result<()> {
|
||||
// Part 1
|
||||
let mut faces = HashSet::<(Face, Coord)>::new();
|
||||
for cube in &input {
|
||||
let cube_faces = [
|
||||
(Face::X, *cube),
|
||||
(Face::X, (cube.0 + 1, cube.1, cube.2)),
|
||||
(Face::Y, *cube),
|
||||
(Face::Y, (cube.0, cube.1 + 1, cube.2)),
|
||||
(Face::Z, *cube),
|
||||
(Face::Z, (cube.0, cube.1, cube.2 + 1)),
|
||||
];
|
||||
for face in cube_faces {
|
||||
if faces.contains(&face) {
|
||||
faces.remove(&face);
|
||||
} else {
|
||||
faces.insert(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Part one: {}", faces.len());
|
||||
|
||||
// Part 2
|
||||
let (x_range, y_range, z_range) = {
|
||||
let min_x = input.iter().map(|c| c.0).min().unwrap();
|
||||
let min_y = input.iter().map(|c| c.1).min().unwrap();
|
||||
let min_z = input.iter().map(|c| c.2).min().unwrap();
|
||||
let max_x = input.iter().map(|c| c.0).max().unwrap();
|
||||
let max_y = input.iter().map(|c| c.1).max().unwrap();
|
||||
let max_z = input.iter().map(|c| c.2).max().unwrap();
|
||||
(min_x..=max_x, min_y..=max_y, min_z..=max_z)
|
||||
};
|
||||
|
||||
let corrected_sa = faces.par_iter().filter(|(face, coord)| {
|
||||
let other = match face {
|
||||
Face::X => (coord.0 - 1, coord.1, coord.2),
|
||||
Face::Y => (coord.0, coord.1 - 1, coord.2),
|
||||
Face::Z => (coord.0, coord.1, coord.2 - 1),
|
||||
};
|
||||
let mut cache = HashMap::new();
|
||||
can_reach_outside(&input, (&x_range, &y_range, &z_range), *coord, &HashSet::new(), &mut cache)
|
||||
|| can_reach_outside(&input, (&x_range, &y_range, &z_range), other, &HashSet::new(), &mut cache)
|
||||
}).count();
|
||||
|
||||
println!("Part 2: {corrected_sa}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn can_reach_outside(
|
||||
input: &Input,
|
||||
(x_range, y_range, z_range): (
|
||||
&RangeInclusive<isize>,
|
||||
&RangeInclusive<isize>,
|
||||
&RangeInclusive<isize>,
|
||||
),
|
||||
position: Coord,
|
||||
visited: &HashSet<Coord>,
|
||||
cache: &mut HashMap<Coord, bool>,
|
||||
) -> bool {
|
||||
if let Some(result) = cache.get(&position) {
|
||||
*result
|
||||
} else {
|
||||
let result = if x_range.contains(&position.0) && y_range.contains(&position.1) && z_range.contains(&position.2) {
|
||||
if input.contains(&position) {
|
||||
false
|
||||
} else {
|
||||
let mut visited = visited.clone();
|
||||
visited.insert(position);
|
||||
|
||||
const DIRECTIONS: &[(isize, isize, isize)] = &[
|
||||
( 1, 0, 0),
|
||||
(-1, 0, 0),
|
||||
( 0, 1, 0),
|
||||
( 0, -1, 0),
|
||||
( 0, 0, 1),
|
||||
( 0, 0, -1),
|
||||
];
|
||||
|
||||
let mut can_reach = false;
|
||||
|
||||
for direction in DIRECTIONS {
|
||||
let new_position = (position.0 + direction.0, position.1 + direction.1, position.2 + direction.2);
|
||||
if visited.contains(&new_position) {
|
||||
continue;
|
||||
}
|
||||
if can_reach_outside(input, (x_range, y_range, z_range), new_position, &visited, cache) {
|
||||
can_reach = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
can_reach
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
cache.insert(position, result);
|
||||
result
|
||||
}
|
||||
}
|
13
test_cases/day_18.txt
Normal file
13
test_cases/day_18.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
2,2,2
|
||||
1,2,2
|
||||
3,2,2
|
||||
2,1,2
|
||||
2,3,2
|
||||
2,2,1
|
||||
2,2,3
|
||||
2,2,4
|
||||
2,2,6
|
||||
1,2,5
|
||||
3,2,5
|
||||
2,1,5
|
||||
2,3,5
|
Loading…
Reference in a new issue