200d538afd1fb1af0a401e81876003baf38fd865
[summerofcode2018soln.git] / src / task1 / task1.hs
1 import Data.List (foldl') -- import the strict fold
2
3 -- number of steps
4 type Step = Int
5 type Position = (Int, Int)
6
7 data Direction = North | East | South | West
8 deriving (Enum, Show, Bounded, Eq)
9
10 -- direction, easting, northing
11 data Mowmaster = Mowmaster { direction :: Direction
12 , position :: Position
13 } deriving (Show, Eq)
14
15 data Instruction = Forward Step
16 | Clockwise
17 | Anticlockwise
18 | Comment String
19 deriving (Show, Eq)
20
21
22
23 main :: IO ()
24 main = do
25 instruction_text <- readFile "data/01-mowmaster.txt"
26 print $ part1 instruction_text
27 print $ part2 instruction_text
28
29 part1 :: String -> Int
30 part1 = length . filter (not . isComment) . lines
31
32 part2 :: String -> Int
33 part2 instruction_text = finalDistance $ executeAll instructions
34 where instructions = readInstructions instruction_text
35 executeAll = foldl' execute initialMowmaster
36
37
38
39 -- Is this line a comment?
40 isComment :: String -> Bool
41 isComment ('#':_) = True
42 isComment _ = False
43
44
45 -- Extract the steps from the input string.
46 readInstructions :: String -> [Instruction]
47 readInstructions = (map readInstruction) . lines
48
49 readInstruction :: String -> Instruction
50 readInstruction i = readInstruction' (head i) (tail i)
51 where readInstruction' 'F' s = Forward (read s)
52 readInstruction' 'C' _ = Clockwise
53 readInstruction' 'A' _ = Anticlockwise
54 readInstruction' _ t = Comment t
55
56
57 initialMowmaster = Mowmaster North (0, 0)
58
59
60 -- Calculate manhattan distance from start to this state
61 finalDistance :: Mowmaster -> Int
62 finalDistance m = (abs e) + (abs n)
63 where (e, n) = position m
64
65
66 -- Make one move
67 execute :: Mowmaster -> Instruction -> Mowmaster
68 execute m (Forward s) = m {position = forward s (direction m) (position m)}
69 execute m Clockwise = m {direction = turnCW (direction m)}
70 execute m Anticlockwise = m {direction = turnACW (direction m)}
71 execute m (Comment _) = m
72
73 -- Move in the current direction
74 forward :: Int -> Direction -> Position -> Position
75 forward s North (e, n) = (e, n+s)
76 forward s South (e, n) = (e, n-s)
77 forward s West (e, n) = (e-s, n)
78 forward s East (e, n) = (e+s, n)
79
80
81 -- | a `succ` that wraps
82 turnCW :: (Bounded a, Enum a, Eq a) => a -> a
83 turnCW dir | dir == maxBound = minBound
84 | otherwise = succ dir
85
86 -- | a `pred` that wraps
87 turnACW :: (Bounded a, Enum a, Eq a) => a -> a
88 turnACW dir | dir == minBound = maxBound
89 | otherwise = pred dir