2025-01-19 22:45:51 +00:00
|
|
|
structure PathFinding =
|
|
|
|
|
struct
|
|
|
|
|
fun filterMinDuplicates (q, eKeys) =
|
2025-01-22 18:22:34 +00:00
|
|
|
if DistVec.isEmpty q then
|
|
|
|
|
q
|
|
|
|
|
else
|
|
|
|
|
let
|
|
|
|
|
val {id = min, ...} = DistVec.findMin q
|
|
|
|
|
|
|
|
|
|
val pos = IntSet.findInsPos (min, eKeys)
|
|
|
|
|
in
|
|
|
|
|
if IntSet.contains (min, eKeys) then
|
|
|
|
|
let val q = DistVec.deleteMin q
|
|
|
|
|
in filterMinDuplicates (q, eKeys)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
q
|
|
|
|
|
end
|
2025-01-19 22:45:51 +00:00
|
|
|
|
|
|
|
|
fun helpGetPathList (curID, eID, eKeys, eVals, acc) =
|
|
|
|
|
if curID = eID then
|
|
|
|
|
(* reached starting ID of platform so return *)
|
|
|
|
|
acc
|
|
|
|
|
else
|
|
|
|
|
(* cons curID and traverse links backwards to reconstruct path *)
|
|
|
|
|
let
|
|
|
|
|
val acc = curID :: acc
|
|
|
|
|
val pos = IntSet.findInsPos (curID, eKeys)
|
2025-01-20 02:38:22 +00:00
|
|
|
|
2025-01-21 00:19:38 +00:00
|
|
|
val {from, distance, ...} = ValSet.sub (eVals, pos)
|
2025-01-19 22:45:51 +00:00
|
|
|
in
|
2025-01-20 11:17:00 +00:00
|
|
|
helpGetPathList (from, eID, eKeys, eVals, acc)
|
2025-01-19 22:45:51 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fun getPathList (pID, eID, eKeys, eVals) =
|
|
|
|
|
helpGetPathList (pID, eID, eKeys, eVals, [])
|
|
|
|
|
|
|
|
|
|
fun loop (pID, eID, platforms, platformTree, q, eKeys, eVals) =
|
2025-01-30 13:06:32 +00:00
|
|
|
if IntSet.contains (pID, eKeys) then
|
|
|
|
|
(* return path if we explored pid *)
|
|
|
|
|
getPathList (pID, eID, eKeys, eVals)
|
|
|
|
|
else
|
|
|
|
|
(* continue dijkstra's algorithm *)
|
|
|
|
|
let
|
|
|
|
|
(* filtering duplicates because we have no decrease-key operation *)
|
|
|
|
|
val q = filterMinDuplicates (q, eKeys)
|
|
|
|
|
in
|
|
|
|
|
if DistVec.isEmpty q then
|
|
|
|
|
(* return empty list to signify that there is no path *)
|
|
|
|
|
[]
|
|
|
|
|
else
|
|
|
|
|
(* find reachable values from min in quad tree *)
|
|
|
|
|
let
|
|
|
|
|
val {distance = distSoFar, id = minID, comesFrom} =
|
|
|
|
|
DistVec.findMin q
|
|
|
|
|
val plat = Platform.find (minID, platforms)
|
|
|
|
|
|
|
|
|
|
(* add explored *)
|
|
|
|
|
val insPos = IntSet.findInsPos (minID, eKeys)
|
|
|
|
|
val eKeys = IntSet.insert (eKeys, minID, insPos)
|
|
|
|
|
val eVals =
|
|
|
|
|
ValSet.insert
|
|
|
|
|
(eVals, {distance = distSoFar, from = comesFrom}, insPos)
|
|
|
|
|
|
|
|
|
|
(* on each loop, increment distSoFar by 15.
|
|
|
|
|
* Result: paths that require jumps to fewer platforms are
|
|
|
|
|
* incentivised a little bit. *)
|
|
|
|
|
val env =
|
|
|
|
|
{ platforms = platforms
|
|
|
|
|
, currentPlat = plat
|
|
|
|
|
, eKeys = eKeys
|
|
|
|
|
, distSoFar = distSoFar + 15
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(* fold over quad tree, updating any distances
|
|
|
|
|
* we find the shortest path for *)
|
|
|
|
|
val (eVals, q) =
|
|
|
|
|
BuildGraph.start (plat, env, (eVals, q), platformTree)
|
|
|
|
|
in
|
|
|
|
|
loop (pID, eID, platforms, platformTree, q, eKeys, eVals)
|
|
|
|
|
end
|
|
|
|
|
end
|
2025-01-19 22:45:51 +00:00
|
|
|
|
|
|
|
|
fun start (pID, eID, platforms, platformTree) =
|
|
|
|
|
let
|
|
|
|
|
(* initialise data structures: the priority queue and the explored map *)
|
2025-01-22 18:22:34 +00:00
|
|
|
val q = DistVec.fromList [{distance = 0, id = eID, comesFrom = eID}]
|
2025-01-19 22:45:51 +00:00
|
|
|
|
2025-01-20 02:38:22 +00:00
|
|
|
(* explored keys and values *)
|
2025-01-20 01:25:09 +00:00
|
|
|
val eKeys = IntSet.empty
|
|
|
|
|
val eVals = ValSet.empty
|
2025-01-19 22:45:51 +00:00
|
|
|
|
2025-01-20 02:38:22 +00:00
|
|
|
(* important: starting node will have a key that points to itself.
|
|
|
|
|
* For example, if starting node is #"e", then the record will say
|
|
|
|
|
* the "from" field is #"e".
|
|
|
|
|
* This is different from the other nodes, where the "from" field
|
|
|
|
|
* will be the ID of the previous node which led to the current one.
|
|
|
|
|
* This is our terminating condition when reconstructing paths:
|
|
|
|
|
* If the key matching this value is the same as the "from" node,
|
|
|
|
|
* then we're done reconstructing the path and can return the path list.
|
|
|
|
|
* *)
|
2025-01-19 22:45:51 +00:00
|
|
|
in
|
|
|
|
|
loop (pID, eID, platforms, platformTree, q, eKeys, eVals)
|
|
|
|
|
end
|
|
|
|
|
end
|