import Control.Exception (assert) main :: IO () main = do instructions <- getContents putStrLn (solution1 instructions) putStrLn (solution2 instructions) solution1 :: String -> String solution1 input = show (uncurry (*) (navigate (parseInstructions input))) solution2 :: String -> String solution2 input = show (uncurry (*) (navigate2 (parseInstructions input))) parseInstructions :: String -> [(Int, Int)] parseInstructions instructions = map parseLine (lines instructions) where parseLine line = case break (== ' ') line of ("forward", distance) -> (read distance, 0) ("down", distance) -> (0, read distance) ("up", distance) -> (0, (-read distance)) _ -> error "Invalid line" navigate :: [(Int, Int)] -> (Int, Int) navigate instructions = foldl1 sumTuples instructions where sumTuples :: (Int, Int) -> (Int, Int) -> (Int, Int) sumTuples (a, b) (c, d) = (a + c, b + d) navigate2 :: [(Int, Int)] -> (Int, Int) navigate2 instructions = takePosition (foldl navigate (0, 0, 0) instructions) where navigate :: (Int, Int, Int) -> (Int, Int) -> (Int, Int, Int) navigate (horz, depth, aim) (speed, dir) = (horz + speed, depth + aim * speed, aim + dir) takePosition :: (Int, Int, Int) -> (Int, Int) takePosition (x,y,_) = (x,y) -- Tests testInput1 :: String testInput1 = unlines [ "forward 5", "down 5", "forward 8", "up 3", "down 8", "forward 2" ] test1 :: String test1 = assert ((solution1 testInput1) == "150") "success" test2 :: String test2 = assert ((solution2 testInput1) == "900") "success"