-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDay01.hs
More file actions
72 lines (58 loc) · 1.88 KB
/
Copy pathDay01.hs
File metadata and controls
72 lines (58 loc) · 1.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
module Main where
import Common
import GridCoord
import Data.List
import qualified Data.Set as Set
import Text.Megaparsec
import Text.Megaparsec.Char
-- | Vectors used for incremental steps
data Vec = Vec !Int !Int
deriving (Eq, Ord, Show, Read)
data Command = Command !Char !Int
parser :: Parser [Command]
parser = (Command <$> oneOf "LDRU" <*> number) `sepBy` string ", "
main :: IO ()
main =
do cmds <- parseOrDie parser <$> readInputFile 1
let path = computePath cmds
print (part1 path)
print (part2 path)
-- | Given a list of steps determine the ultimate Manhattan-distance from
-- the starting position.
part1 :: [Coord] -> Int
part1 = manhattanDistance origin . last
part2 :: [Coord] -> Maybe Int
part2 = fmap (manhattanDistance origin) . duplicate
computePath :: [Command] -> [Coord]
computePath = toCoords origin . toSteps north
where
north = Vec 0 (-1)
-- | Find the first duplicate element in a list
duplicate :: Ord a => [a] -> Maybe a
duplicate = aux Set.empty
where
aux _ [] = Nothing
aux seen (x:xs)
| Set.member x seen = Just x
| otherwise = aux (Set.insert x seen) xs
-- | Compute steps taken by following a list of commands
toSteps ::
Vec {- ^ initial direction -} ->
[Command] {- ^ commands -} ->
[Vec] {- ^ list of directions -}
toSteps dir0 cmds = concat (snd (mapAccumL aux dir0 cmds))
where
aux dir (Command lr steps) =
let dir' = turn lr dir
in (dir', replicate steps dir')
toCoords ::
Coord {- ^ origin -} ->
[Vec] {- ^ steps -} ->
[Coord] {- ^ path -}
toCoords = scanl step
turn :: Char -> Vec -> Vec
turn 'L' (Vec dx dy) = Vec (-dy) dx
turn 'R' (Vec dx dy) = Vec dy (-dx)
turn c _ = error ("Bad instruction: " ++ [c])
step :: Coord -> Vec -> Coord
step (Coord x y) (Vec dx dy) = Coord (x + dx) (y + dy)