1
0
Fork 0
projecteuler/83_alt.hs

76 lines
2.5 KiB
Haskell
Raw Permalink Normal View History

import Data.List.Split
import Data.Matrix
import Data.Maybe
import Data.Foldable
import Data.PQueue.Min
2018-08-23 00:08:27 +00:00
type Value = Integer
2017-10-24 05:47:05 +00:00
type Distance = Integer
type Position = (Int, Int)
2018-08-23 00:08:27 +00:00
data MElement = MElement {
value :: Value,
2018-08-23 00:08:27 +00:00
visited :: Bool
} deriving (Eq, Show)
data QElement = QElement {
distance :: Distance,
position :: (Int, Int)
} deriving (Eq, Show)
2018-08-23 00:08:27 +00:00
instance Ord QElement where
QElement d1 p1 <= QElement d2 p2 = d1 <= d2
2018-08-23 00:08:27 +00:00
markVisited :: Position -> Matrix MElement -> Matrix MElement
markVisited pos m =
let MElement value _ = m ! pos
in unsafeSet (MElement value True) pos m
2017-10-24 05:47:05 +00:00
2018-08-23 00:08:27 +00:00
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
2017-10-24 05:47:05 +00:00
dijkstra p m q =
2018-08-23 00:08:27 +00:00
let (minElement@(QElement dist pos), newQ) = deleteFindMin q
neighbours = getNeighbours m minElement
in if pos == p then dist
else dijkstra p (foldr update m neighbours) (foldr insert newQ neighbours)
where update (QElement _ pos) = markVisited pos
2018-08-23 00:08:27 +00:00
findShortestPathLength :: Matrix MElement -> Distance
findShortestPathLength m =
2018-08-23 00:08:27 +00:00
let MElement value _ = m ! (1, 1)
initialMinQ = singleton $ QElement value (1, 1)
lastPos = (nrows m, ncols m)
2017-10-24 05:47:05 +00:00
in dijkstra lastPos m initialMinQ
2018-08-23 00:08:27 +00:00
setInitial :: Matrix MElement -> Matrix MElement
setInitial m =
2018-08-23 00:08:27 +00:00
let MElement v _ = m ! (1, 1)
in unsafeSet (MElement v True) (1, 1) m
2018-08-23 00:08:27 +00:00
initElement :: Matrix Integer -> Position -> MElement
initElement m p =
let value = m ! p
2018-08-23 00:08:27 +00:00
in MElement value False
2018-08-23 00:08:27 +00:00
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