Fixed coordinate packing/unpacking, delegated more functions to appropriate objects, increased test coverage

main
Bryson Zimmerman 11 months ago
parent 15672c867c
commit 9cbf367375

@ -19,6 +19,8 @@ import java.util.*
object World { object World {
//Default size should be 20 //Default size should be 20
val tiles = WorldData(ArrayList<ArrayList<TileProperties>>()) val tiles = WorldData(ArrayList<ArrayList<TileProperties>>())
var sizeX = 10
var sizeY = 10
fun update(tile: Tile, to: TileProperties) { fun update(tile: Tile, to: TileProperties) {
tiles.value[tile.x()][tile.y()] = to tiles.value[tile.x()][tile.y()] = to
@ -26,10 +28,12 @@ object World {
//Returns a coordinate pair //Returns a coordinate pair
fun getRandomLocation(): Tile { fun getRandomLocation(): Tile {
return Tile((0..tiles.value.size-1).random(), (0..tiles.value.get(0).size-1).random()) return Tile((0..<sizeX).random(), (0..<sizeY).random())
} }
fun setSize(x: Int, y: Int) { fun setSize(x: Int, y: Int) {
sizeX = x
sizeY = y
tiles.setSize(x, y) tiles.setSize(x, y)
} }

@ -17,17 +17,17 @@ enum class Directions(val dir: Int) {
else -> NONE else -> NONE
} }
} }
fun getModifier(dir: Directions): Long { fun getModifier(dir: Directions): ULong {
return when(dir) { return when(dir) {
UP -> NORTH UP -> NORTH
DOWN -> SOUTH DOWN -> SOUTH
LEFT -> WEST LEFT -> WEST
RIGHT -> EAST RIGHT -> EAST
else -> 0L else -> NONEMOD
} }
} }
fun convertModifier(mod: Long): Directions { fun convertModifier(mod: ULong): Directions {
return when(mod) { return when(mod) {
NORTH -> UP NORTH -> UP
SOUTH -> DOWN SOUTH -> DOWN
@ -37,12 +37,12 @@ enum class Directions(val dir: Int) {
} }
} }
const val SOUTH: Long = 0x1L const val SOUTH: ULong = 1UL
const val NORTH: Long = -0x1L const val NORTH: ULong = 4294967295UL
const val WEST: Long = -0x100000000L const val WEST: ULong = 18446744069414584320UL
const val EAST: Long = 0x100000000L const val EAST: ULong = 4294967296UL
val ALL = arrayOf(UP, DOWN, LEFT, RIGHT) val ALL = arrayOf(UP, DOWN, LEFT, RIGHT)
const val NONEMOD = 0L const val NONEMOD = 0UL
} }
fun inv(): Int { fun inv(): Int {

@ -2,16 +2,20 @@ package technology.zim.data
import technology.zim.World import technology.zim.World
@JvmInline @JvmInline
value class Tile(val value: Long) { value class Tile(private val value: ULong) {
constructor(x: Int, y: Int): this(pack(x, y)) { constructor(x: Int, y: Int): this(pack(x, y)) {
} }
fun connect(candidateTile: Tile) { fun connect(candidateTile: Tile) {
val dir = Directions.convertModifier(candidateTile.value - this.value) val dir = toward(candidateTile)
connect(dir) connect(dir)
} }
//Connect two tiles together. //Connect two tiles together.
//Calls utility function on the connected cell //Calls utility function on the connected cell
fun connect(dir: Directions) { fun connect(dir: Directions) {
@ -20,12 +24,12 @@ value class Tile(val value: Long) {
//Ensure that the tile is within bounds //Ensure that the tile is within bounds
if(candidateTile.isInBounds() && this.isInBounds()) if(candidateTile.isInBounds() && this.isInBounds())
{ {
World.tiles.value[x()][y()] = getProperties().add(dir) if(this.y() == World.sizeY - 1 && dir == Directions.DOWN)
World.tiles.value[candidateTile.x()][candidateTile.y()] = candidateTile.getProperties().add(Directions.opposite(dir)) println("wat")
World.update(this, getProperties().add(dir))
World.update(candidateTile, candidateTile.getProperties().add(candidateTile.toward(this)))
} }
else { else {
//Shouldn't matter whether we skip connecting an out-of-bounds item
//Should also never get to the point where the attempt is made //Should also never get to the point where the attempt is made
println("Attempted to connect to outside bounds: <" + println("Attempted to connect to outside bounds: <" +
candidateTile.x() + ", " + candidateTile.y() candidateTile.x() + ", " + candidateTile.y()
@ -35,20 +39,25 @@ value class Tile(val value: Long) {
} }
} }
//Duplicating code from getAdjacent shaved off 100ms fun toward(otherTile: Tile): Directions {
//I'm keeping it return Directions.convertModifier(otherTile.value - this.value)
}
fun getAdjacentTiles(explored:Boolean): Set<Tile> { fun getAdjacentTiles(explored:Boolean): Set<Tile> {
val adj = mutableSetOf<Tile>() val adj = mutableSetOf<Tile>()
val dirs = Directions.ALL val dirs = Directions.ALL
dirs.forEach { dir -> dirs.forEach { dir ->
val candidateTile = this + dir val candidateTile = this + dir
//Ensure that the tile is within bounds //Ensure that the tile is within bounds
if(candidateTile.isInBounds() && candidateTile.getProperties().visited() == explored) if(candidateTile.isInBounds() && candidateTile.getProperties().visited() == explored)
{ {
println("$this+$dir --> $candidateTile")
adj.add(candidateTile) adj.add(candidateTile)
} }
} }
if(adj.isEmpty() && explored)
println("no explored found")
return adj return adj
} }
@ -77,41 +86,33 @@ value class Tile(val value: Long) {
return this + Directions.getModifier(dir) return this + Directions.getModifier(dir)
} }
operator fun plus(mod: Long): Tile { operator fun plus(mod: ULong): Tile {
return Tile(this.value + mod) return Tile(this.x() + x(mod), this.y() + y(mod))
} }
operator fun plus(tile: Tile): Tile {
return Tile(x() + tile.x(), y() + tile.y())
}
fun getCoordinates(): Pair<Int, Int> {
return Pair(x(), y())
}
fun x(): Int { fun x(): Int {
return (value shr 32).toInt() return x(value)
} }
//Gets the x value of the given coordinate form //Gets the x value of the Long as though it were in coordinate form
fun x(coord: Tile):Int { fun x(coords: ULong): Int {
return coord.x() return (coords shr 32).toLong().toInt()
} }
//Gets the x value of the coordinate form of the given direction //Bitwise and to ensure the left-hand half of the Long is zero'd, then convert toInt()
fun x(dir: Directions):Int {
return (this + dir).x()
}
fun y():Int { fun y():Int {
return value.toInt() return y(value)
}
//Gets the y value of the given coordinate form
fun y(coord: Tile):Int {
return coord.y()
} }
//Gets the y value of the coordinate form of the given direction //Get the y value from a Long as though it were a Tile
fun y(dir: Directions):Int { fun y(coords: ULong): Int {
return (this + dir).y() return coords.toLong().toInt()
} }
override fun toString():String { override fun toString():String {
@ -119,8 +120,8 @@ value class Tile(val value: Long) {
} }
companion object { companion object {
fun pack(x: Int, y: Int):Long { fun pack(mostSignificantBits: Int, leastSignificantBits: Int): ULong {
return (x.toLong() shl 32) + y.toLong() return (mostSignificantBits.toUInt().toULong() shl 32) or leastSignificantBits.toUInt().toULong()
} }
} }

@ -0,0 +1,35 @@
import org.junit.jupiter.api.Test
class CoordPackTest {
@Test
fun packUnpack() {
val xOrig = -0x1
val yOrig = 0x1
val coords = pack(xOrig, yOrig)
val xNew = x(coords)
val yNew = y(coords)
println("done")
assert(xOrig == xNew)
assert(yOrig == yNew)
}
fun pack(mostSignificantBits: Int, leastSignificantBits: Int): ULong {
return (mostSignificantBits.toUInt().toULong() shl 32) or leastSignificantBits.toUInt().toULong()
}
fun x(coords: ULong): Int {
return (coords shr 32).toLong().toInt()
}
fun y(coords: ULong): Int {
return coords.toLong().toInt()
}
}

@ -14,8 +14,37 @@ class TileTest {
MazeFinder.cleanUp() MazeFinder.cleanUp()
} }
//Confirm that an empty map acts like it is empty
@Test
fun emptyTest() {
val tile = Tile(3, 3)
var adjacent = tile.getAdjacentTiles(false)
assert(adjacent.size == 4)
var explored = tile.getAdjacentTiles(true)
assert(explored.isEmpty())
}
@Test
fun squareTest() {
val startTile = Tile(1, 1)
var endTile = startTile
endTile = endTile + LEFT
endTile = endTile + UP
endTile = endTile + RIGHT
endTile = endTile + DOWN
assert(startTile == endTile)
}
@Test @Test
fun connectOutOfBoundsInvalid() { fun connectOutOfBoundsInvalid() {
println("Following out of bounds log entries are expected")
println("-------------------------------------------------------------")
val bottom = Tile(1, 9) val bottom = Tile(1, 9)
bottom.connect(DOWN) bottom.connect(DOWN)
assertFalse(bottom.getProperties().isSouth()) assertFalse(bottom.getProperties().isSouth())
@ -23,6 +52,7 @@ class TileTest {
@Test @Test
fun outOfBoundsTest() { fun outOfBoundsTest() {
val tooNorth = Tile(1, -1) val tooNorth = Tile(1, -1)
val tooWest = Tile(-1, 1) val tooWest = Tile(-1, 1)
val tooEast = Tile(10, 1) val tooEast = Tile(10, 1)
@ -31,6 +61,7 @@ class TileTest {
val northIn = Tile(0, 0) val northIn = Tile(0, 0)
val southIn = Tile(9, 9) val southIn = Tile(9, 9)
println("-------------------------------------------------------------")
assert(northIn.isInBounds()) assert(northIn.isInBounds())
assert(southIn.isInBounds()) assert(southIn.isInBounds())

Loading…
Cancel
Save