1 import Data.List (foldl') -- import the strict fold
5 type Position = (Int, Int)
7 -- the directions. See below for functions for turning
8 data Direction = North | East | South | West
9 deriving (Enum, Show, Bounded, Eq)
11 -- direction, easting, northing
12 data Mowmaster = Mowmaster { direction :: Direction
13 , position :: Position
16 -- one instruction for the mowmaster
17 data Instruction = Forward Distance
27 instruction_text <- readFile "data/01-mowmaster.txt"
28 print $ part1 instruction_text
29 print $ part2 instruction_text
31 part1 :: String -> Int
32 part1 = length . filter (not . isComment) . lines
34 part2 :: String -> Int
35 part2 instruction_text = finalDistance $ executeAll instructions
36 where instructions = readInstructions instruction_text
37 executeAll = foldl' execute initialMowmaster
40 -- Is this line a comment?
41 isComment :: String -> Bool
42 isComment ('#':_) = True
46 -- Extract the steps from the input string.
47 readInstructions :: String -> [Instruction]
48 readInstructions = (map readInstruction) . lines
50 readInstruction :: String -> Instruction
51 readInstruction i = readInstruction' (head i) (tail i)
52 where readInstruction' 'F' s = Forward (read s)
53 readInstruction' 'C' _ = Clockwise
54 readInstruction' 'A' _ = Anticlockwise
55 readInstruction' _ t = Comment t
58 initialMowmaster = Mowmaster North (0, 0)
61 -- Calculate manhattan distance from start to this state
62 finalDistance :: Mowmaster -> Int
63 finalDistance m = (abs e) + (abs n)
64 where (e, n) = position m
68 execute :: Mowmaster -> Instruction -> Mowmaster
69 execute m (Forward s) = m {position = forward s (direction m) (position m)}
70 execute m Clockwise = m {direction = turnCW (direction m)}
71 execute m Anticlockwise = m {direction = turnACW (direction m)}
72 execute m (Comment _) = m
75 -- Move in the current direction
76 forward :: Int -> Direction -> Position -> Position
77 forward s North (e, n) = (e, n+s)
78 forward s South (e, n) = (e, n-s)
79 forward s West (e, n) = (e-s, n)
80 forward s East (e, n) = (e+s, n)
82 -- | a `succ` that wraps
83 turnCW :: (Bounded a, Enum a, Eq a) => a -> a
84 turnCW dir | dir == maxBound = minBound
85 | otherwise = succ dir
87 -- | a `pred` that wraps
88 turnACW :: (Bounded a, Enum a, Eq a) => a -> a
89 turnACW dir | dir == minBound = maxBound
90 | otherwise = pred dir