this post was submitted on 21 Dec 2024
7 points (88.9% liked)

Advent Of Code

995 readers
6 users here now

An unofficial home for the advent of code community on programming.dev!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

AoC 2024

Solution Threads

M T W T F S S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 1 year ago
MODERATORS
 

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

you are viewing a single comment's thread
view the rest of the comments
[–] CameronDev 1 points 1 week ago

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