diff --git a/83_alt2.hs b/83_alt2.hs new file mode 100644 index 0000000..364153b --- /dev/null +++ b/83_alt2.hs @@ -0,0 +1,76 @@ +import Data.List.Split +import Data.Matrix +import Data.Maybe +import Data.Foldable +import Data.PQueue.Min + +type Value = Integer +type Distance = Integer +type Position = (Int, Int) +data MElement = MElement { + value :: Value, + visited :: Bool +} deriving (Eq, Show) +data QElement = QElement { + distance :: Distance, + position :: (Int, Int) +} deriving (Eq, Show) + +instance Ord QElement where + QElement d1 p1 <= QElement d2 p2 = d1 <= d2 + +markVisited :: Position -> Matrix MElement -> Matrix MElement +markVisited pos m = + let MElement value _ = m ! pos + in unsafeSet (MElement value True) pos m + +getNeighbour :: Matrix MElement -> Distance -> Position -> Maybe QElement +getNeighbour m dist pos@(i, j) = do + MElement val vis <- safeGet i j m + if vis then Nothing + else return $ QElement (dist + val) pos + +getNeighbours :: Matrix MElement -> QElement -> [QElement] +getNeighbours m (QElement dist (i, j)) = + catMaybes [getNeighbour m dist ((i - 1), j), + getNeighbour m dist ((i + 1), j), + getNeighbour m dist (i, (j - 1)), + getNeighbour m dist (i, (j + 1))] + +dijkstra :: Position -> Matrix MElement -> MinQueue QElement -> Distance +dijkstra p m q = + let minElement@(QElement dist pos) = findMin q + neighbours = getNeighbours m minElement + in if pos == p then dist + else dijkstra p (foldr update m neighbours) (foldr insert q neighbours) -- add neighbours to q + where update (QElement _ pos) = markVisited pos + +findShortestPathLength :: Matrix MElement -> Distance +findShortestPathLength m = + let MElement value _ = m ! (1, 1) + initialMinQ = singleton $ QElement value (1, 1) + lastPos = (nrows m, ncols m) + in dijkstra lastPos m initialMinQ + +setInitial :: Matrix MElement -> Matrix MElement +setInitial m = + let MElement v _ = m ! (1, 1) + in unsafeSet (MElement v True) (1, 1) m + +initElement :: Matrix Integer -> Position -> MElement +initElement m p = + let value = m ! p + in MElement value False + +toElementMatrix :: Matrix Integer -> Matrix MElement +toElementMatrix m = + matrix (nrows m) (ncols m) (initElement m) + +main :: IO () +main = do + contents <- readFile "p083_matrix.txt" + let listsMatrix = fmap (fmap read . (splitOn ",")) $ lines contents :: [[Integer]] + valueMatrix = fromLists listsMatrix + unvisitedMatrix = toElementMatrix valueMatrix + mtrx = setInitial unvisitedMatrix + print $ findShortestPathLength mtrx \ No newline at end of file