Compare commits

..

2 Commits

@ -3,6 +3,8 @@ package technology.zim
import technology.zim.data.Directions import technology.zim.data.Directions
import technology.zim.data.Tile import technology.zim.data.Tile
import technology.zim.data.TileHeap import technology.zim.data.TileHeap
import technology.zim.data.TileNavigatedArray
import kotlin.math.abs
//A* pathfinder backed by an array to improve efficiency //A* pathfinder backed by an array to improve efficiency
@ -11,7 +13,7 @@ import technology.zim.data.TileHeap
object ArrayBackedPathfinder { object ArrayBackedPathfinder {
//TODO: Replace with array for coordinate lookups for speed, do it in a separate pathfinder class to demonstrate the difference //TODO: Replace with array for coordinate lookups for speed, do it in a separate pathfinder class to demonstrate the difference
val gVals = HashMap<Tile, Int>() val gVals = TileNavigatedArray<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) {
@ -24,10 +26,10 @@ object ArrayBackedPathfinder {
return return
} }
val frontier = TileHeap(end, gVals) val frontier = TileHeap(end, this::fValue)
//Prime the things //Prime the things
gVals.put(start, 0) gVals.set(start, 0)
frontier.insert(start) frontier.insert(start)
var current: Tile var current: Tile
@ -44,7 +46,7 @@ object ArrayBackedPathfinder {
if(candidateTile.isInBounds() && candidateG == -1) if(candidateTile.isInBounds() && candidateG == -1)
{ {
//Otherwise, the tile has been reached and this path is not better, so carry on //Otherwise, the tile has been reached and this path is not better, so carry on
gVals.put(candidateTile, currentG + 1) gVals.set(candidateTile, currentG + 1)
frontier.insert(candidateTile) frontier.insert(candidateTile)
World.update(candidateTile, candidateTile.getProperties() +Directions.FRONTIER) World.update(candidateTile, candidateTile.getProperties() +Directions.FRONTIER)
} }
@ -74,4 +76,11 @@ object ArrayBackedPathfinder {
World.update(start, start.getProperties() + Directions.INPATH) World.update(start, start.getProperties() + Directions.INPATH)
} }
private fun fValue(prospect: Tile, end: Tile): Int {
return hValue(prospect, end).plus(MapBackedPathfinder.gVals.get(prospect) ?: 0)
}
private fun hValue(prospect: Tile, end:Tile): Int {
return abs(prospect.x() - end.x()) + abs(prospect.y() - end.y())
}
} }

