main
Bryson Zimmerman 11 months ago
parent d37ba3448c
commit 2a433508c7

@ -1,10 +1,13 @@
package technology.zim
import technology.zim.data.Directions
import technology.zim.data.Tile
import technology.zim.data.TileNavigatedArray
object BFSPathFinder {
//In this particular situation, only a single outcome is likely. Thus, BFS always finds the perfect (and only) path
//Skipping the Heap data structure allows better utilization of on-die cache
var gVals:TileNavigatedArray<Int> = TileNavigatedArray<Int>()
fun generatePath(start: Tile, end: Tile) {
if (!start.isInBounds() || !end.isInBounds()) {
@ -15,21 +18,48 @@ object BFSPathFinder {
println("Ouroboros detected")
return
}
gVals = TileNavigatedArray<Int>(World.sizeX, World.sizeY, false)
//Queue for tiles to be checked
val frontier = ArrayDeque<Tile>()
frontier.addLast(start)
gVals.set(start, 0)
World.update(start, Directions.BFSFRONTIER)
var current:Tile
while (frontier.isNotEmpty()) {
//Grab the next tile
// Mark it explored
//Grab the next tile and its gValue
current = frontier.removeFirst()
val currentG = gVals.get(current)?:Int.MAX_VALUE-1.also{throw IndexOutOfBoundsException("Couldn't get gValue in BFS")}
//record its distance-cost
// add its unexplored neighbors
// add its unexplored neighbors and update their gVals
current.getConnections().forEach {
tile ->
if(!World.get(tile).isBFSFrontier()) {
World.update(tile, Directions.BFSFRONTIER)
frontier.addLast(tile)
gVals.set(tile, currentG + 1)
}
}
}
markPath(start, end)
}
fun markPath(start: Tile, end:Tile) {
//Step through the path from end until start
var current = end
var lowestG = Int.MAX_VALUE
var lowestCost = end
while(current != start) {
World.update(current, current.getProperties() + Directions.BFSINPATH)
current.getConnections().forEach { candidateTile ->
val candidateG = gVals.get(candidateTile) ?: -1
if(candidateTile.isInBounds() && candidateG != -1 && candidateG < lowestG ) {
lowestG = candidateG
lowestCost = candidateTile
}
}
current = lowestCost
}
World.update(start, start.getProperties() + Directions.BFSINPATH)
}
}

@ -16,19 +16,27 @@ class HierarchicalPathfinding {
}
println("Pathfinding")
val BFSPathFinderTime = measureTime {
BFSPathFinder.generatePath(Tile(0, 0), Tile(n-1, n-1))
}
val ArrayBackedPathfinderTime = measureTime {
ArrayBackedPathfinder.generatePath(Tile(0, 0), Tile(n - 1, (n - 1)))
}
/*
val MapBackedPathfinderTime = measureTime {
MapBackedPathfinder.generatePath(Tile(0, 0), Tile(n - 1, (n - 1)))
}
*/
println(World.toString())
println(n*n)
println("Maze build time: ${buildMazeTime.inWholeMilliseconds} ms")
println("HashMap-Backed Pathfinder time: ${MapBackedPathfinderTime.inWholeMilliseconds}ms")
//println("HashMap-Backed Pathfinder time: ${MapBackedPathfinderTime.inWholeMilliseconds}ms")
println("Array-Backed Pathfinder time: ${ArrayBackedPathfinderTime.inWholeMilliseconds}ms")
println("BFS Pathfinder time: ${BFSPathFinderTime.inWholeMilliseconds}ms")
}
//Clear the maze of pathfinding markers before running another pathfinding algorithm

@ -34,6 +34,9 @@ object World {
const val ANSI_CYAN = "\u001B[36m"
const val ANSI_WHITE = "\u001B[37m"
fun update(tile: Tile, dir: Directions) {
update(tile, get(tile) + dir)
}
fun update(tile: Tile, to: TileProperties) {
tiles.set(tile, to)
@ -74,7 +77,7 @@ object World {
for (y in 0..sizeY - 1) {
//Upper line: Print each tile, print right-hand connections
for (x in 0..sizeX - 1) {
if(get(Tile(x, y)).connections and(INPATH.dir) != 0)
if(get(Tile(x, y)).connections and(INPATH.dir+BFSINPATH.dir) != 0)
inPath = true
else if (get(Tile(x, y)).connections and(FRONTIER.dir) != 0)
checked = true

@ -5,6 +5,8 @@ import technology.zim.World
//Tile is a ULong that represents the X,Y coordinates of a Tile
//Contains functions necessary for accessing and manipulating Tiles
//TODO: Untangle visited maths
@JvmInline
value class Tile(private val value: ULong) {
@ -40,6 +42,7 @@ value class Tile(private val value: ULong) {
return Directions.convertModifier(Tile(otherTile.x() - this.x(), otherTile.y() - this.y()).value)
}
//Get adjacent tiles for Prim's Algorithm
fun getAdjacentTiles(explored:Boolean): Set<Tile> {
val adj = mutableSetOf<Tile>()
val dirs = Directions.ALL
@ -111,6 +114,7 @@ value class Tile(private val value: ULong) {
return "<" + x() + ", " + y() + ">"
}
//Get connections for pathfinding algorithms
fun getConnections(): Set<Tile> {
val connections = mutableSetOf<Tile>()
val properties = getProperties()

@ -58,6 +58,10 @@ value class TileProperties(val connections: Int) {
return connections and(MANIFEST.dir) == MANIFEST.dir
}
fun isBFSFrontier(): Boolean {
return connections and(BFSFRONTIER.dir) == BFSFRONTIER.dir
}
override fun toString():String {
val ret = StringBuilder()
if(isWest()) {

Loading…
Cancel
Save