Day sixteen part two

This commit is contained in:
2024-12-18 22:45:36 +01:00
parent f81b2c9e37
commit db0167b064

View File

@@ -46,41 +46,64 @@ task1 input =
let worldMap = parseFile input
rawGraph = mapToGraph worldMap
in do
--rawGraph |> wEdges |> Map.elems |> join |> showEdgesSimple |> putStrLn
worldGraph <- simplifyGraph rawGraph
worldGraph |> wEdges |> Map.elems |> join |> showEdgesSimple |> putStrLn
--return $ expectJust "No path found" $ findBestPath worldGraph [(wStart worldGraph, East)]
bestPath <- dijkstra worldGraph Map.empty (Map.singleton (wStart worldGraph, East) 0)
return $ expectJust "No path found" $ bestPath
(bestPath, _) <- dijkstra worldGraph Map.empty (Map.singleton (wStart worldGraph, East) (0, []))
return bestPath
task2 :: String -> IO IntType
task2 _ = return 2
task2 input =
let worldMap = parseFile input
rawGraph = mapToGraph worldMap
in do
(bestCost, bestPaths) <- dijkstra rawGraph Map.empty (Map.singleton (wStart rawGraph, East) (0, []))
[wEnd rawGraph] : bestPaths |> join |> Set.fromList |> length |> return
showEdgesSimple :: [Edge] -> String
showEdgesSimple [] = ""
showEdgesSimple (edge:edges) = (show $ eFrom edge) ++ " -> " ++ (show $ eTo edge) ++ ": " ++ (show $ ePrice edge) ++ "\n" ++ (showEdgesSimple edges)
dijkstra :: WorldGraph -> Map.Map (Vec2, Direction) Int -> Map.Map (Vec2, Direction) Int -> IO (Maybe Int)
dijkstra world@WorldGraph { wEdges, wEnd } done unvisited
type WasBestePreis = (Int, [(Vec2, Direction)])
dijkstra :: WorldGraph -> Map.Map (Vec2, Direction) WasBestePreis -> Map.Map (Vec2, Direction) WasBestePreis -> IO (Int, [[Vec2]])
dijkstra world@WorldGraph { wEdges, wEnd, wStart } done unvisited
| null unvisited =
[North, East, South, West] |> map (\d -> done Map.!? (wEnd, d) |> maybeToList) |> join |> minimum |> pure |> return
let bestePreis = [North, East, South, West] |> map (\d -> done Map.!? (wEnd, d) |> maybeToList) |> join |> foldr combineBestePreis (maxBound :: IntType, [])
in bestePreis |> \(p, os) -> (p, map (reconstructPath done) os |> join) |> return
| otherwise =
let ((pos, dir), cost) = findNext
let ((pos, dir), (cost, _)) = findNext
nextDone = Map.insert (pos, dir) (unvisited Map.! (pos, dir)) done
outgoing = Map.findWithDefault [] pos wEdges
unvisitedOutgoing = outgoing |> filter (\Edge { eTo, eDirTo } -> Map.notMember (eTo, eDirTo) done)
unvisitedOutgoingWithPrice = unvisitedOutgoing |> map (\e@Edge { eDirFrom, ePrice } -> (e, if dir == dOpposite eDirFrom then cost + ePrice else cost + ePrice + 1000)) :: [(Edge, IntType)]
unvisitedWithoutCurrent = Map.delete (pos, dir) unvisited
nextUnvisited = foldr (\(Edge { eTo, eDirTo }, price) -> Map.alter (pure . maybe price (min price)) (eTo, eDirTo)) unvisitedWithoutCurrent unvisitedOutgoingWithPrice
nextDone = Map.insert (pos, dir) cost done
in do
-- putStrLn $ "Processing " ++ (show pos) ++ "/" ++ (show dir)
-- print nextUnvisited
dijkstra world nextDone nextUnvisited
nextUnvisited = foldr (\(Edge { eTo, eDirTo }, price) -> Map.alter (pure . maybeCombineBestePreis (price, [(pos, dir)])) (eTo, eDirTo)) unvisitedWithoutCurrent unvisitedOutgoingWithPrice
in dijkstra world nextDone nextUnvisited
where
findNext :: ((Vec2, Direction), Int)
findNext :: ((Vec2, Direction), WasBestePreis)
findNext =
let options = unvisited |> Map.assocs
in foldr (\a@(_,aC) b@(_,bC) -> if aC < bC then a else b) (head options) (drop 1 options)
in foldr (\a@(_,(aC,_)) b@(_,(bC,_)) -> if aC < bC then a else b) (head options) (drop 1 options)
maybeCombineBestePreis :: WasBestePreis -> Maybe WasBestePreis -> WasBestePreis
maybeCombineBestePreis a Nothing = a
maybeCombineBestePreis a (Just b) = combineBestePreis a b
combineBestePreis :: WasBestePreis -> WasBestePreis -> WasBestePreis
combineBestePreis (aP, aOs) (bP, bOs)
| aP < bP = (aP, aOs)
| aP == bP = (aP, aOs ++ bOs)
| aP > bP = (bP, bOs)
reconstructPath :: Map.Map (Vec2, Direction) WasBestePreis -> (Vec2, Direction) -> [[Vec2]]
reconstructPath done cur@(curPos,_) =
case done Map.!? cur of
Nothing -> [[curPos]]
Just (_,[]) -> [[curPos]]
Just (_,os) -> map (reconstructPath done) os |> join |> map (\subPath -> curPos : subPath)
showEntries :: Show a => Show b => [(a,b)] -> String
showEntries [] = ""
showEntries ((k,v):rest) = show k ++ ": " ++ show v ++ "\n" ++ showEntries rest
findBestPath :: WorldGraph -> [(Vec2, Direction)] -> Maybe Int
findBestPath _ [] = error "Must call findBestPath with an initial position"