Today’s puzzle is one of those typical “same instructions, differing interpretations” problems AoC is so good at. This post is a literate Haskell program, let’s get the imports out of the way.

```
import Data.Complex
import Data.List
```

Parsing is dead easy. Assuming line-based instructions, I just pass the first character as-is and convert the number to a `Double`

.

```
parseInstruction :: String -> (Char,Double)
:n) = (i,read n) parseInstruction (i
```

Why a double? I’m going to use `Complex`

numbers, and in Haskell they only have a useful `Num`

instance if the underlying type implements `RealFloat`

. So `Double`

it is, even if the coordinates are only expected to take integer values.

`type C = Complex Double`

In part 1, `NESW`

mean to move the ship by the specified distance, whereas the `LRF`

series implement “turtle graphics”. So my step function maintains the ship’s position and direction.

```
go1 :: (C,C) -> (Char,Double) -> (C,C)
= case i of
go1 (pos,hdg) (i,n) 'N' -> (pos + (0 :+ n) ,hdg)
'S' -> (pos - (0 :+ n) ,hdg)
'W' -> (pos - (n :+ 0) ,hdg)
'E' -> (pos + (n :+ 0) ,hdg)
'F' -> (pos + (n :+ 0)*hdg,hdg)
'L' -> (pos ,hdg * (0 :+ 1 )^a)
'R' -> (pos ,hdg * (0 :+ (-1))^a)
where a | round n `mod` 90 == 0 = round n `div` 90
```

In part 2, a “waypoint” is introduced. Its use looks more like like a speed vector than a navigational waypoint, but let’s play along. Here the only way to move is the `F`

instruction; `NESW`

adjust the vector by addition, `LR`

by rotation.

```
go2 :: (C,C) -> (Char,Double) -> (C,C)
= case i of
go2 (pos,wpt) (i,n) 'N' -> (pos ,wpt + (0 :+ n))
'S' -> (pos ,wpt - (0 :+ n))
'W' -> (pos ,wpt - (n :+ 0))
'E' -> (pos ,wpt + (n :+ 0))
'L' -> (pos ,wpt * (0 :+ 1 )^a)
'R' -> (pos ,wpt * (0 :+ (-1))^a)
'F' -> (pos + (n :+ 0)*wpt,wpt)
where a | round n `mod` 90 == 0 = round n `div` 90
```

All that’s left is to fold the instructions, pairing the appropriate `go`

function with its starting vector.

```
main :: IO ()
= do
main <- map parseInstruction . lines <$> readFile "day12.in"
instrs let (destination1,_) = foldl' go1 (0 :+ 0, 1 :+ 0) instrs
print $ round (dist destination1)
let (destination2,_) = foldl' go2 (0 :+ 0,10 :+ 1) instrs
print $ round (dist destination2)
```

And measuring the distance to the origin by Manhattan distance, because for some reason that’s what makes sense during a storm.

```
dist :: C -> Double
:+ y) = abs x + abs y dist (x
```

This concludes today’s solution. See you soon!