Day 21: Keypad Conundrum
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
You are viewing a single thread.
View all comments Rust
Like many it seems, this one also broke my brain. Its basically the same as Day 19, but something about it mentally broke me.
#[cfg(test)]
mod tests {
use std::collections::HashMap;
static NUMPAD: [[char; 3]; 4] = [
['7', '8', '9'],
['4', '5', '6'],
['1', '2', '3'],
['X', '0', 'A'],
];
static DPAD: [[char; 3]; 2] = [['X', '^', 'A'], ['<', 'v', '>']];
fn valid_path(pad: &[[char; 3]], start: (isize, isize), path: &str) -> bool {
let mut pos = (start.0, start.1);
for c in path.chars() {
match c {
'^' => pos.0 -= 1,
'v' => pos.0 += 1,
'<' => pos.1 -= 1,
'>' => pos.1 += 1,
'A' => {}
_ => unreachable!(),
};
if pad[pos.0 as usize][pos.1 as usize] == 'X' {
return false;
}
}
true
}
fn move_pad(pad: &[[char; 3]], start: char, end: char) -> Vec<String> {
let mut start_coord = (0, 0);
let mut end_coord = (0, 0);
for i in 0..pad.len() {
for j in 0..3 {
if pad[i][j] == end {
end_coord = (i as isize, j as isize);
}
if pad[i][j] == start {
start_coord = (i as isize, j as isize);
}
}
}
let delta_i = end_coord.0 - start_coord.0;
let vert = match delta_i {
-3 => "^^^",
-2 => "^^",
-1 => "^",
0 => "",
1 => "v",
2 => "vv",
3 => "vvv",
_ => unreachable!(),
};
let delta_j = end_coord.1 - start_coord.1;
let horz = match delta_j {
-2 => "<<",
-1 => "<",
0 => "",
1 => ">",
2 => ">>",
_ => unreachable!(),
};
let vert_path = horz.to_string() + vert + "A";
let horz_path = vert.to_string() + horz + "A";
if !valid_path(pad, start_coord, &vert_path) {
return vec![horz_path];
}
if !valid_path(pad, start_coord, &horz_path) {
return vec![vert_path];
}
vec![vert_path, horz_path]
}
fn dpad_seq_len(p0: &str, depth: usize, cache: &mut HashMap<(String, usize), usize>) -> usize {
if depth == 0 {
return p0.len();
}
if let Some(cost) = cache.get(&(p0.to_string(), depth)) {
return *cost;
}
let mut first = 'A';
let mut length = 0;
for second in p0.chars() {
let moves = move_pad(&DPAD, first, second);
let mut min = usize::MAX;
for m in moves {
let l = dpad_seq_len(&m, depth - 1, cache);
if l < min {
min = l;
}
}
length += min;
first = second;
}
cache.insert((p0.to_string(), depth), length);
length
}
fn numpad_seq_len(
p0: &str,
depth: usize,
cache: &mut HashMap<(String, usize), usize>,
) -> usize {
let mut first = 'A';
let mut length = 0;
for second in p0.chars() {
let moves = move_pad(&NUMPAD, first, second);
let mut min = usize::MAX;
for m in moves {
let l = dpad_seq_len(&m, depth, cache);
if l < min {
min = l;
}
}
length += min;
first = second;
}
length
}
#[test]
fn test_numpad2dpad() {
let mut cache = HashMap::new();
assert_eq!(68, numpad_seq_len("029A", 2, &mut cache));
assert_eq!(60, numpad_seq_len("980A", 2, &mut cache));
assert_eq!(68, numpad_seq_len("179A", 2, &mut cache));
assert_eq!(64, numpad_seq_len("456A", 2, &mut cache));
assert_eq!(64, numpad_seq_len("379A", 2, &mut cache));
}
#[test]
fn day21_part1_test() {
let mut cache = HashMap::new();
let input = std::fs::read_to_string("src/input/day_21.txt").unwrap();
let codes = input.split('\n').collect::<Vec<&str>>();
let mut total = 0;
for code in codes {
let min_length = numpad_seq_len(code, 2, &mut cache);
println!("{code}: {min_length}");
total += min_length * code[0..3].parse::<usize>().unwrap();
}
println!("{}", total);
}
#[test]
fn day21_part2_test() {
let mut cache = HashMap::new();
let input = std::fs::read_to_string("src/input/day_21.txt").unwrap();
let codes = input.split('\n').collect::<Vec<&str>>();
let mut total = 0;
for code in codes {
let min_length = numpad_seq_len(code, 25, &mut cache);
println!("{code}: {min_length}");
total += min_length * code[0..3].parse::<usize>().unwrap();
}
println!("{}", total);
}
}