implement code for precomputing reachable platforms so it can be reused (but haven't modified implementation of Dijkstra's algorithm to use it, and haven't added it to game type yet)

This commit is contained in:
2025-01-31 03:46:28 +00:00
parent 0cdd81189c
commit a24ada0f37
3 changed files with 225 additions and 0 deletions

View File

@@ -213,3 +213,15 @@ structure DistVec =
fun g ({distance = a, ...}: elem, {distance = b, ...}: elem) = a > b
end)
structure PlatSet =
MakeBinVec
(struct
type elem = {distance: int, id: int}
fun l ({id = a, ...}: elem, {id = b, ...}: elem) = a < b
fun eq ({id = a, ...}: elem, {id = b, ...}: elem) = a = b
fun g ({id = a, ...}: elem, {id = b, ...}: elem) = a > b
end)

212
fcore/graph.sml Normal file
View File

@@ -0,0 +1,212 @@
structure Graph =
struct
fun insertIfNew (dist, platSet, foldPlatID) =
let
val insRecord = {id = foldPlatID, distance = dist}
val pos = PlatSet.findInsPos (insRecord, platSet)
in
if pos <> ~1 andalso pos <> Vector.length platSet then
(* platSet may already contain foldPlatID; check *)
let
val {id = key, ...} = PlatSet.sub (platSet, pos)
in
if key = foldPlatID then
(* alread contains foldPlatID so return *)
platSet
else
(* foldPlatID is new; insert it *)
PlatSet.insert (platSet, insRecord, pos)
end
else
(* foldPlatID is new; insert it *)
PlatSet.insert (platSet, insRecord, pos)
end
type env =
{platforms: GameType.platform vector, currentPlat: GameType.platform}
structure Vertical =
MakeQuadTreeFold
(struct
type env = env
type state = PlatSet.elem vector
fun fold (foldPlatID, env: env, platSet) =
let
val {platforms, currentPlat} = env
val {y = foldPlatY, ...} = Platform.find (foldPlatID, platforms)
val {y = currentPlatY, ...} = currentPlat
val newDist = abs (foldPlatY - currentPlatY)
in
insertIfNew (newDist, platSet, foldPlatID)
end
end)
structure Horizontal =
MakeQuadTreeFold
(struct
type env = env
type state = PlatSet.elem vector
fun minWidth (p1: GameType.platform, p2: GameType.platform) =
let
val {x = p1x, width = p1w, ...} = p1
val {x = p2x, width = p2w, ...} = p2
val p1fx = p1x + p1w
val p2fx = p2x + p2w
val w1 = abs (p1fx - p2fx)
val w2 = abs (p1fx - p2x)
val w3 = abs (p1x - p2x)
val w4 = abs (p1x - p2fx)
val min = Int.min (w1, w2)
val min = Int.min (min, w3)
in
Int.min (min, w4)
end
fun pythagoras (width, height) =
let
val wsq = width * width
val hsq = height * height
val hypotenuseSq = wsq + hsq
val hypSq = Real.fromInt hypotenuseSq
val hyp = Math.sqrt hypSq
in
Real.toInt IEEEReal.TO_NEAREST hyp
end
fun fold (foldPlatID, env: env, platSet) =
let
val {platforms, currentPlat} = env
val foldPlat = Platform.find (foldPlatID, platforms)
val foldPlatY = #y foldPlat
val {y = currentPlatY, ...} = currentPlat
val height = abs (foldPlatY - currentPlatY)
val width = minWidth (currentPlat, foldPlat)
val newDist = pythagoras (width, height)
in
insertIfNew (newDist, platSet, foldPlatID)
end
end)
fun traceRightDescent (x, y, platTree, env, platSet) =
if x >= Constants.worldWidth orelse y >= Constants.worldHeight then
(* we hit bounds of screen and saw that there was
* no way to jump to next nextPlatID *)
platSet
else
let
val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y
val platSet = Horizontal.foldRegion
(x, y, width, height, env, platSet, platTree)
val nextX = x + Constants.moveEnemyBy
val nextY = y + Constants.moveEnemyBy
in
traceRightDescent (nextX, nextY, platTree, env, platSet)
end
fun traceRightJumpAscent (x, y, remainingJump, platTree, env, platSet) =
if remainingJump >= Constants.jumpLimit - Constants.enemySize then
traceRightDescent (x, y, platTree, env, platSet)
else
let
val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y
val platSet = Horizontal.foldRegion
(x, y, width, height, env, platSet, platTree)
val nextX = x + Constants.moveEnemyBy
val nextY = y - Constants.moveEnemyBy
val nextJump = remainingJump + Constants.moveEnemyBy
in
traceRightJumpAscent (nextX, nextY, nextJump, platTree, env, platSet)
end
fun traceRightJump (currentPlat: GameType.platform, env, platSet, platTree) =
let
val {x, y, width, ...} = currentPlat
val x = x - Constants.enemySize + width
in
traceRightJumpAscent (x, y, 0, platTree, env, platSet)
end
fun traceLeftDescent (x, y, platTree, env, platSet) =
if x <= 0 orelse y >= Constants.worldHeight then
platSet
else
let
val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y
val platSet = Horizontal.foldRegion
(x, y, width, height, env, platSet, platTree)
val nextX = x - Constants.moveEnemyBy
val nextY = y + Constants.moveEnemyBy
in
traceLeftDescent (nextX, nextY, platTree, env, platSet)
end
fun traceLeftJumpAscent (x, y, remainingJump, platTree, env, platSet) =
if remainingJump >= Constants.jumpLimit - Constants.enemySize then
traceLeftDescent (x, y, platTree, env, platSet)
else
let
val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y
val platSet = Horizontal.foldRegion
(x, y, width, height, env, platSet, platTree)
val nextX = x - Constants.moveEnemyBy
val nextY = y - Constants.moveEnemyBy
val nextJump = remainingJump + Constants.moveEnemyBy
in
traceLeftJumpAscent (nextX, nextY, nextJump, platTree, env, platSet)
end
fun traceLeftJump (currentPlat: GameType.platform, env, platSet, platTree) =
let
val {x, y, ...} = currentPlat
val x = x + Constants.enemySize
in
traceLeftJumpAscent (x, y, 0, platTree, env, platSet)
end
fun start (currentPlat: GameType.platform, env: env, platSet, platformTree) =
let
val {x, y, width, ...} = currentPlat
(* calculate area to search in y axis *)
val searchY = y - Constants.jumpLimit
val height = Constants.worldHeight - searchY
val platSet = Vertical.foldRegion
(x, searchY, width, height, env, platSet, platformTree)
val platSet = traceRightJump (currentPlat, env, platSet, platformTree)
in
traceLeftJump (currentPlat, env, platSet, platformTree)
end
fun build (currentPlat, platforms, platformTree) =
let
val env = {currentPlat = currentPlat, platforms = platforms}
in
start (currentPlat, env, PlatSet.empty, platformTree)
end
fun fromPlatforms (platforms: GameType.platform vector, platformTree) =
Vector.map (fn plat => build (plat, platforms, platformTree)) platforms
end