diff --git a/cabal.project b/cabal.project index 16c0dc1..52eaf81 100644 --- a/cabal.project +++ b/cabal.project @@ -8,4 +8,4 @@ packages: source-repository-package type: git location: https://github.com/glguy/intcode - tag: 1a9daae346eb458065c1926e60e89d5c43856607 \ No newline at end of file + tag: ba1799a40b6f9efbf4d53bfe871802cee0000bce diff --git a/solutions/src/2024/16.hs b/solutions/src/2024/16.hs index f411517..9d6e05c 100644 --- a/solutions/src/2024/16.hs +++ b/solutions/src/2024/16.hs @@ -83,51 +83,47 @@ import Advent.Search (fillN) main :: IO () main = do input <- getInputArray 2024 16 - let start:_ = [p | (p,'S') <- assocs input] - end :_ = [p | (p,'E') <- assocs input] - open = amap ('#' /=) input + let start = head [p | (p,'S') <- assocs input] + end = head [p | (p,'E') <- assocs input] + open = amap ('#' /=) input step (p,v) = [(1000, (p, turnRight v))] ++ [(1000, (p, turnLeft v))] ++ [( 1, (p', v)) | let p' = p + v, open ! p'] isEnd (p, _) = p == end - (cost, preds) = shortestPath (start, east) step isEnd - nodesOnShortestPaths - = Set.map fst - $ fillN (preds Map.!) - [(end,v) | v <- [north, east, south, west], Map.member (end, v) preds] - - -- putStr (drawPicture (Map.fromList ([(n, '!') | n <- Set.elems nodesOnShortestPaths] <> assocs input))) + (cost, ends, preds) = shortestPath (start, east) step isEnd + nodesOnShortestPaths = Set.map fst (fillN (preds Map.!) ends) print cost print (length nodesOnShortestPaths) --- | Main loop for a shortest-path implementation that computes the cost of the shortest path +-- | Main loop for a shortest-path implementation that computes the cost of the shortest path. shortestPath :: Ord a => - a {- ^ initial node -} -> - (a -> [(Int, a)]) {- ^ successors of a node -} -> - (a -> Bool) {- ^ predicate for the destination -} -> - (Int, Map a [a]) {- ^ cost of shortest path to end and predecessors of all shortest paths -} + a {- ^ initial node -} -> + (a -> [(Int, a)]) {- ^ successors of a node -} -> + (a -> Bool) {- ^ predicate for the destination -} -> + (Int, [a], Map a [a]) {- ^ cost, reached end states, predecessors -} shortestPath start step isEnd = go Map.empty (IntMap.singleton 0 (Map.singleton start [])) where + addWork q (k, v) = IntMap.insertWith (Map.unionWith (++)) k v q go seen q = case IntMap.minViewWithKey q of Nothing -> error "no solution" Just ((cost, states), q1) - | done -> (cost, seen') - | otherwise -> go seen' q2 + | null done -> go seen' q2 + | otherwise -> (cost, done, seen') where -- remove all the states at this cost that we've seen at a lower cost states' = Map.difference states seen -- look for states that have reached the target - done = any isEnd (Map.keys states') + done = filter isEnd (Map.keys states') -- mark all the new states at this cost as seen so we don't revisit them again seen' = Map.union seen states' -- queue up all the successor states to be visited in the future - q2 = foldl (\m (k,v) -> IntMap.insertWith (Map.unionWith (++)) k v m) q1 + q2 = foldl addWork q1 [(cost + amt, Map.singleton next [cur]) | cur <- Map.keys states', (amt, next) <- step cur]