1
1
import Data.Map qualified as M
2
2
import Data.Set qualified as S
3
- import Data.Maybe (fromJust , fromMaybe )
4
- import Data.List (find )
5
-
6
- -- A variation of 17.hs that shows the discovered path
3
+ import Control.Arrow ((&&&) )
7
4
8
5
main :: IO ()
9
- main = interact $ unlines . ( \ grid -> concat [ p1 grid, p2 grid] ) . parse
6
+ main = interact $ ( ++ " \n " ) . show . ( p1 &&& p2) . parse
10
7
11
8
type Node = (Int , Int )
12
9
data Grid a = Grid { items :: M. Map Node a , lastNode :: Node }
13
10
11
+ parse :: String -> Grid Int
12
+ parse s = Grid { items = M. fromList xs, lastNode = fst (last xs) }
13
+ where xs = [((x, y), read [c]) | (y, l) <- enum (lines s), (x, c) <- enum l]
14
+
15
+ enum :: [a ] -> [(Int , a )]
16
+ enum = zip [0 .. ]
17
+
14
18
data Direction = L | R | U | D deriving (Eq , Ord )
15
19
data Cell = Cell {
16
20
node :: Node , direction :: Direction ,
@@ -20,13 +24,6 @@ data Cell = Cell {
20
24
21
25
data Neighbour = Neighbour { cell :: Cell , distance :: Int }
22
26
23
- parse :: String -> Grid Int
24
- parse s = Grid { items = M. fromList xs, lastNode = fst (last xs) }
25
- where xs = [((x, y), read [c]) | (y, l) <- enum (lines s), (x, c) <- enum l]
26
-
27
- enum :: [a ] -> [(Int , a )]
28
- enum = zip [0 .. ]
29
-
30
27
neighbours :: Grid Int -> [Int ] -> Cell -> [Neighbour ]
31
28
neighbours Grid { items } range = filter inRange . adjacent
32
29
where
@@ -50,29 +47,28 @@ neighbours Grid { items } range = filter inRange . adjacent
50
47
_ -> (d, xs)
51
48
inRange Neighbour { cell } = moves cell `elem` range
52
49
53
- -- Find the shortest path from start to an end using Dijkstra's algorithm.
54
- dijkstra :: Grid Int -> Node -> (Cell -> Bool ) -> [Int ] -> (Maybe Int , [String ])
55
- dijkstra grid@ Grid { items } start isEnd range =
56
- go (M. singleton startCell 0 ) M. empty S. empty (singleton (0 , startCell))
50
+ shortestPath :: [Int ] -> Grid Int -> Int
51
+ shortestPath moveRange grid@ Grid { items, lastNode } =
52
+ go (M. singleton startCell 0 ) S. empty (singleton (0 , startCell))
57
53
where
58
54
-- By setting moves to 0, the starting cell's considers both the left and
59
55
-- down neighbours as equivalent (which is what we want).
60
- startCell = Cell { node = start , direction = L , moves = 0 }
61
-
62
- go ds parent seen q = case extractMin q of
63
- Nothing -> ( Nothing , [] )
64
- Just ((du, u), q')
65
- | isEnd u -> ( Just du, showDistanceMap grid ds parent u range )
66
- | u `S.member` seen -> go ds parent seen q'
67
- | otherwise ->
68
- let adj = neighbours grid range u
69
- (ds', parent', q'') = foldl (relax u du) (ds, parent , q') adj
70
- in go ds' parent ' (S. insert u seen) q''
71
-
72
- relax u du (ds, parent, q) Neighbour { cell = v, distance = d } =
56
+ startCell = Cell { node = ( 0 , 0 ) , direction = L , moves = 0 }
57
+ isEnd Cell { node } = node == lastNode
58
+
59
+ go ds seen q = case extractMin q of
60
+ Nothing -> 0
61
+ Just (( du, u), q' )
62
+ | isEnd u -> du
63
+ | S. member u seen -> go ds seen q'
64
+ | otherwise -> let adj = neighbours grid moveRange u
65
+ (ds', q'') = foldl (relax u du) (ds, q') adj
66
+ in go ds' (S. insert u seen) q''
67
+
68
+ relax u du (ds, q) Neighbour { cell = v, distance = d } =
73
69
let d' = du + d in case M. lookup v ds of
74
- Just dv | dv < d' -> (ds, parent, q)
75
- _ -> (M. insert v d' ds, M. insert v u parent, insert (d', v) q)
70
+ Just dv | dv < d' -> (ds, q)
71
+ _ -> (M. insert v d' ds, insert (d', v) q)
76
72
77
73
data Heap a = Empty | Heap a (Heap a ) (Heap a )
78
74
@@ -93,30 +89,6 @@ singleton x = Heap x Empty Empty
93
89
insert :: Ord a => a -> Heap a -> Heap a
94
90
insert x h = singleton x `union` h
95
91
96
- showDistanceMap :: Grid a -> M. Map Cell Int -> M. Map Cell Cell -> Cell -> [Int ] -> [String ]
97
- showDistanceMap Grid { lastNode = (mx, my) } ds parent end range = map line [0 .. my]
98
- where
99
- path = retrace S. empty end
100
- where retrace s n = let s' = S. insert n s in case M. lookup n parent of
101
- Nothing -> s'
102
- Just p -> retrace s' p
103
- isOnPath cell = S. member cell path
104
- line y = unwords $ map dist [0 .. mx]
105
- where dist x = showCell $ find isOnPath [
106
- Cell {node = (x, y), direction = d, moves }
107
- | d <- [L , R , U , D ], moves <- range]
108
- showCell Nothing = " . "
109
- showCell (Just cell@ Cell { node, moves }) =
110
- " " ++ d ++ " " ++ show moves ++ " "
111
- where d = pad3 $ show $ fromJust $ M. lookup cell ds
112
- pad3 s = reverse $ take 3 (reverse (" " ++ s))
113
-
114
- p1 , p2 :: Grid Int -> [String ]
115
- p1 grid = runP grid [1 .. 3 ]
116
- p2 grid = runP grid [4 .. 10 ]
117
-
118
- runP :: Grid Int -> [Int ] -> [String ]
119
- runP grid range = let (r, zs) = dijkstra grid (0 , 0 ) isEnd range
120
- in zs ++ [" shortest-path result " ++ (show $ fromMaybe (- 1 ) r)]
121
- where
122
- isEnd Cell { node } = node == (lastNode grid)
92
+ p1 , p2 :: Grid Int -> Int
93
+ p1 = shortestPath [1 .. 3 ]
94
+ p2 = shortestPath [4 .. 10 ]
0 commit comments