Skip to main content

aoc/year2016/
day02.rs

1//! # Bathroom Security
2//!
3//! Relies heavily on the [`point`] and [`grid`] modules.
4//!
5//! [`grid`]: crate::util::grid
6//! [`point`]: crate::util::point
7use crate::util::grid::*;
8use crate::util::point::*;
9
10pub fn parse(input: &str) -> Vec<&str> {
11    input.lines().collect()
12}
13
14/// The square keypad is bounded by a square, starting on `5` in the middle.
15pub fn part1(input: &[&str]) -> String {
16    let keypad = "123\n456\n789";
17    code(input, keypad, ORIGIN, |p| p.x.abs() <= 1 && p.y.abs() <= 1)
18}
19
20/// The diamond keypad is bounded by a diamond, starting on `5` at the left.
21pub fn part2(input: &[&str]) -> String {
22    let keypad = "##1##\n#234#\n56789\n#ABC#\n##D##";
23    code(input, keypad, Point::new(-2, 0), |p| p.manhattan(ORIGIN) <= 2)
24}
25
26/// Follows the instructions with the keypad centered on the origin, pushing the key reached at
27/// the end of each line. Moves that leave the keypad are ignored.
28fn code(input: &[&str], keypad: &str, start: Point, inside: impl Fn(Point) -> bool) -> String {
29    let digits = Grid::parse(keypad);
30    // Translates from origin centered coordinates back into grid coordinates.
31    let center = Point::new(digits.width / 2, digits.height / 2);
32
33    let mut position = start;
34    let mut result = String::new();
35
36    for line in input {
37        for b in line.bytes() {
38            let next = position + Point::from(b);
39            if inside(next) {
40                position = next;
41            }
42        }
43        result.push(digits[position + center] as char);
44    }
45
46    result
47}