1 import Data.List (foldl') -- import the strict fold
7 type Position = (Int, Int)
9 -- the directions. See below for functions for turning
10 data Direction = North | East | South | West
11 deriving (Enum, Show, Bounded, Eq)
13 -- the currenct state of a Mowmaster
14 data Mowmaster = Mowmaster { direction :: Direction
15 , position :: Position
18 -- one instruction for the mowmaster
19 data Instruction = Forward Distance
29 instruction_text <- readFile "data/01-mowmaster.txt"
30 print $ part1 instruction_text
31 print $ part2 instruction_text
33 part1 :: String -> Int
34 part1 = length . filter (not . isComment) . lines
36 part2 :: String -> Int
37 part2 instruction_text = finalDistance $ executeAll instructions
38 where instructions = readInstructions instruction_text
39 executeAll = foldl' execute initialMowmaster
42 -- Is this line a comment?
43 isComment :: String -> Bool
44 isComment ('#':_) = True
48 -- Extract the steps from the input string.
49 readInstructions :: String -> [Instruction]
50 readInstructions = (map readInstruction) . lines
52 readInstruction :: String -> Instruction
53 readInstruction i = readInstruction' (head i) (tail i)
54 where readInstruction' 'F' s = Forward (read s)
55 readInstruction' 'C' _ = Clockwise
56 readInstruction' 'A' _ = Anticlockwise
57 readInstruction' _ t = Comment t
60 initialMowmaster = Mowmaster East (0, 0)
63 -- Calculate manhattan distance from start to this state
64 finalDistance :: Mowmaster -> Int
65 finalDistance m = (abs e) + (abs n)
66 where (e, n) = position m
70 execute :: Mowmaster -> Instruction -> Mowmaster
71 execute m (Forward s) = m {position = forward s (direction m) (position m)}
72 execute m Clockwise = m {direction = turnCW (direction m)}
73 execute m Anticlockwise = m {direction = turnACW (direction m)}
74 execute m (Comment _) = m
77 -- Move in the current direction
78 forward :: Distance -> Direction -> Position -> Position
79 forward s North (e, n) = (e, n+s)
80 forward s South (e, n) = (e, n-s)
81 forward s West (e, n) = (e-s, n)
82 forward s East (e, n) = (e+s, n)
84 -- | a `succ` that wraps
85 turnCW :: (Bounded a, Enum a, Eq a) => a -> a
86 turnCW dir | dir == maxBound = minBound
87 | otherwise = succ dir
89 -- | a `pred` that wraps
90 turnACW :: (Bounded a, Enum a, Eq a) => a -> a
91 turnACW dir | dir == minBound = maxBound
92 | otherwise = pred dir