-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay19.hs
73 lines (62 loc) · 2.23 KB
/
Day19.hs
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
73
module Day19
( part1
, part2
) where
import Data.Array.Unboxed (UArray, assocs, (!?))
import Data.Char (isAlpha)
import Data.Maybe (fromJust, isJust, isNothing)
import Helpers.Parsers (arrayFromString)
import Linear.V2 (V2 (..))
type Pos = V2 Int
type Maze = UArray Pos Char
data Packet = Packet
{ pos :: Pos
, dir :: Pos
, seen :: String
, counter :: Int
} deriving (Show)
left :: Pos -> Pos
left (V2 x y) = V2 y (-x)
right :: Pos -> Pos
right (V2 x y) = V2 (-y) x
runMaze1 :: Maze -> String
runMaze1 maze = reverse . seen . explore maze $ packet
where
[(start, _)] = filter isStart . assocs $ maze
isStart (V2 _ y, c) = y == 0 && c == '|'
packet = Packet start (V2 0 1) "" 0
runMaze2 :: Maze -> Int
runMaze2 maze = counter . explore maze $ packet
where
[(start, _)] = filter isStart . assocs $ maze
isStart (V2 _ y, c) = y == 0 && c == '|'
packet = Packet start (V2 0 1) "" 0
explore :: Maze -> Packet -> Packet
explore maze packet
| isNothing safePath = error "I'm all lost in the supermarket"
| path == ' ' = packet
| path `elem` "|-" = explore maze . move $ packet
| path == '+' = explore maze . move . fromJust . rotate $ packet
| isAlpha path = explore maze . move . checkMove . collect $ packet
where
safePath = maze !? pos packet
path = fromJust safePath
move p = p {pos = pos p + dir p, counter = counter p + 1}
rotate p
| null turns || length turns == 2 = Nothing
| otherwise = Just p {dir = head turns}
turns = filter canTurn [left . dir $ packet, right . dir $ packet]
canTurn d = isJust (nextStep d) && nextStep d /= Just ' '
nextStep = (maze !?) . (+ pos packet)
collect p = p {seen = path : seen packet}
checkMove p
| (dir p `elem` [V2 0 1, V2 0 (-1)]
&& fromJust (maze !? (dir p + pos p)) `elem` "+|")
|| (dir p `elem` [V2 1 0, V2 (-1) 0]
&& fromJust (maze !? (dir p + pos p)) `elem` "+-") = p
| isJust . rotate $ p = fromJust . rotate $ p
| otherwise = p
part1 :: Bool -> String -> String
part1 _ = runMaze1 . arrayFromString
part2 :: Bool -> String -> String
part2 _ = show . runMaze2 . arrayFromString