diff --git a/src/day21.rs b/src/day21.rs deleted file mode 100644 index 57d7595..0000000 --- a/src/day21.rs +++ /dev/null @@ -1,271 +0,0 @@ -use crate::util::maps::Direction; -use std::collections::HashMap; - -const DPADS: usize = 25; - -pub fn day21() { - let sequences: Vec = crate::input(21).lines().map(|l| l.to_string()).collect(); - - let mut memo: HashMap<(String, usize), u64> = HashMap::new(); - fn deeper(s: String, depth: usize, memo: &mut HashMap<(String, usize), u64>) -> u64 { - // if this is already in deep lut, return - if let Some(&expanded_size) = memo.get(&(s.to_string(), depth)) { - return expanded_size; - } - // if this is two characters at the end, add expanded size to deep lut, and return - if depth == 1 { - let expanded_size = expand_dpad_string(&s).len() as u64; - memo.insert((s, depth), expanded_size); - return expanded_size; - } - // otherwise 1. expand, 2. split into substrings, and 3. recur for each substring - let expanded = expand_dpad_string(&s); - // 2. get substrings split by A (but including the A characters at the end of each substring) - let substrings: Vec = expanded - .split_terminator("A") - .map(|substring| { - let mut substring = substring.to_string(); - substring.push_str("A"); - substring - }) - .collect(); - let mut total: u64 = 0; - for substring in substrings { - let final_expanded_size = deeper(substring, depth - 1, memo); - total += final_expanded_size; - } - memo.insert((s, depth), total); - total - } - - let mut complexity: u64 = 0; - for sequence in sequences.iter() { - let first_dpad_steps = expand_numpad_string(sequence); - let length = deeper(first_dpad_steps.clone(), DPADS, &mut memo); - let numeric = sequence - .chars() - .filter(|c| c.is_numeric()) - .collect::() - .parse::() - .unwrap(); - complexity += length * numeric; - } - - println!("Total Complexity: {}", complexity); -} - -fn expand_dpad_string(s: &str) -> String { - let sequence: Vec = s.chars().map(char_to_directional_keypad_index).collect(); - sequence_to_dpad_steps( - &directional_keypad(), - sequence, - char_to_directional_keypad_index('A'), - ) -} - -fn expand_numpad_string(s: &str) -> String { - let sequence: Vec = s.chars().map(char_to_numerical_keypad_index).collect(); - sequence_to_dpad_steps( - &numerical_keypad(), - sequence, - char_to_numerical_keypad_index('A'), - ) -} - -fn sequence_to_dpad_steps(keypad: &Keypad, sequence: Vec, start: usize) -> String { - let mut sequence = sequence.clone(); - sequence.insert(0, start); - - let mut total_path = "".to_string(); - - for w in sequence.windows(2) { - let best_path = shortest_paths(keypad, w[0], w[1]) - .into_iter() - // convert paths to strings - .map(|path| path.iter().map(direction_to_char).collect::()) - // get the most efficient path (there are certain arbitrary rules for efficiency) - .max_by_key(|path| efficiency_score(path.as_str())) - .unwrap(); - total_path.push_str(&best_path); - total_path.push_str("A"); - } - - total_path -} - -fn shortest_paths(keypad: &Keypad, start: usize, end: usize) -> Vec> { - fn path_costs(keypad: &Keypad, p: usize, cost_so_far: u64, costs: &mut HashMap) { - if cost_so_far < costs.get(&p).copied().unwrap_or(u64::MAX) { - costs.insert(p, cost_so_far); - } else { - return; - } - for &adjacent in keypad.adjacents(p) { - path_costs(keypad, adjacent, cost_so_far + 1, costs); - } - } - let mut costs: HashMap = HashMap::new(); - path_costs(keypad, end, 0, &mut costs); - - fn find_paths( - keypad: &Keypad, - start: usize, - costs: &HashMap, - ) -> Vec> { - if costs[&start] == 0 { - return vec![vec![]]; - } - keypad.buttons[start] - .links - .iter() - .filter(|(_, adjacent)| costs[adjacent] < costs[&start]) - .flat_map(|(&direction, &adjacent)| { - let mut paths = find_paths(keypad, adjacent, costs); - paths.iter_mut().for_each(|path| { - path.insert(0, direction); - }); - paths - }) - .collect() - } - - find_paths(keypad, start, &costs) -} - -fn efficiency_score(s: &str) -> u64 { - let repetition_score = s - .chars() - .collect::>() - .windows(2) - .filter(|w| w[0] == w[1]) - .count() as u64; - let mut order_mishaps: u64 = 0; - for ss in s.split("A") { - order_mishaps += ss.matches(">v").count() as u64; - order_mishaps += ss.matches("^<").count() as u64; - order_mishaps += ss.matches("v<").count() as u64; - order_mishaps += ss.matches(">^").count() as u64; - } - - (repetition_score << 32) | (u32::MAX as u64 - order_mishaps) -} - -struct Keypad { - buttons: Vec