use std::{ collections::HashMap, hash::{Hash, Hasher}, }; use arrayvec::ArrayVec; use itertools::Itertools; fn main() -> anyhow::Result<()> { let input = std::io::stdin() .lines() .collect::, _>>()? .into_iter() .filter(|v| !v.is_empty()) .map(|v| map_input(&v)) .collect_vec(); let mut part1 = 0; let mut part2 = 0; for input in input { let code = input .iter() .filter(|v| **v != 10) .fold(0, |acc, curr| acc * 10 + (*curr as usize)); part1 += code * solve(input, 2); part2 += code * solve(input, 25); } eprintln!("{part1}"); eprintln!("{part2}"); Ok(()) } fn solve(input: [u8; 5], directional_robots: u8) -> usize { let mut out = 0; for (&a, &b) in input.iter().tuple_windows() { let buttons = inputs_for_keypad(a, b); let mut cache = HashMap::new(); out += expand_inputs(&buttons, directional_robots, directional_robots, &mut cache); } out } fn hash_buttons(v: &[Button]) -> u64 { let mut hasher = std::hash::DefaultHasher::new(); v.hash(&mut hasher); hasher.finish() } fn expand_inputs( buttons: &[Button], n: u8, max_n: u8, cache: &mut HashMap<(u64, u8), usize>, ) -> usize { let button_hash = hash_buttons(buttons); if let Some(cached) = cache.get(&(button_hash, n)) { return *cached; } if n == 0 { cache.insert((button_hash, n), buttons.len()); return buttons.len(); } let mut acc = 0; for (&a, &b) in (n != max_n) .then_some(&Button::A) .into_iter() .chain(buttons.iter()) .tuple_windows() { acc += expand_inputs(&inputs_for_robot(a, b), n - 1, max_n, cache); } cache.insert((button_hash, n), acc); acc } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] enum Button { Up, Down, Left, Right, A, } fn inputs_for_robot(a: Button, b: Button) -> ArrayVec { let mut out = ArrayVec::new(); match (a, b) { (Button::A, Button::Up) | (Button::Right, Button::Down) | (Button::Down, Button::Left) => { out.push(Button::Left); } (Button::A, Button::Right) => { out.push(Button::Down); } (Button::A, Button::Down) => { out.push(Button::Left); out.push(Button::Down); } (Button::A, Button::Left) => { out.push(Button::Down); out.push(Button::Left); out.push(Button::Left); } (Button::Up, Button::A) | (Button::Left, Button::Down) | (Button::Down, Button::Right) => { out.push(Button::Right); } (Button::Right, Button::A) => { out.push(Button::Up); } (Button::Down, Button::A) => { out.push(Button::Up); out.push(Button::Right); } (Button::Left, Button::A) => { out.push(Button::Right); out.push(Button::Right); out.push(Button::Up); } (Button::Left, Button::Up) => { out.push(Button::Right); out.push(Button::Up); } (Button::Up, Button::Left) => { out.push(Button::Down); out.push(Button::Left); } (Button::Right, Button::Up) => { out.push(Button::Left); out.push(Button::Up); } (Button::Up, Button::Right) => { out.push(Button::Down); out.push(Button::Right); } _ => {} } out.push(Button::A); out } fn inputs_for_keypad(a: u8, b: u8) -> Vec