{-# Language LambdaCase, QuasiQuotes, TemplateHaskell #-}
module Main (main) where
import Advent.Coord
import Advent (format, stageTH)
import Data.List (foldl')
type Command = Either (D, Int) (T, A)
data D = DN | DS | DE | DW | DF
data T = TL | TR
data A = A90 | A180 | A270
stageTH
data Sim = Sim { Sim -> Coord
here, Sim -> Coord
vect :: !Coord }
type Update s a = (a -> a) -> (s -> s)
mapHere, mapVect :: Update Sim Coord
mapHere :: Update Sim Coord
mapHere Coord -> Coord
f Sim
s = Sim
s { here = f (here s) }
mapVect :: Update Sim Coord
mapVect Coord -> Coord
f Sim
s = Sim
s { vect = f (vect s) }
main :: IO ()
IO ()
main =
do [Either (D, Int) (T, A)]
inp <- [format|2020 12 ((@D%u|@T@A)%n)*|]
Int -> IO ()
forall a. Show a => a -> IO ()
print (Update Sim Coord -> Sim -> [Either (D, Int) (T, A)] -> Int
walk Update Sim Coord
mapHere (Coord -> Coord -> Sim
Sim Coord
origin Coord
east ) [Either (D, Int) (T, A)]
inp)
Int -> IO ()
forall a. Show a => a -> IO ()
print (Update Sim Coord -> Sim -> [Either (D, Int) (T, A)] -> Int
walk Update Sim Coord
mapVect (Coord -> Coord -> Sim
Sim Coord
origin (Int -> Coord -> Coord -> Coord
move Int
10 Coord
east Coord
north)) [Either (D, Int) (T, A)]
inp)
walk :: Update Sim Coord -> Sim -> [Command] -> Int
walk :: Update Sim Coord -> Sim -> [Either (D, Int) (T, A)] -> Int
walk Update Sim Coord
f Sim
st [Either (D, Int) (T, A)]
xs = Coord -> Coord -> Int
manhattan Coord
origin (Sim -> Coord
here ((Sim -> Either (D, Int) (T, A) -> Sim)
-> Sim -> [Either (D, Int) (T, A)] -> Sim
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (Update Sim Coord -> Sim -> Either (D, Int) (T, A) -> Sim
action Update Sim Coord
f) Sim
st [Either (D, Int) (T, A)]
xs))
action ::
Update Sim Coord ->
Sim -> Command -> Sim
action :: Update Sim Coord -> Sim -> Either (D, Int) (T, A) -> Sim
action Update Sim Coord
mapCard Sim
st = \case
Left (D
DN, Int
n) -> Update Sim Coord
mapCard (Int -> Coord -> Coord -> Coord
move Int
n Coord
north ) Sim
st
Left (D
DS, Int
n) -> Update Sim Coord
mapCard (Int -> Coord -> Coord -> Coord
move Int
n Coord
south ) Sim
st
Left (D
DE, Int
n) -> Update Sim Coord
mapCard (Int -> Coord -> Coord -> Coord
move Int
n Coord
east ) Sim
st
Left (D
DW, Int
n) -> Update Sim Coord
mapCard (Int -> Coord -> Coord -> Coord
move Int
n Coord
west ) Sim
st
Left (D
DF, Int
n) -> Update Sim Coord
mapHere (Int -> Coord -> Coord -> Coord
move Int
n (Sim -> Coord
vect Sim
st)) Sim
st
Right (T
TL, A
A90) -> Update Sim Coord
mapVect Coord -> Coord
turnLeft Sim
st
Right (T
TL,A
A270) -> Update Sim Coord
mapVect Coord -> Coord
turnRight Sim
st
Right (T
TL,A
A180) -> Update Sim Coord
mapVect Coord -> Coord
turnAround Sim
st
Right (T
TR, A
A90) -> Update Sim Coord
mapVect Coord -> Coord
turnRight Sim
st
Right (T
TR,A
A180) -> Update Sim Coord
mapVect Coord -> Coord
turnAround Sim
st
Right (T
TR,A
A270) -> Update Sim Coord
mapVect Coord -> Coord
turnLeft Sim
st
move :: Int -> Coord -> Coord -> Coord
move :: Int -> Coord -> Coord -> Coord
move Int
n Coord
v Coord
d = Int -> Coord -> Coord
scaleCoord Int
n Coord
v Coord -> Coord -> Coord
forall a. Num a => a -> a -> a
+ Coord
d