First run at implementing A* with several todo's to conform to correct implementation

main
Bryson Zimmerman 11 months ago
parent ef94fb7d05
commit 9a5d021f3f

@ -1,6 +1,7 @@
package technology.zim package technology.zim
import technology.zim.data.Tile import technology.zim.data.Tile
import technology.zim.data.TileHeap
import kotlin.math.abs import kotlin.math.abs
//A* to be upgraded with hierarchies //A* to be upgraded with hierarchies
@ -9,7 +10,7 @@ import kotlin.math.abs
//and https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Comparator.html //and https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Comparator.html
object PathFinder { object PathFinder {
val hVals = HashMap<Tile, Int>()
//work along the path, marking tiles with VISITED along the way //work along the path, marking tiles with VISITED along the way
//if marking with visited is too expensive, just make the path and finalize it //if marking with visited is too expensive, just make the path and finalize it
fun generatePath(start: Tile, end: Tile) { fun generatePath(start: Tile, end: Tile) {
@ -22,12 +23,23 @@ object PathFinder {
return return
} }
//Frontier defined by a Tile heap that makes comparisons on calculated hValues val frontier = TileHeap(end)
//Frontier tiles are known to have a current cost: g(n) (number of steps from start to this node)+ calculate own distance from the end h(n) //Prime the things
//Probably best to just make an array of integers, where the coordinates store the tile's g(n) hVals.put(start, hValue(start, end))
frontier.insert(start)
//Always grab the lowest value of f(n) = g(n) + h(n) from the frontier, mark it visited, mark its g(n), and add its unvisited neighbors
var current: Tile
//TODO: update TileHeap to utilize full f(n) instead of just h(n)
do {
current = frontier.popMin()
//TODO: Can't delegate getUnexploredTiles to Tile as this prevents adding tiles back to the frontier when a better path found
current.getUnexploredTiles(hVals).forEach {
value ->
frontier.insert(value)
hVals.put(value, hVals.get(current)?.plus(1) ?: 0.also { throw IllegalStateException("Couldn't get hValue of current tile")})
}
} while( current != end)
//Need to be able to return a tile to the frontier if a shorter path to it is found //Need to be able to return a tile to the frontier if a shorter path to it is found

@ -1,6 +1,7 @@
package technology.zim.data package technology.zim.data
import technology.zim.World import technology.zim.World
import java.util.HashMap
//Tile is a ULong that represents the X,Y coordinates of a Tile //Tile is a ULong that represents the X,Y coordinates of a Tile
//Contains functions necessary for accessing and manipulating Tiles //Contains functions necessary for accessing and manipulating Tiles
@ -113,6 +114,23 @@ value class Tile(private val value: ULong) {
return "<" + x() + ", " + y() + ">" return "<" + x() + ", " + y() + ">"
} }
//TODO: Consider pushing getAdjacent and getUnexplored to their call locations to avoid allocating sets?
fun getUnexploredTiles(map: HashMap<Tile, Int>):Set<Tile> {
val adj = mutableSetOf<Tile>()
val dirs = Directions.ALL
dirs.forEach { dir ->
val candidateTile = this + dir
//Ensure that the tile is within bounds
if(candidateTile.isInBounds() && !map.containsKey(candidateTile))
{
//println("$this+$dir --> $candidateTile")
adj.add(candidateTile)
}
}
return adj
}
companion object { companion object {
fun pack(mostSignificantBits: Int, leastSignificantBits: Int): ULong { fun pack(mostSignificantBits: Int, leastSignificantBits: Int): ULong {
return (mostSignificantBits.toUInt().toULong() shl 32) or leastSignificantBits.toUInt().toULong() return (mostSignificantBits.toUInt().toULong() shl 32) or leastSignificantBits.toUInt().toULong()

Loading…
Cancel
Save