From 9a5d021f3f4ae596593931362b3330249fe00a52 Mon Sep 17 00:00:00 2001 From: Bryson Zimmerman Date: Wed, 6 Nov 2024 11:48:14 -0500 Subject: [PATCH] First run at implementing A* with several todo's to conform to correct implementation --- src/main/kotlin/PathFinder.kt | 26 +++++++++++++++++++------- src/main/kotlin/data/Tile.kt | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/PathFinder.kt b/src/main/kotlin/PathFinder.kt index 953cdb6..7021274 100644 --- a/src/main/kotlin/PathFinder.kt +++ b/src/main/kotlin/PathFinder.kt @@ -1,6 +1,7 @@ package technology.zim import technology.zim.data.Tile +import technology.zim.data.TileHeap import kotlin.math.abs //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 object PathFinder { - + val hVals = HashMap() //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 fun generatePath(start: Tile, end: Tile) { @@ -22,12 +23,23 @@ object PathFinder { return } - //Frontier defined by a Tile heap that makes comparisons on calculated hValues - - //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) - //Probably best to just make an array of integers, where the coordinates store the tile's g(n) - - //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 + val frontier = TileHeap(end) + + //Prime the things + hVals.put(start, hValue(start, end)) + frontier.insert(start) + + 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 diff --git a/src/main/kotlin/data/Tile.kt b/src/main/kotlin/data/Tile.kt index dba8935..a9c7670 100644 --- a/src/main/kotlin/data/Tile.kt +++ b/src/main/kotlin/data/Tile.kt @@ -1,6 +1,7 @@ package technology.zim.data import technology.zim.World +import java.util.HashMap //Tile is a ULong that represents the X,Y coordinates of a Tile //Contains functions necessary for accessing and manipulating Tiles @@ -113,6 +114,23 @@ value class Tile(private val value: ULong) { return "<" + x() + ", " + y() + ">" } + //TODO: Consider pushing getAdjacent and getUnexplored to their call locations to avoid allocating sets? + fun getUnexploredTiles(map: HashMap):Set { + val adj = mutableSetOf() + 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 { fun pack(mostSignificantBits: Int, leastSignificantBits: Int): ULong { return (mostSignificantBits.toUInt().toULong() shl 32) or leastSignificantBits.toUInt().toULong()