# Advent of Code 2016 - Day 2 - Bathroom Security

On the second day of Advent of Code 2016 we are asked to work out what a bathroom code is based on the supplied instructions.

### Part 1

For part one we are required to follow our input (instructions UDLR per keycode) based on a 3x3 1-9 keypad. We begin by generating a dictionary lookup of the supplied keypad based on x, y cordinates to their related key. In a similiar mannor to how we used Complex numbers to represent x, y coordinates in the previous solution, we will be doing the same here.

``````def generate_keypad(input):
return {complex(x, y): key
for y, line in enumerate(input.splitlines())
for x, key in enumerate(line.split())
if key != '.'}
``````

So as to correctly handle any intentional whitespace going forward we will represent this intent using a `.`. From here, we can then create a function which will take in the keypad, along with the initial key position and instructions and return the resulting keycode.

``````DIRECTIONS = {'U': 0+-1j, 'D': 0+1j, 'L': -1+0j, 'R': 1+0j}

pos = next(pos for pos, key in keypad.items() if key == initial_key)
code = ''

for instruction in instructions:
for direction in instruction:
if ((next_pos := pos + DIRECTIONS[direction]) in keypad):
pos = next_pos

return code
``````

Using an assignment expression we are able to succinctly express that we only wish to apply positional moves that are within the supplied keypad bounds. Once we have exhausted the given code instructions directions we append this to the resulting code. Finally, we return the complete code to the callee.

With these building block in-place we can compose them together to produce the desired answer ðŸŒŸ.

``````def part1(input):
4 5 6
7 8 9""")

``````

### Part 2

For part two we are required to instead discern what the keycode will be based on a revised keypad. Fortunatly, based on the building blocks we already have in-place we can simply update the `generate_keypad` argument. In doing so we produce the answer we desire to complete part two ðŸŒŸ.

``````def part2(input):
. 2 3 4 .
5 6 7 8 9
. A B C .
. . D . .""")

``````

### Alternative Solution

Instead of representing the coordinate as a Complex number, I additionally explored creating a more aptly modelled value object which managed this state in an immutable manor. Using Data Classes and the `__add__` dunder method I was able to design the following:

``````@dataclass(frozen=True)
class Point2D:
x: int
y: int

if not isinstance(other, Point2D):
return NotImplemented
return Point2D(self.x + other.x, self.y + other.y)
``````

The only other aspects of the original solution that required modification were in the instantiation of these objects.

``````DIRECTIONS = {'U': Point2D(0, -1), 'D': Point2D(0, 1),
'L': Point2D(-1, 0), 'R': Point2D(1, 0)}