## Complex numbers for planar geometry

Once again, I’m enjoying solving Eric Wastl’s excellent Advent of Code puzzles.

Today, day 12 involved a ship navigating in a 2D plane. The ship follows a series of instructions taking the form of actions and values such as `F10 N3 F7 R90 F11 ...`, where, for the first part:

• actions N, S, E, W step by the value in the compass directions N, S, E, W
• actions L, R turn the ship left and right by the number of degrees specified by the value
• action F advances the ship in the direction it faces by the given value

Perhaps the most obvious way to model this is by implementing a `Point` class, with `x` and `y` values, and suitable methods to advance and rotate.

Another way is to use complex numbers, which are natively supported by Python — and many other languages. The complex plane is a 2D plane. The point `(x, y)` is represented by a single complex number `p = x + y * j`. Stepping in any direction corresponds to addition, and rotation to multiplication.

So, the instructions `N, S, E, W` map to adding complex numbers `j, -j, 1, -1`.

Quarter turns left and right map to multiplication by `j` and `-j`.

```def ship_position(instructions):
'''Return the final position of the ship after following the instructions

Instructions are a series of (action, value) pairs.
'''
ship, direction = 0, 1 # Start at the origin facing E
step = {'N':1j, 'W':-1, 'S':-1j, 'E': 1}
turn = {'R':-1j, 'L':1j}
for action, value in instructions:
if action in 'NSEW':
ship += value * step[action]
elif action in 'LR':
assert value % 90 == 0 # check rectilinear motion
direction *= turn[action] ** (value//90)
else:
assert action == 'F'
ship += value * direction
return ship

```

It’s also possible to implement the conditionals above arithmetically. We can think of each instruction advancing the ship (possibly by zero) and turning it (possibly by zero degrees).

```def ship_position(instructions):
ship, direction = 0, 1
step = {'N':1j, 'W':-1, 'S':-1j, 'E': 1}
turn = {'R':-1j, 'L':1j}
for action, value in instructions:
ship += value * (step.get(action, 0) + (action=='F') * direction)
direction *= turn.get(action, 1) ** (value//90)
return ship

```

More solutions here, and thanks again to Eric Wastl.