From 1ba42462ba0b5df94c365cf44d8f21955660eb2e Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Sun, 19 Jan 2025 22:45:51 +0000 Subject: [PATCH] progress implementing dijkstra's algorithm for path finding using quad trees --- fcore/bin-vec.sml | 21 ++++++++++++ fcore/path-finding.sml | 77 ++++++++++++++++++++++++++++++++++++++++++ oms.mlb | 2 ++ 3 files changed, 100 insertions(+) create mode 100644 fcore/path-finding.sml diff --git a/fcore/bin-vec.sml b/fcore/bin-vec.sml index 65537cc..3e45d7d 100644 --- a/fcore/bin-vec.sml +++ b/fcore/bin-vec.sml @@ -147,3 +147,24 @@ structure IntSet = fun eq (a, b) = a = b val g = Int.> end) + +structure ValSet = + MakeBinVec + (struct + type elem = {distance: int, from: char} + + (* l, e and q functions are not actually used in the ValSet + * because the IntSet is meant to contain keys while the ValSet + * is meant to contain corresponding values, like in a Map structure. + * However, it's required by the functor, + * and it is actually easy to implement so no issue. *) + + fun l ({distance = a, ...}: elem, {distance = b, ...}: elem) = + a < b + + fun eq ({distance = a, ...}: elem, {distance = b, ...}: elem) = + a = b + + fun g ({distance = a, ...}: elem, {distance = b, ...}: elem) = + a > b + end) diff --git a/fcore/path-finding.sml b/fcore/path-finding.sml new file mode 100644 index 0000000..fca92cf --- /dev/null +++ b/fcore/path-finding.sml @@ -0,0 +1,77 @@ +structure PathFinding = +struct + fun filterMinDuplicates (q, eKeys) = + let + val min = DistHeap.findMin q + in + if IntSet.contains (min, eKeys) then + let + val q = DistHeap.deleteMin q + in + filterMinDuplicates (q, eKeys) + end + else + q + end + + 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) + val {from, ...} = IntSet.sub (eVals, pos) + in + helpGetPathList (from, eID, eKeys, eVals, acc) + end + + fun getPathList (pID, eID, eKeys, eVals) = + helpGetPathList (pID, eID, eKeys, eVals, []) + + fun loop (pID, eID, platforms, platformTree, q, eKeys, eVals) = + let + (* filtering duplicates because we have no decrease-key operation *) + val q = filterMinDuplicates (q, eKeys) + val min = DistHeap.findMin q + in + if min = ~1 then + (* return empty list to signify that there is no path *) + [] + else if min = pID then + (* found path to destination so reconstruct path and return *) + getPathList (pID, eID, eKeys, eVals) + else + (* find reachable values from min in quad tree *) + let + val plat = Platform.find (min, platforms) + + fun start (pID, eID, platforms, platformTree) = + let + (* initialise data structures: the priority queue and the explored map *) + val q = DistHeap.empty + val q = DistHeap.insert ({distance = 0, id = eID}, q) + + val exploredKeys = IntSet.empty + val exploredVals = ValSet.empty + + val insPos = IntSet.findInsPos (eID, exploredKeys) + val exploredKeys = IntSet.insert (exploredKeys, eID, insPos) + + (* 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. + * *) + val eVal = {distance = 0, from = Char.fromInt eID} + val exploredVals = ValSet.insert (exploredVals, eVal, insPos) + in + loop (pID, eID, platforms, platformTree, q, eKeys, eVals) + end +end diff --git a/oms.mlb b/oms.mlb index 788e870..85078bb 100644 --- a/oms.mlb +++ b/oms.mlb @@ -11,6 +11,8 @@ fcore/quad-tree-fold.sml fcore/bin-search.sml fcore/bin-vec.sml +fcore/path-finding.sml + ann "allowVectorExps true" in