071fe68f3d1310f88b1f35e42c83cbee92e9ae41
[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 type Position = (Int, Int)
6
7 -- the directions. See below for functions for turning
8 data Direction = North | East | South | West
9 deriving (Enum, Show, Bounded, Eq)
10
11 -- direction, easting, northing
12 data Mowmaster = Mowmaster { direction :: Direction
13 , position :: Position
14 } deriving (Show, Eq)
15
16 -- one instruction for the mowmaster
17 data Instruction = Forward Distance
18 | Clockwise
19 | Anticlockwise
20 | Comment String
21 deriving (Show, Eq)
22
23
24
25 main :: IO ()
26 main = do
27 instruction_text <- readFile "data/01-mowmaster.txt"
28 print $ part1 instruction_text
29 print $ part2 instruction_text
30
31 part1 :: String -> Int
32 part1 = length . filter (not . isComment) . lines
33
34 part2 :: String -> Int
35 part2 instruction_text = finalDistance $ executeAll instructions
36 where instructions = readInstructions instruction_text
37 executeAll = foldl' execute initialMowmaster
38
39
40 -- Is this line a comment?
41 isComment :: String -> Bool
42 isComment ('#':_) = True
43 isComment _ = False
44
45
46 -- Extract the steps from the input string.
47 readInstructions :: String -> [Instruction]
48 readInstructions = (map readInstruction) . lines
49
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
56
57
58 initialMowmaster = Mowmaster North (0, 0)
59
60
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
65
66
67 -- Make one move
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
73
74
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)
81
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
86
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