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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::char;

pub fn solve(input: &str) -> String {
  let arrangement = vec![
    vec![None, None, Some('1'), None, None],
    vec![None, Some('2'), Some('3'), Some('4'), None],
    vec![Some('5'), Some('6'), Some('7'), Some('8'), Some('9')],
    vec![None, Some('A'), Some('B'), Some('C'), None],
    vec![None, None, Some('D'), None, None],
  ];
  let mut keypad = Keypad {
    arrangement: arrangement,
    current: (0, 2),
  };

  let mut answer = String::new();
  for c in input.chars() {
    match c {
      'U' => {
        keypad.move_(Dir::Up);
      }
      'D' => {
        keypad.move_(Dir::Down);
      }
      'L' => {
        keypad.move_(Dir::Left);
      }
      'R' => {
        keypad.move_(Dir::Right);
      }
      '\n' => {
        answer.push(keypad.button());
      }
      _ => {
        unreachable!();
      }
    }
  }
  answer.push(keypad.button());
  answer
}

#[test]
fn test_solve() {
  let instructions = "ULL
RRDDD
LURDL
UUUUD";

  assert_eq!(solve(instructions), "5DB3".to_string());
}

struct Keypad {
  arrangement: Vec<Vec<Option<char>>>,
  current: (usize, usize),
}

impl Keypad {
  fn move_(&mut self, dir: Dir) {
    let (dx, dy): (isize, isize) = match dir {
      Dir::Up => (0, -1),
      Dir::Down => (0, 1),
      Dir::Left => (-1, 0),
      Dir::Right => (1, 0),
    };

    let x = (self.current.0 as isize + dx) as usize;
    let y = (self.current.1 as isize + dy) as usize;

    if self.button_at(x, y).is_some() {
      self.current = (x, y);
    }
  }

  fn button(&self) -> char {
    let (x, y) = self.current;
    self.arrangement[y][x].unwrap()
  }

  fn button_at(&self, x: usize, y: usize) -> Option<char> {
    self.arrangement.get(y).and_then(|row| row.get(x).and_then(|c| *c))
  }
}

enum Dir {
  Up,
  Down,
  Left,
  Right,
}

#[test]
fn test_keypad() {
  let arrangement = vec![
    vec!['1', '2', '3'],
    vec!['4', '5', '6'],
    vec!['7', '8', '9'],
  ]
    .iter()
    .map(|row| row.iter().map(|x| Some(*x)).collect())
    .collect();
  let mut keypad = Keypad {
    arrangement: arrangement,
    current: (1, 1),
  };

  assert_eq!(keypad.button_at(1, 1), Some('5'));
  assert_eq!(keypad.button(), '5');

  keypad.move_(Dir::Up);
  assert_eq!(keypad.button(), '2');

  keypad.move_(Dir::Up);
  assert_eq!(keypad.button(), '2');
}