11{-# LANGUAGE TupleSections #-}
22
3+ import Criterion.Main
34import Data.Function
45import qualified Data.IntMap as IM
56import Data.IntMap.Strict (IntMap )
@@ -12,21 +13,26 @@ type Grid = IntMap Int
1213
1314type Pt = Int
1415
16+ factor :: Int
17+ factor = 10000
18+
1519conv :: (Int , Int ) -> Pt
16- conv (x, y) = 10000 * x + y
20+ conv (x, y) = factor * x + y
1721
1822from :: Pt -> (Int , Int )
19- from n = (n `div` 10000 , n `mod` 10000 )
23+ from n = (n `div` factor , n `mod` factor )
2024
2125toGrid :: [[Int ]] -> Grid
2226toGrid = IM. fromList . concat . zipWith (\ x l -> zipWith (curry (\ ((x, a), y) -> (conv (x, y), a))) (map (x,) l) [1 .. ]) [1 .. ]
2327
28+ toGrid2 :: [[Int ]] -> Grid
2429toGrid2 = toGrid . embig
2530
2631succW :: Int -> Int
2732succW n = max ((n + 1 ) `mod` 10 ) 1
2833
29- embig l = concat $ take 5 $ iterate (map (map succW)) [concat $ take 5 (iterate (map succW) r) | r <- l]
34+ embig :: [[Int ]] -> [[Int ]]
35+ embig = concat . take 5 . iterate (map (map succW)) . map (concat . take 5 . iterate (map succW))
3036
3137{-
3238 1 function Dijkstra(Graph, source):
@@ -35,7 +41,7 @@ embig l = concat $ take 5 $ iterate (map (map succW)) [concat $ take 5 (iterate
3541 4
3642 5 for each vertex v in Graph:
3743 6 dist[v] ← INFINITY
38- 7 prev[v] ← UNDEFINED
44+ 7 # prev[v] ← UNDEFINED
3945 8 add v to Q
4046 9 dist[source] ← 0
414710
@@ -48,19 +54,19 @@ embig l = concat $ take 5 $ iterate (map (map succW)) [concat $ take 5 (iterate
485417 alt ← dist[u] + length(u, v)
495518 if alt < dist[v]:
505619 dist[v] ← alt
51- 20 prev[v] ← u
57+ 20 # prev[v] ← u
525821
53- 22 return dist[], prev[]
59+ 22 return dist[]
5460-}
5561
5662type PQueue a = IntMap [a ]
5763
58- pminView :: PQueue a -> (a , PQueue a )
64+ -- pminView :: PQueue a -> ((Key, a) , PQueue a)
5965pminView p =
6066 let Just (l, p') = IM. minViewWithKey p
6167 in case l of
6268 (_, [] ) -> pminView p
63- (k, x : xs) -> (x , if null xs then IM. delete k p' else IM. insert k xs p')
69+ (k, x : xs) -> ((k, x) , if null xs then IM. delete k p' else IM. insert k xs p')
6470
6571pins :: Int -> a -> PQueue a -> PQueue a
6672pins k x = IM. insertWith (++) k [x]
@@ -73,34 +79,36 @@ neighbors g p = IS.filter (`IM.member` g) (IS.fromList (conv <$> [(x -1, y), (x,
7379 where
7480 (x, y) = from p
7581
76- dijkstra :: IntMap Int -> Int -> ( IntMap Int , IntMap Int )
77- dijkstra g s = step1 & step2 & step3
82+ dijkstra :: Grid -> Int -> IntMap Int
83+ dijkstra g s = step1 & step2
7884 where
79- step1 = let c = IM. keysSet g; (a, b) = IS. foldl' go (mempty , mempty ) c in (a, b, c)
80- go (dv, pv) v = (dv', pv')
85+ step1 = let c = IM. keysSet g; a = IS. foldl' go mempty c in (a, c, pins 0 s pempty)
8186 where
82- dv' = IM. insert v (maxBound :: Int ) dv
83- pv' = IM. insert v (conv (0 , 0 )) pv
84- step2 (dv, pv, q) = (IM. insert s (conv (0 , 0 )) dv, pv, q)
85- step3 (dv, pv, q)
86- | IS. null q = (dv, pv)
87- | otherwise = step3 (dv', pv', q')
87+ go dv v = IM. insert v (maxBound :: Int ) dv
88+ step2 (dv, unseen, q)
89+ | IM. null q = dv
90+ | otherwise = step2 (dv', unseen', q'')
8891 where
89- q' = IS. delete u q
90- u = nextVert dv
91- (dv', pv') = IS. foldl' f (dv, pv) (IS. intersection q (neighbors g u))
92+ -- u is the closest vertex to visit
93+ ((d, u), q') = pminView q
94+ unseen' = IS. delete u unseen
95+ -- for all neighbors of u, visit it and thread the distance map and priority queue
96+ (dv', q'') = IS. foldl' visit (dv, q') (neighbors g u)
9297 where
93- f (dv, pv) v = (dv'', pv'')
98+ -- to visit a point p', make sure it's in the graph
99+ visit (dv, q') p'
100+ | p' `IM.member` g = (dv'', q'')
101+ | otherwise = (dv, q')
94102 where
95- alt = dv IM. ! u + g IM. ! v
96- (dv'', pv'') = if alt < dv IM. ! v then (IM. insert v alt dv, IM. insert v u pv) else (dv, pv)
97- nextVert :: IntMap Int -> Int
98- nextVert dv = v
99- where
100- v :: Int
101- v = fst $ IS. foldl' (\ (x, c) y -> if (dv IM. ! y) < c then (y, dv IM. ! y) else (x, c)) (undefined , maxBound :: Int ) q
103+ -- compute the new distance to p' (store into alt) and
104+ -- compare against the previous distance
105+ alt = d + g IM. ! p'
106+ -- if it's better then update distance for p' in dv to be alt
107+ (dv'', q'') = if alt < dv IM. ! p' then (IM. insert p' alt dv, pins alt p' q') else (dv, q')
102108
103- part1 (inp, n) = fst (dijkstra inp (conv (1 , 1 ))) IM. ! conv (n, n)
109+ part1 (inp, n) = dijkstra inp (conv (1 , 1 )) IM. ! conv (n, n)
110+
111+ part2 = part1
104112
105113main = do
106114 let dayNumber = 15 :: Int
@@ -110,14 +118,13 @@ main = do
110118 let x = map (map (read . pure )) . lines $ inp'
111119 let inp = toGrid x
112120 let inp2 = toGrid2 x
113- let n = length (head $ lines $ inp')
121+ let n = length (head $ lines inp')
114122 print (part1 (inp, n))
115123 print (part1 (inp2, n * 5 ))
116-
117- -- -- defaultMain
118- -- -- [ bgroup
119- -- -- dayString
120- -- -- [ bench "part1" $ whnf part1 inp,
121- -- -- bench "part2" $ whnf part2 inp
122- -- -- ]
123- -- -- ]
124+ defaultMain
125+ [ bgroup
126+ dayString
127+ [ bench " part1" $ whnf part1 (inp, n),
128+ bench " part2" $ whnf part2 (inp2, n * 5 )
129+ ]
130+ ]
0 commit comments