Add day21
This commit is contained in:
parent
0af0645dda
commit
2d3c79bf43
131
day21/Cargo.lock
generated
Normal file
131
day21/Cargo.lock
generated
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day21"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"glam",
|
||||||
|
"itertools",
|
||||||
|
"phf",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glam"
|
||||||
|
version = "0.29.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||||
|
|
||||||
|
[[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]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||||
9
day21/Cargo.toml
Normal file
9
day21/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day21"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
phf = { version = "0.11.2", features = ["macros"] }
|
||||||
|
glam = "0.29.2"
|
||||||
|
itertools = "0.13.0"
|
||||||
165
day21/src/main.rs
Normal file
165
day21/src/main.rs
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
use std::{collections::HashMap, fmt::Display, iter};
|
||||||
|
|
||||||
|
use glam::IVec2;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use phf::phf_map;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
|
enum Pad {
|
||||||
|
Keypad,
|
||||||
|
Numpad,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
|
enum Direction {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
fn to_vec(self) -> IVec2 {
|
||||||
|
match self {
|
||||||
|
Direction::Up => IVec2::new(-1, 0),
|
||||||
|
Direction::Down => IVec2::new(1, 0),
|
||||||
|
Direction::Left => IVec2::new(0, -1),
|
||||||
|
Direction::Right => IVec2::new(0, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Direction {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Direction::Up => write!(f, "^"),
|
||||||
|
Direction::Down => write!(f, "v"),
|
||||||
|
Direction::Left => write!(f, "<"),
|
||||||
|
Direction::Right => write!(f, ">"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static NUMPAD_POSITIONS: phf::Map<char, IVec2> = phf_map! {
|
||||||
|
'7' => IVec2::new(0, 0),
|
||||||
|
'8' => IVec2::new(0, 1),
|
||||||
|
'9' => IVec2::new(0, 2),
|
||||||
|
'4' => IVec2::new(1, 0),
|
||||||
|
'5' => IVec2::new(1, 1),
|
||||||
|
'6' => IVec2::new(1, 2),
|
||||||
|
'1' => IVec2::new(2, 0),
|
||||||
|
'2' => IVec2::new(2, 1),
|
||||||
|
'3' => IVec2::new(2, 2),
|
||||||
|
'0' => IVec2::new(3, 1),
|
||||||
|
'A' => IVec2::new(3, 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static KEYPAD_POSITIONS: phf::Map<char, IVec2> = phf_map! {
|
||||||
|
'^' => IVec2::new(0, 1),
|
||||||
|
'A' => IVec2::new(0, 2),
|
||||||
|
'<' => IVec2::new(1, 0),
|
||||||
|
'v' => IVec2::new(1, 1),
|
||||||
|
'>' => IVec2::new(1, 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parse(input: &str) -> Vec<String> {
|
||||||
|
input.lines().map(|l| l.to_string()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn directions(pos1: &IVec2, pos2: &IVec2) -> Vec<Vec<Direction>> {
|
||||||
|
let diff = pos2 - pos1;
|
||||||
|
let mut path_directions = vec![];
|
||||||
|
if diff.x > 0 {
|
||||||
|
path_directions.extend((0..diff.x).map(|_| Direction::Down));
|
||||||
|
} else {
|
||||||
|
path_directions.extend((0..diff.x.abs()).map(|_| Direction::Up));
|
||||||
|
}
|
||||||
|
if diff.y > 0 {
|
||||||
|
path_directions.extend((0..diff.y).map(|_| Direction::Right));
|
||||||
|
} else {
|
||||||
|
path_directions.extend((0..diff.y.abs()).map(|_| Direction::Left));
|
||||||
|
}
|
||||||
|
let reverse = path_directions.iter().rev().map(|d| d.to_owned()).collect();
|
||||||
|
if reverse == path_directions {
|
||||||
|
vec![path_directions]
|
||||||
|
} else {
|
||||||
|
vec![path_directions, reverse]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_allowed_path(pos1: &IVec2, directions: &[Direction], banned_pos: &IVec2) -> bool {
|
||||||
|
let mut pos = *pos1;
|
||||||
|
for direction in directions {
|
||||||
|
pos += direction.to_vec();
|
||||||
|
if pos == *banned_pos {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_paths(pos1: &IVec2, pos2: &IVec2, banned_pos: &IVec2) -> Vec<Vec<Direction>> {
|
||||||
|
directions(pos1, pos2)
|
||||||
|
.iter()
|
||||||
|
.filter(|d| is_allowed_path(pos1, d, banned_pos))
|
||||||
|
.map(|d| d.to_owned())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn min_length(code: &str, pads: &[Pad], cache: &mut HashMap<(String, usize), usize>) -> usize {
|
||||||
|
// credits: RubixDev
|
||||||
|
|
||||||
|
if pads.is_empty() {
|
||||||
|
return code.len();
|
||||||
|
}
|
||||||
|
if let Some(val) = cache.get(&(code.to_string(), pads.len())) {
|
||||||
|
return *val;
|
||||||
|
}
|
||||||
|
let result = std::iter::once('A')
|
||||||
|
.chain(code.chars())
|
||||||
|
.tuple_windows()
|
||||||
|
.map(|(start, end)| {
|
||||||
|
match pads[0] {
|
||||||
|
Pad::Numpad => get_paths(
|
||||||
|
NUMPAD_POSITIONS.get(&start).unwrap(),
|
||||||
|
NUMPAD_POSITIONS.get(&end).unwrap(),
|
||||||
|
&IVec2::new(3, 0),
|
||||||
|
),
|
||||||
|
Pad::Keypad => get_paths(
|
||||||
|
KEYPAD_POSITIONS.get(&start).unwrap(),
|
||||||
|
KEYPAD_POSITIONS.get(&end).unwrap(),
|
||||||
|
&IVec2::new(0, 0),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.into_iter()
|
||||||
|
.map(|dirs| dirs.iter().map(|d| d.to_string()).collect::<String>() + "A")
|
||||||
|
})
|
||||||
|
.multi_cartesian_product()
|
||||||
|
.map(|combination| {
|
||||||
|
combination
|
||||||
|
.iter()
|
||||||
|
.map(|c| min_length(c, &pads[1..], cache))
|
||||||
|
.sum::<usize>()
|
||||||
|
})
|
||||||
|
.min()
|
||||||
|
.unwrap();
|
||||||
|
cache.insert((code.to_string(), pads.len()), result);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part12(input: &[String], keypad_robot_count: usize) -> usize {
|
||||||
|
let mut cache = HashMap::new();
|
||||||
|
let pads: Vec<Pad> = iter::once(Pad::Numpad)
|
||||||
|
.chain((0..keypad_robot_count).map(|_| Pad::Keypad))
|
||||||
|
.collect();
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.map(|s| s[..s.len() - 1].parse::<usize>().unwrap() * min_length(s, &pads, &mut cache))
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input = parse(include_str!("../input.txt"));
|
||||||
|
println!("{}", part12(&input, 2));
|
||||||
|
println!("{}", part12(&input, 25));
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user