use std::fs; fn solve_part1(lines: &Vec<&str>) -> String { let mut result = String::new(); let mut num = 5; for line in lines { for c in line.chars() { num = match c { 'U' => if num - 3 > 0 { num - 3 } else { num }, 'D' => if num + 3 < 10 { num + 3 } else { num }, 'L' => if num % 3 != 1 { num - 1 } else { num }, 'R' => if num % 3 != 0 { num + 1 } else { num }, _ => num, // shouldn't happen } } result.push_str(&num.to_string()); } result } fn solve_part2(lines: &Vec<&str>) -> String { let mut result = String::new(); // Part 2's keypad is a bit more exotic let keypad = [ [0, 0, 1, 0, 0], [0, 2, 3, 4, 0], [5, 6, 7, 8, 9], [0, 10, 11, 12, 0], [0, 0, 13, 0, 0], ]; let mut pos = (2, 0); // (row, col) index for line in lines { for c in line.chars() { let mut new = pos; match c { 'U' => new.0 = if pos.0 > 0 { pos.0 - 1 } else { pos.0 }, 'D' => new.0 = if pos.0 < 4 { pos.0 + 1 } else { pos.0 }, 'L' => new.1 = if pos.1 > 0 { pos.1 - 1 } else { pos.1 }, 'R' => new.1 = if pos.1 < 4 { pos.1 + 1 } else { pos.1 }, _ => {}, // shouldn't happen }; // Ignore this `c' if it would take us off the diamond's edge if keypad[new.0][new.1] != 0 { pos = new; } } // Print as hexadecimal to follow puzzle description result.push_str(&format!("{:X}", keypad[pos.0][pos.1])); } result } fn main() { // Read directions from input text file let input = fs::read_to_string("input.txt").unwrap(); let lines = input.lines().collect(); // Part 1 gives 74921 for me println!("Part 1 solution: {}", solve_part1(&lines)); // Part 2 gives A6B35 for me println!("Part 2 solution: {}", solve_part2(&lines)); } #[cfg(test)] mod tests { use super::*; #[test] fn part1_example1() { let lines = vec!["ULL", "RRDDD", "LURDL", "UUUUD"]; assert_eq!(solve_part1(&lines), "1985"); } #[test] fn part2_example1() { let lines = vec!["ULL", "RRDDD", "LURDL", "UUUUD"]; assert_eq!(solve_part2(&lines), "5DB3"); } }