@ -3,6 +3,7 @@ package technology.zim
import technology.zim.data.Directions import technology.zim.data.Directions
import technology.zim.data.Tile import technology.zim.data.Tile
import technology.zim.data.TileHeap import technology.zim.data.TileHeap
import kotlin.math.abs
//A* to be upgraded with hierarchies //A* to be upgraded with hierarchies
@ -23,7 +24,7 @@ object MapBackedPathfinder {
return return
} }
val frontier = TileHeap(end, gVals) val frontier = TileHeap(end, this::fValue)
//Prime the things //Prime the things
gVals.put(start, 0) gVals.put(start, 0)
@ -52,6 +53,15 @@ object MapBackedPathfinder {
//At this point, a path is found //At this point, a path is found
println("Path found!") println("Path found!")
markPath(start, end)
}
private fun fValue(prospect: Tile, end: Tile): Int {
return hValue(prospect, end).plus(gVals.get(prospect) ?: 0)
}
private fun hValue(prospect: Tile, end:Tile): Int {
return abs(prospect.x() - end.x()) + abs(prospect.y() - end.y())
} }
fun markPath(start: Tile, end:Tile) { fun markPath(start: Tile, end:Tile) {

@ -6,7 +6,7 @@ import kotlin.math.abs
//Translated code from CS222 MaxHeap homework //Translated code from CS222 MaxHeap homework
//Cannot use index 0 due to Integer limitations //Cannot use index 0 due to Integer limitations
//TODO: Consider better options than passing in the information this thing needs //TODO: Consider better options than passing in the information this thing needs
class TileHeap(val end: Tile, val gVals: HashMap<Tile, Int>) { class TileHeap(val end: Tile, val fValue:(Tile, Tile) -> Int) {
val dat = ArrayList<Tile>() val dat = ArrayList<Tile>()
init { init {
//Shove some data into the zero slot //Shove some data into the zero slot
@ -36,7 +36,7 @@ class TileHeap(val end: Tile, val gVals: HashMap<Tile, Int>) {
if(dat.isEmpty()) if(dat.isEmpty())
throw ArrayIndexOutOfBoundsException() throw ArrayIndexOutOfBoundsException()
if(fValue(dat[index]) < fValue(dat[parent(index)]) && index > 1) { if(fValue(dat[index], end) < fValue(dat[parent(index)], end) && index > 1) {
swap(index, parent(index)) swap(index, parent(index))
siftUp(parent(index)) siftUp(parent(index))
} }
@ -47,12 +47,12 @@ class TileHeap(val end: Tile, val gVals: HashMap<Tile, Int>) {
var minValueIndex = index var minValueIndex = index
val l = leftChild(index) val l = leftChild(index)
if(l < dat.size && fValue(dat[l]) < fValue(dat[minValueIndex]) ) { if(l < dat.size && fValue(dat[l], end) < fValue(dat[minValueIndex], end) ) {
minValueIndex = l minValueIndex = l
} }
val r = rightChild(index) val r = rightChild(index)
if(r < dat.size && fValue(dat[r]) < fValue(dat[minValueIndex])) { if(r < dat.size && fValue(dat[r], end) < fValue(dat[minValueIndex], end) ) {
minValueIndex = r minValueIndex = r
} }
@ -78,12 +78,4 @@ class TileHeap(val end: Tile, val gVals: HashMap<Tile, Int>) {
return index > (dat.size / 2) return index > (dat.size / 2)
} }
private fun fValue(prospect: Tile): Int {
return hValue(prospect).plus(gVals.get(prospect) ?: 0)
}
private fun hValue(prospect: Tile): Int {
return abs(prospect.x() - end.x()) + abs(prospect.y() - end.y())
}
} }

@ -4,23 +4,29 @@ package technology.zim.data
//Row-major for improved memory locality.. maybe make it flexible? //Row-major for improved memory locality.. maybe make it flexible?
//Delegation should allow direct access to functions, with added functions for convenience //Delegation should allow direct access to functions, with added functions for convenience
class TileNavigatedArray<T>(val data: ArrayList<T> = ArrayList<T>(), var colSize:Int = 10, class TileNavigatedArray<T>(val data: ArrayList<T?> = ArrayList<T?>(), var colSize:Int = 10,
var rowSize:Int = 10, val colMajor:Boolean = false) : MutableList<T> by data { var rowSize:Int = 10, val colMajor:Boolean = false) : MutableList<T?> by data {
//TODO: Create initializer that fills array with null values
constructor(col:Int, row:Int,major:Boolean) : this(colSize = col, rowSize = row,colMajor = major)
constructor(col:Int, row:Int,major:Boolean) : this(colSize = col, rowSize = row,colMajor = major) {
}
//Accept a tile, use its coordinates to pull the requested data //Accept a tile, use its coordinates to pull the requested data
fun get(tile: Tile):T { fun get(tile: Tile):T? {
return data[rowOffset(tile) + colOffset(tile)] return data[rowOffset(tile) + colOffset(tile)]
} }
fun add(tile: Tile, value: T) { fun add(tile: Tile, value: T?) {
data.add(rowOffset(tile)+colOffset(tile), value) data.add(rowOffset(tile)+colOffset(tile), value)
} }
fun set(tile: Tile, value: T?) {
data.set(rowOffset(tile) + colOffset(tile), value)
}
//Give it the row //Give it the row
fun rowOffset(tile: Tile):Int { fun rowOffset(tile: Tile):Int {
assert(false) //Fix the return value
return when (colMajor) { return when (colMajor) {
//If column major, jump by column size * x //If column major, jump by column size * x
true -> colSize * tile.x() true -> colSize * tile.x()
@ -30,7 +36,6 @@ class TileNavigatedArray<T>(val data: ArrayList<T> = ArrayList<T>(), var colSize
} }
fun colOffset(tile: Tile):Int { fun colOffset(tile: Tile):Int {
assert(false) //Fix the return value
return when (colMajor) { return when (colMajor) {
//If column major, return the y value //If column major, return the y value
true -> tile.y() true -> tile.y()

@ -7,11 +7,12 @@ import kotlin.test.BeforeTest
class TileHeapTest { class TileHeapTest {
companion object { companion object {
var heap = TileHeap(Tile(20, 20)) var gVals = HashMap<Tile, Int>()
var heap = TileHeap(Tile(20, 20), gVals)
} }
@BeforeTest @BeforeTest
fun setUp() { fun setUp() {
heap = TileHeap(Tile(20, 20)) heap = TileHeap(Tile(20, 20), gVals)
arrayOf(Tile(0, 0), Tile(1, 1), Tile(5, 5), Tile(4, 4), Tile(19, 19), Tile(2, 2)).forEach { item -> arrayOf(Tile(0, 0), Tile(1, 1), Tile(5, 5), Tile(4, 4), Tile(19, 19), Tile(2, 2)).forEach { item ->
heap.insert(item) heap.insert(item)
} }

@ -1,16 +1,32 @@
import technology.zim.data.Tile
import technology.zim.data.TileNavigatedArray
import kotlin.test.BeforeTest import kotlin.test.BeforeTest
import kotlin.test.Test import kotlin.test.Test
class TileNavigatedArrayTest { class TileNavigatedArrayTest {
var arr:TileNavigatedArray<Int> = TileNavigatedArray()
@BeforeTest @BeforeTest
fun setUp() { fun setUp() {
arr = TileNavigatedArray<Int>(10, 10, false)
arr.addAll(0..(10*10))
} }
@Test @Test
fun addAndAccessTest() { fun addAndAccessTest() {
arr.apply {
set(Tile(0,0), -1)
set(Tile(0,1), -2)
set(Tile(1, 0), -3)
set(Tile(1, 1), -4)
set(Tile(2, 1), -5)
set(Tile(2, 2), -6)
}
assert(arr.get(Tile(0, 0)) == -1)
assert(arr.get(Tile(0, 1)) == -2)
assert(arr.get(Tile(1, 0)) == -3)
assert(arr.get(Tile(1, 1)) == -4)
assert(arr.get(Tile(2, 1)) == -5)
assert(arr.get(Tile(2, 2)) == -6)
} }
} }
Loading…
Cancel
Save