use std::collections::HashMap; #[path = "../lib.rs"] mod lib; #[derive(Eq, Hash, PartialEq, Clone, Copy)] enum Dir { Left, Down, Right, Up, A, } fn get_pos_dir(v: Dir) -> (usize, usize) { return match v { Dir::Left => (0, 0), Dir::Down => (1, 0), Dir::Right => (2, 0), Dir::Up => (1, 1), Dir::A => (2, 1), }; } fn get_pos_numeric(v: u8) -> (usize, usize) { return match v { b'0' => (1, 1), b'A' => (2, 1), b'1' => (0, 2), b'2' => (1, 2), b'3' => (2, 2), b'4' => (0, 3), b'5' => (1, 3), b'6' => (2, 3), b'7' => (0, 4), b'8' => (1, 4), b'9' => (2, 4), _ => unreachable!(), }; } fn press(x1: usize, y1: usize, x2: usize, y2: usize, steps: usize, cache: &mut HashMap<(Dir, Dir, usize), usize>) -> usize { let mut count1 = 0; let mut count2 = 0; if x2 == 0 && y1 == 1 { count1 = usize::MAX; } else { let mut pos = Dir::A; for _ in x1..x2 { count1 += press_dir(Dir::Right, pos, steps - 1, cache); pos = Dir::Right; } for _ in x2..x1 { count1 += press_dir(Dir::Left, pos, steps - 1, cache); pos = Dir::Left; } for _ in y1..y2 { count1 += press_dir(Dir::Up, pos, steps - 1, cache); pos = Dir::Up; } for _ in y2..y1 { count1 += press_dir(Dir::Down, pos, steps - 1, cache); pos = Dir::Down; } count1 += press_dir(Dir::A, pos, steps - 1, cache); } if x1 == 0 && y2 == 1 { count2 = usize::MAX; } else { let mut pos = Dir::A; for _ in y1..y2 { count2 += press_dir(Dir::Up, pos, steps - 1, cache); pos = Dir::Up; } for _ in y2..y1 { count2 += press_dir(Dir::Down, pos, steps - 1, cache); pos = Dir::Down; } for _ in x1..x2 { count2 += press_dir(Dir::Right, pos, steps - 1, cache); pos = Dir::Right; } for _ in x2..x1 { count2 += press_dir(Dir::Left, pos, steps - 1, cache); pos = Dir::Left; } count2 += press_dir(Dir::A, pos, steps - 1, cache); } return count1.min(count2); } fn press_dir(button: Dir, prev: Dir, steps: usize, cache: &mut HashMap<(Dir, Dir, usize), usize>) -> usize { if steps == 0 { return 1; } else if let Some(count) = cache.get(&(button, prev, steps)) { return *count; } else { let (x1, y1) = get_pos_dir(prev); let (x2, y2) = get_pos_dir(button); let count = press(x1, y1, x2, y2, steps, cache); cache.insert((button, prev, steps), count); return count; } } fn get_sequence(code: &str, steps: usize, cache: &mut HashMap<(Dir, Dir, usize), usize>) -> usize { let mut pos = b'A'; let mut count = 0; for b in code.bytes() { let (x1, y1) = get_pos_numeric(pos); let (x2, y2) = get_pos_numeric(b); count += press(x1, y1, x2, y2, steps, cache); pos = b; } return count; } fn main() { let mut sum1 = 0; let mut sum2 = 0; let mut cache = HashMap::new(); for line in lib::iter_input() { let value = line[..line.len() - 1].parse::().unwrap(); sum1 += get_sequence(&line, 2 + 1, &mut cache) * value; sum2 += get_sequence(&line, 25 + 1, &mut cache) * value; } println!("part1: {}", sum1); println!("part2: {}", sum2); }