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
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); } }