generated from janezicmatej/aoc-template
Compare commits
2 Commits
00000260b8
...
0000028054
Author | SHA1 | Date |
---|---|---|
Matej Janezic | 0000028054 | |
Matej Janezic | 00000270f6 |
|
@ -17,6 +17,18 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.8.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
@ -36,6 +48,7 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
name = "aoc"
|
name = "aoc"
|
||||||
version = "48.0.0"
|
version = "48.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cached",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
"itertools",
|
"itertools",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
|
@ -87,6 +100,39 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cached"
|
||||||
|
version = "0.54.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"cached_proc_macro",
|
||||||
|
"cached_proc_macro_types",
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
"once_cell",
|
||||||
|
"thiserror",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cached_proc_macro"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cached_proc_macro_types"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.78"
|
version = "1.0.78"
|
||||||
|
@ -115,6 +161,41 @@ version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenvy"
|
name = "dotenvy"
|
||||||
version = "0.15.6"
|
version = "0.15.6"
|
||||||
|
@ -275,6 +356,16 @@ version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"allocator-api2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
|
@ -366,6 +457,12 @@ dependencies = [
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -535,9 +632,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.16.0"
|
version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
|
@ -562,7 +659,7 @@ checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 1.0.107",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -616,18 +713,18 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.33"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
@ -829,6 +926,12 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.107"
|
version = "1.0.107"
|
||||||
|
@ -840,6 +943,17 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.90"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-configuration"
|
name = "system-configuration"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -875,6 +989,26 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
@ -1000,6 +1134,12 @@ version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -1037,7 +1177,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 1.0.107",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1071,7 +1211,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 1.0.107",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
@ -1092,6 +1232,16 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-time"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
@ -1232,3 +1382,23 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
|
@ -21,6 +21,7 @@ authors.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
cached = "0.54.0"
|
||||||
hashbrown = "0.15.2"
|
hashbrown = "0.15.2"
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
num-integer = "0.1.46"
|
num-integer = "0.1.46"
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
###############
|
||||||
|
#...#...#.....#
|
||||||
|
#.#.#.#.#.###.#
|
||||||
|
#S#...#.#.#...#
|
||||||
|
#######.#.#.###
|
||||||
|
#######.#.#...#
|
||||||
|
#######.#.###.#
|
||||||
|
###..E#...#...#
|
||||||
|
###.#######.###
|
||||||
|
#...###...#...#
|
||||||
|
#.#####.#.###.#
|
||||||
|
#.#...#.#.#...#
|
||||||
|
#.#.#.#.#.#.###
|
||||||
|
#...#...#...###
|
||||||
|
###############
|
|
@ -0,0 +1,5 @@
|
||||||
|
029A
|
||||||
|
980A
|
||||||
|
179A
|
||||||
|
456A
|
||||||
|
379A
|
|
@ -0,0 +1,135 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use aoc::grid_vec::{Direction, Grid, Point};
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
|
fn parse_input(input: &str) -> (Grid, Point, Point) {
|
||||||
|
let mut grid: Grid = input.parse().unwrap();
|
||||||
|
let start = grid.find(b'S').unwrap();
|
||||||
|
let end = grid.find(b'E').unwrap();
|
||||||
|
|
||||||
|
grid[start] = b'.';
|
||||||
|
grid[end] = b'.';
|
||||||
|
|
||||||
|
(grid, start, end)
|
||||||
|
}
|
||||||
|
fn bfs(
|
||||||
|
grid: &Grid,
|
||||||
|
start: Point,
|
||||||
|
limit: Option<usize>,
|
||||||
|
cheat: bool,
|
||||||
|
visited: &mut HashMap<Point, usize>,
|
||||||
|
queue: &mut VecDeque<(Point, usize)>,
|
||||||
|
) {
|
||||||
|
visited.clear();
|
||||||
|
queue.clear();
|
||||||
|
|
||||||
|
queue.push_back((start, 0));
|
||||||
|
|
||||||
|
while let Some((p, l)) = queue.pop_front() {
|
||||||
|
if visited.contains_key(&p) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
visited.insert(p, l);
|
||||||
|
|
||||||
|
for d in Direction::CROSS {
|
||||||
|
let n = p + d;
|
||||||
|
|
||||||
|
let nv = grid.get(&n);
|
||||||
|
let uwnv = *nv.unwrap_or(&b'#');
|
||||||
|
let valid_neigh = (cheat && nv.is_some()) || uwnv == b'.';
|
||||||
|
let valid_length = l < limit.unwrap_or(usize::MAX);
|
||||||
|
let unvisited = !visited.contains_key(&n);
|
||||||
|
|
||||||
|
if valid_neigh && valid_length && unvisited {
|
||||||
|
queue.push_back((n, l + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cheat_neighbours_and_benchmark(
|
||||||
|
grid: &Grid,
|
||||||
|
start: Point,
|
||||||
|
cheat_limit: usize,
|
||||||
|
) -> HashMap<Point, Vec<(Point, usize)>> {
|
||||||
|
let mut map = HashMap::<Point, Vec<(Point, usize)>>::new();
|
||||||
|
|
||||||
|
let mut reuse_queue = VecDeque::new();
|
||||||
|
let mut reuse_visited = HashMap::new();
|
||||||
|
|
||||||
|
let mut valid_points = HashMap::new();
|
||||||
|
|
||||||
|
bfs(
|
||||||
|
grid,
|
||||||
|
start,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
&mut valid_points,
|
||||||
|
&mut reuse_queue,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (&s, _) in valid_points.iter() {
|
||||||
|
bfs(
|
||||||
|
grid,
|
||||||
|
s,
|
||||||
|
Some(cheat_limit),
|
||||||
|
true,
|
||||||
|
&mut reuse_visited,
|
||||||
|
&mut reuse_queue,
|
||||||
|
);
|
||||||
|
for (&point, &length) in reuse_visited.iter().filter(|(&p, _)| grid[p] == b'.') {
|
||||||
|
map.entry(s).or_default().push((point, length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cheated_bfs(
|
||||||
|
grid: &Grid,
|
||||||
|
start: Point,
|
||||||
|
end: Point,
|
||||||
|
cheat_limit: usize,
|
||||||
|
increase_limit: usize,
|
||||||
|
) -> usize {
|
||||||
|
let neighbours = get_cheat_neighbours_and_benchmark(grid, start, cheat_limit);
|
||||||
|
|
||||||
|
let mut reuse_queue = VecDeque::new();
|
||||||
|
|
||||||
|
let mut from_start = HashMap::new();
|
||||||
|
let mut from_end = HashMap::new();
|
||||||
|
|
||||||
|
bfs(grid, start, None, false, &mut from_start, &mut reuse_queue);
|
||||||
|
bfs(grid, end, None, false, &mut from_end, &mut reuse_queue);
|
||||||
|
|
||||||
|
let benchmark = from_start[&end];
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
for node in from_start.keys() {
|
||||||
|
for (neigh, cheat_dist) in neighbours[node].iter() {
|
||||||
|
let start_dist = from_start[node];
|
||||||
|
let end_dist = from_end[neigh];
|
||||||
|
|
||||||
|
let dist = start_dist + cheat_dist + end_dist;
|
||||||
|
if dist < benchmark && dist.abs_diff(benchmark) >= increase_limit {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_one(input: &str) -> Option<usize> {
|
||||||
|
let (grid, start, end) = parse_input(input);
|
||||||
|
cheated_bfs(&grid, start, end, 2, 100).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_two(input: &str) -> Option<usize> {
|
||||||
|
let (grid, start, end) = parse_input(input);
|
||||||
|
cheated_bfs(&grid, start, end, 20, 100).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
aoc::solution!(20);
|
|
@ -0,0 +1,157 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use cached::proc_macro::cached;
|
||||||
|
use cached::SizedCache;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
const NUMPAD: [(u8, [Option<(u8, u8)>; 4]); 11] = [
|
||||||
|
(b'0', [Some((b'2', b'^')), Some((b'A', b'>')), None, None]),
|
||||||
|
(b'1', [Some((b'2', b'>')), Some((b'4', b'^')), None, None]),
|
||||||
|
(b'2', [Some((b'0', b'v')), Some((b'1', b'<')), Some((b'3', b'>')), Some((b'5', b'^')),]),
|
||||||
|
(b'3', [Some((b'2', b'<')), Some((b'6', b'^')), Some((b'A', b'v')), None,]),
|
||||||
|
(b'4', [Some((b'1', b'v')), Some((b'5', b'>')), Some((b'7', b'^')), None,]),
|
||||||
|
(b'5', [Some((b'2', b'v')), Some((b'4', b'<')), Some((b'6', b'>')), Some((b'8', b'^')),]),
|
||||||
|
(b'6', [Some((b'3', b'v')), Some((b'5', b'<')), Some((b'9', b'^')), None,]),
|
||||||
|
(b'7', [Some((b'4', b'v')), Some((b'8', b'>')), None, None]),
|
||||||
|
(b'8', [Some((b'5', b'v')), Some((b'7', b'<')), Some((b'9', b'>')), None,]),
|
||||||
|
(b'9', [Some((b'6', b'v')), Some((b'8', b'<')), None, None]),
|
||||||
|
(b'A', [Some((b'0', b'<')), Some((b'3', b'^')), None, None]),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
const KEYPAD: [(u8, [Option<(u8, u8)>; 3]); 5] = [
|
||||||
|
(b'^', [Some((b'A', b'>')), Some((b'v', b'v')), None]),
|
||||||
|
(b'<', [Some((b'v', b'>')), None, None]),
|
||||||
|
(b'v', [Some((b'<', b'<')), Some((b'^', b'^')), Some((b'>', b'>'))]),
|
||||||
|
(b'>', [Some((b'v', b'<')), Some((b'A', b'^')), None]),
|
||||||
|
(b'A', [Some((b'^', b'<')), Some((b'>', b'v')), None]),
|
||||||
|
];
|
||||||
|
|
||||||
|
fn bfs(graph: &HashMap<u8, Vec<(u8, u8)>>, s: u8, e: u8) -> Vec<VecDeque<u8>> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
let mut queue = VecDeque::new();
|
||||||
|
let mut shortest = usize::MAX;
|
||||||
|
|
||||||
|
queue.push_back((s, VecDeque::new()));
|
||||||
|
|
||||||
|
while let Some((n, mut p)) = queue.pop_front() {
|
||||||
|
if n == e {
|
||||||
|
if shortest == usize::MAX {
|
||||||
|
shortest = p.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.len() == shortest {
|
||||||
|
p.push_back(b'A');
|
||||||
|
res.push(p);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.len() >= shortest {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (nn, c) in graph[&n].iter().copied() {
|
||||||
|
let mut np = p.clone();
|
||||||
|
np.push_back(c);
|
||||||
|
|
||||||
|
queue.push_back((nn, np));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cached(
|
||||||
|
ty = "SizedCache<String, usize>",
|
||||||
|
create = "{ SizedCache::with_size(100000) }",
|
||||||
|
convert = r#"{ format!("{sequence:?}{level}{graph}") }"#
|
||||||
|
)]
|
||||||
|
fn dfs(
|
||||||
|
graphs: &[HashMap<u8, Vec<(u8, u8)>>],
|
||||||
|
graph: usize,
|
||||||
|
mut sequence: VecDeque<u8>,
|
||||||
|
level: usize,
|
||||||
|
) -> usize {
|
||||||
|
let graph = &graphs[graph];
|
||||||
|
sequence.push_front(b'A');
|
||||||
|
let mut res = 0;
|
||||||
|
|
||||||
|
for (n1, n2) in sequence.into_iter().tuple_windows() {
|
||||||
|
let paths = bfs(graph, n1, n2);
|
||||||
|
if level == 0 {
|
||||||
|
res += paths.into_iter().map(|p| p.len()).min().unwrap();
|
||||||
|
} else {
|
||||||
|
res += paths
|
||||||
|
.into_iter()
|
||||||
|
.map(|p| dfs(graphs, 1, p, level - 1))
|
||||||
|
.min()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_graphs() -> [HashMap<u8, Vec<(u8, u8)>>; 2] {
|
||||||
|
let mut numpad = HashMap::new();
|
||||||
|
for (k, v) in NUMPAD.iter() {
|
||||||
|
numpad.insert(*k, v.iter().filter_map(|&x| x).collect_vec());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut keypad = HashMap::new();
|
||||||
|
for (k, v) in KEYPAD.iter() {
|
||||||
|
keypad.insert(*k, v.iter().filter_map(|&x| x).collect_vec());
|
||||||
|
}
|
||||||
|
|
||||||
|
[numpad, keypad]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_chain(input: &str, level: usize) -> usize {
|
||||||
|
let graphs = build_graphs();
|
||||||
|
|
||||||
|
let mut res = 0;
|
||||||
|
for line in input.lines() {
|
||||||
|
let n: usize = line.strip_suffix("A").unwrap().parse().unwrap();
|
||||||
|
let sequence = VecDeque::from_iter(line.as_bytes().iter().copied());
|
||||||
|
let min_len = dfs(&graphs, 0, sequence, level);
|
||||||
|
res += min_len * n;
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_one(input: &str) -> Option<usize> {
|
||||||
|
Some(solve_chain(input, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_two(input: &str) -> Option<usize> {
|
||||||
|
Some(solve_chain(input, 25))
|
||||||
|
}
|
||||||
|
|
||||||
|
aoc::solution!(21);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_part_one() {
|
||||||
|
assert_eq!(
|
||||||
|
part_one(&aoc::template::read_file("examples", 21)),
|
||||||
|
Some(126384)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_part_two() {
|
||||||
|
assert_eq!(
|
||||||
|
part_two(&aoc::template::read_file("examples", 21)),
|
||||||
|
Some(154115708116294)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue