aboutsummaryrefslogtreecommitdiffstats
path: root/day15/main.hs
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2021-12-15 19:33:37 +0200
committerJan Tuomi <jans.tuomi@gmail.com>2021-12-16 11:34:44 +0200
commit16448e917d676a18d3aa9db6c4e89d5ee31379ab (patch)
treec4ca97f3872dcbf288c3e42c2f47555db243d735 /day15/main.hs
parentca42298c307a3009720d6bc93f294ae308168262 (diff)
Day 15
Diffstat (limited to 'day15/main.hs')
-rw-r--r--day15/main.hs92
1 files changed, 92 insertions, 0 deletions
diff --git a/day15/main.hs b/day15/main.hs
new file mode 100644
index 0000000..cff4233
--- /dev/null
+++ b/day15/main.hs
@@ -0,0 +1,92 @@
+module Main where
+
+import Control.Monad (foldM)
+import Data.Bifunctor (bimap, first, second)
+import Data.Char (digitToInt)
+import Data.Function (on)
+import qualified Data.List as L
+import Data.Map.Strict (Map, (!))
+import qualified Data.Map.Strict as M
+import Data.PQueue.Prio.Min (MinPQueue)
+import qualified Data.PQueue.Prio.Min as PQ
+import Debug.Trace (traceShow, traceShowId)
+import Utils
+
+type Point = (Int, Int)
+
+type Dim = (Int, Int)
+
+type WMap = Map Point Int
+
+type TMap = Map Point Int
+
+update :: WMap -> TMap -> MinPQueue Int Point -> Point -> Point -> (TMap, MinPQueue Int Point)
+update wmap tmap unvisitedPQ source target =
+ let w = wmap ! target
+ oldT = tmap ! target
+ newT = tmap ! source + w
+ in if newT < oldT
+ then (M.insert target (min oldT newT) tmap, PQ.insert newT target unvisitedPQ)
+ else (tmap, unvisitedPQ)
+
+getNeighbors :: WMap -> Point -> [Point]
+getNeighbors wmap p@(x, y) =
+ [(1, 0), (0, 1), (-1, 0), (0, -1)]
+ $> map (bimap (x +) (y +))
+ .> filter (`M.member` wmap)
+
+recurse :: Point -> WMap -> TMap -> MinPQueue Int Point -> Int
+recurse goal wmap tmap unvisitedPQ
+ | null unvisitedPQ = tmap ! goal
+ | otherwise =
+ let ((currentT, current), unvisitedPQ') = PQ.deleteFindMin unvisitedPQ
+
+ -- if currentT == tmap ! current
+ unvisitedNeighbors = getNeighbors wmap current
+ (tmap', unvisitedPQ'') =
+ L.foldl' (\(tm_, pq_) nb -> update wmap tm_ pq_ current nb) (tmap, unvisitedPQ') unvisitedNeighbors
+ in if currentT > tmap ! current
+ then recurse goal wmap tmap unvisitedPQ'
+ else recurse goal wmap tmap' unvisitedPQ''
+
+dijkstra :: Point -> WMap -> Point -> Int
+dijkstra goal costs start =
+ let initTMap = M.mapWithKey (\_ _ -> maxBound :: Int) costs $> M.adjust (const 0) start
+ initUnvisited = PQ.fromList [(0, start)]
+ in recurse goal costs initTMap initUnvisited
+
+e1 chart (xSize, ySize) =
+ let start = (0, 0)
+ goal = (xSize - 1, ySize - 1)
+ in dijkstra goal chart start
+
+e2 chart (xSize, ySize) =
+ let start = (0, 0)
+ goal = (5 * xSize - 1, 5 * ySize - 1)
+ chunks = [(cx, cy) | cx <- [0 .. 4], cy <- [0 .. 4]]
+ chart' =
+ chunks
+ $> foldr
+ ( \(cx, cy) acc ->
+ M.foldrWithKey
+ ( \(x, y) v ->
+ M.insert (x + cx * xSize, y + cy * ySize) ((v + cx + cy - 1) `mod` 9 + 1)
+ )
+ acc
+ chart
+ )
+ M.empty
+ in dijkstra goal chart' start
+
+main :: IO ()
+main =
+ do
+ contents <- getContents
+
+ let input = contents $> lines .> map (map digitToInt)
+ let dim@(xSize, ySize) = (length $ head input, length input)
+ let coords = [(x, y) | y <- [0 .. ySize - 1], x <- [0 .. xSize - 1]]
+ let chart = zip coords (concat input) $> M.fromList
+
+ e1 chart dim $> print
+ e2 chart dim $> print