e7a4f4bacf3770fe7192a9296eaa84dafa58b2a1
[summerofcode2018soln.git] / src / task1 / task1.hs
1 import Data.List (foldl') -- import the strict fold
2
3 -- number of steps
4 type Distance = Int
5
6 -- easting, northing
7 type Position = (Int, Int)
8
9 -- the directions. See below for functions for turning
10 data Direction = North | East | South | West
11 deriving (Enum, Show, Bounded, Eq)
12
13 -- the currenct state of a Mowmaster
14 data Mowmaster = Mowmaster { direction :: Direction
15 , position :: Position
16 } deriving (Show, Eq)
17
18 -- one instruction for the mowmaster
19 data Instruction = Forward Distance
20 | Clockwise
21 | Anticlockwise
22 | Comment String
23 deriving (Show, Eq)
24
25
26
27 main :: IO ()
28 main = do
29 instruction_text <- readFile "data/01-mowmaster.txt"
30 print $ part1 instruction_text
31 print $ part2 instruction_text
32
33 part1 :: String -> Int
34 part1 = length . filter (not . isComment) . lines
35
36 part2 :: String -> Int
37 part2 instruction_text = finalDistance $ executeAll instructions
38 where instructions = readInstructions instruction_text
39 executeAll = foldl' execute initialMowmaster
40
41
42 -- Is this line a comment?
43 isComment :: String -> Bool
44 isComment ('#':_) = True
45 isComment _ = False
46
47
48 -- Extract the steps from the input string.
49 readInstructions :: String -> [Instruction]
50 readInstructions = (map readInstruction) . lines
51
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
58
59
60 initialMowmaster = Mowmaster North (0, 0)
61
62
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
67
68
69 -- Make one move
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
75
76
77 -- Move in the current direction
78 forward :: Int -> 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)
83
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
88
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