module Day12 ( Action , Inst , action , value , Program , parseProgram , State , position , heading , start , run ) where import Data.Char import Text.ParserCombinators.ReadP data Action = N | S | E | W | L | R | F deriving (Eq, Show) data Inst = Inst { action :: Action, value :: Int } deriving (Eq, Show) inst :: ReadP Inst inst = do a <- action' v <- int return $ Inst a v where int :: ReadP Int int = do digits <- munch1 isDigit return $ read digits action' :: ReadP Action action' = do a <- choice $ map char "NSEWLRF" return $ case a of 'N' -> N 'S' -> S 'E' -> E 'W' -> W 'L' -> L 'R' -> R 'F' -> F type Program = [Inst] program :: ReadP Program program = inst `sepBy1` skipSpaces parse p s = parsedResult $ readP_to_S p s where parsedResult [(a, _)] = a parsedResult (a:as) = parsedResult as parsedResult _ = error "Parser error" parseProgram = parse program data State = State { position :: (Int, Int) , heading :: Action -- This isn't "correct" } deriving (Eq, Show) start = State (0, 0) E updatePosition :: State -> ((Int -> Int), (Int -> Int)) -> State updatePosition s (deltaX, deltaY) = State np (heading s) where (x, y) = position s np = (deltaX x, deltaY y) updateHeading :: State -> Action -> State updateHeading s nh = State (position s) nh travel :: State -> Inst -> State travel s i = updatePosition s $ case i of (Inst N d) -> (id, (+) d) (Inst E d) -> ((+) d, id) (Inst S d) -> (id, (-) d) (Inst W d) -> ((-) d, id) headings = cycle [N, E, S, W] rotate h (Inst d v) = headings !! (v `div` 90) where headings = dropWhile (/= h) $ cycle $ case d of R -> [N, E, S, W] L -> [N, W, S, E] tick :: State -> Inst -> State tick s i@(Inst a v) | a == N || a == S || a == E || a == W = travel s i | a == L || a == R = updateHeading s $ rotate (heading s) i | a == F = travel s (Inst (heading s) v) run :: Program -> State run = foldl tick start