Skip to content

Commit

Permalink
optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
bananasmoothii committed Apr 2, 2023
1 parent 61bbd09 commit 17ad4a0
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 35 deletions.
2 changes: 2 additions & 0 deletions src/main/kotlin/fr/bananasmoothii/wfc/space/Bounds.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ package fr.bananasmoothii.wfc.space
interface Bounds<D: Dimension<D>>: Dimensioned<D>, Iterable<Coords<D>> {
val min: Coords<D>
val max: Coords<D>

operator fun contains(coords: Coords<D>): Boolean
}
5 changes: 3 additions & 2 deletions src/main/kotlin/fr/bananasmoothii/wfc/space/d2/Bounds2D.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.bananasmoothii.wfc.space.d2

import fr.bananasmoothii.wfc.space.Bounds
import fr.bananasmoothii.wfc.space.Coords
import fr.bananasmoothii.wfc.space.d2.Bounds2D.Companion.rangeTo

/**
Expand All @@ -12,8 +13,8 @@ class Bounds2D private constructor(override val min: Coords2D, override val max:
val width = max.x - min.x + 1
val height = max.y - min.y + 1

operator fun contains(coords: Coords2D): Boolean =
coords.x in min.x..max.x && coords.y in min.y..max.y
override operator fun contains(coords: Coords<Dimension2D>): Boolean =
(coords as Coords2D).x in min.x..max.x && coords.y in min.y..max.y


override operator fun iterator(): Iterator<Coords2D> = object : Iterator<Coords2D> {
Expand Down
12 changes: 6 additions & 6 deletions src/main/kotlin/fr/bananasmoothii/wfc/space/d2/Coords2D.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package fr.bananasmoothii.wfc.space.d2

import fr.bananasmoothii.wfc.space.Coords
import fr.bananasmoothii.wfc.space.Direction
import fr.bananasmoothii.wfc.space.d2.Direction2D.*
import fr.bananasmoothii.wfc.space.d2.Direction2D.UP

data class Coords2D(val x: Int, val y: Int) : Coords<Dimension2D>, D2 {

Expand All @@ -11,11 +11,11 @@ data class Coords2D(val x: Int, val y: Int) : Coords<Dimension2D>, D2 {
* **Warning**: [UP] means towards negative y
*/
override fun move(direction: Direction<Dimension2D>): Coords2D {
return when (direction) {
UP -> copy(y = y - 1)
DOWN -> copy(y = y + 1)
LEFT -> copy(x = x - 1)
RIGHT -> copy(x = x + 1)
return when (direction.hashCode()) {
1 -> copy(y = y - 1) // UP
2 -> copy(y = y + 1) // DOWN
3 -> copy(x = x - 1) // LEFT
4 -> copy(x = x + 1) // RIGHT
else -> throw IllegalArgumentException("Direction $direction is not a Direction2D")
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/kotlin/fr/bananasmoothii/wfc/space/d3/Bounds3D.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.bananasmoothii.wfc.space.d3

import fr.bananasmoothii.wfc.space.Bounds
import fr.bananasmoothii.wfc.space.Coords
import fr.bananasmoothii.wfc.space.d3.Bounds3D.Companion.rangeTo

/**
Expand All @@ -9,8 +10,8 @@ import fr.bananasmoothii.wfc.space.d3.Bounds3D.Companion.rangeTo
*/
class Bounds3D private constructor(override val min: Coords3D, override val max: Coords3D) : Bounds<Dimension3D>, D3 {

operator fun contains(coords: Coords3D): Boolean =
coords.x in min.x..max.x && coords.y in min.y..max.y && coords.z in min.z..max.z
override operator fun contains(coords: Coords<Dimension3D>): Boolean =
(coords as Coords3D).x in min.x..max.x && coords.y in min.y..max.y && coords.z in min.z..max.z


override operator fun iterator(): Iterator<Coords3D> = object : Iterator<Coords3D> {
Expand Down
14 changes: 7 additions & 7 deletions src/main/kotlin/fr/bananasmoothii/wfc/space/d3/Coords3D.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ data class Coords3D(val x: Int, val y: Int, val z: Int) : Coords<Dimension3D>, D
* [EAST] is positive x, and [UP] is positive y.
*/
override fun move(direction: Direction<Dimension3D>): Coords3D {
return when (direction) {
NORTH -> copy(z = z - 1)
SOUTH -> copy(z = z + 1)
EAST -> copy(x = x + 1)
WEST -> copy(x = x - 1)
UP -> copy(y = y + 1)
DOWN -> copy(y = y - 1)
return when (direction.hashCode()) {
1 -> copy(z = z - 1) // NORTH
2 -> copy(z = z + 1) // SOUTH
3 -> copy(x = x + 1) // EAST
4 -> copy(x = x - 1) // WEST
5 -> copy(y = y + 1) // UP
6 -> copy(y = y - 1) // DOWN
else -> throw IllegalArgumentException("Direction $direction is not a Direction3D")
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/fr/bananasmoothii/wfc/tile/AbstractTileSet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ abstract class AbstractTileSet<C : Rotatable<D>, D : Dimension<D>> : Dimensioned
else action()
}

fun getTileList(longArray: LongArray): List<Tile<C, D>> {
val list = ArrayList<Tile<C, D>>(longArray.size * 64)
open fun getTileList(longArray: LongArray): List<Tile<C, D>> {
val list = ArrayList<Tile<C, D>>(longArray.size * 16) // this is a very rough estimation
for (i in 0 .. maxId) {
if (longArray.getBitAt(i)) list.add(tiles[i])
}
return list
}

fun pickTile(tilesAtCoordsArray: LongArray?, random: kotlin.random.Random): Int {
open fun pickTile(tilesAtCoordsArray: LongArray?, random: kotlin.random.Random): Int {
if (tilesAtCoordsArray == null) return random.nextInt(maxId)
val possibilities = getTileList(tilesAtCoordsArray)
return possibilities[random.nextInt(possibilities.size)].id
Expand Down
12 changes: 11 additions & 1 deletion src/main/kotlin/fr/bananasmoothii/wfc/tile/simple/TileSet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ sealed class TileSet<C : Rotatable<D>, D : Dimension<D>, T : Tile<C, D>>(overrid
protected val _tiles: MutableList<T> = mutableListOf()

override val tiles: List<T>
get() = _tiles.toList()
get() {
return _tiles.toList()
}

override fun fromId(id: Int): T = _tiles[id]

Expand All @@ -25,6 +27,14 @@ sealed class TileSet<C : Rotatable<D>, D : Dimension<D>, T : Tile<C, D>>(overrid
}
}
}

override fun getTileList(longArray: LongArray): List<Tile<C, D>> {
val list = ArrayList<Tile<C, D>>(longArray.size * 16) // this is a very rough estimation
for (i in 0 .. maxId) {
if (longArray.getBitAt(i)) list.add(tiles[i])
}
return list
}
}

class NeighborBasedTileSet<C : Rotatable<D>, D : Dimension<D>>(dimension: D) :
Expand Down
28 changes: 16 additions & 12 deletions src/main/kotlin/fr/bananasmoothii/wfc/wavefunction/WaveFunction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,33 @@ import fr.bananasmoothii.wfc.tile.Tile
import fr.bananasmoothii.wfc.util.*
import kotlin.random.Random

open class WaveFunction<C : Rotatable<D>, D : Dimension<D>>(
class WaveFunction<C : Rotatable<D>, D : Dimension<D>>(
val tileSet: AbstractTileSet<C, D>,
protected val random: Random = Random.Default,
private val random: Random = Random.Default,
val commitStates: Boolean = true,
var onCollapse: ((Coords<D>, Tile<C, D>) -> Unit)? = null,
) : Iterable<Map.Entry<Coords<D>, List<Tile<C, D>>>>, Versionable {

init {
require(!tileSet.canCreateNewPieces) { "You have to finish creating the TileSet before using it in generation" }
}

protected var map = mutableMapOf<Coords<D>, LongArray>()
private var map = mutableMapOf<Coords<D>, LongArray>()

protected var lastCoordsWherePicked: Coords<D>? = null
protected var lastTileIdPicked: Int? = null
private var lastCoordsWherePicked: Coords<D>? = null
private var lastTileIdPicked: Int? = null

protected val maxEntropyArray = tileSet.maxEntropyArray
protected val arraySize = tileSet.arraySize
private val maxEntropyArray = tileSet.maxEntropyArray
private val arraySize = tileSet.arraySize

//private val dispatcher = newSingleThreadContext("Propagation thread")

fun collapse(bounds: Bounds<D>) {
if (!commitStates) commit() // commit only once
for (coords in bounds) {
val tilesAtCoordsArray = map[coords]
if (tilesAtCoordsArray?.hasSingle1Bit() == true) continue
commit()
if (commitStates) commit()
// there are multiple possibilities, so we pick one
lastCoordsWherePicked = coords
val tileId = tileSet.pickTile(tilesAtCoordsArray, random)
Expand Down Expand Up @@ -93,7 +95,7 @@ open class WaveFunction<C : Rotatable<D>, D : Dimension<D>>(
}
}

protected data class PropagationTask<D : Dimension<D>>(
private data class PropagationTask<D : Dimension<D>>(
val center: Coords<D>,
val direction: Direction<D>
) {
Expand All @@ -118,16 +120,18 @@ open class WaveFunction<C : Rotatable<D>, D : Dimension<D>>(
}


protected open inner class State(
private open inner class State(
val map: MutableMap<Coords<D>, LongArray>,
val lastCoordsWherePicked: Coords<D>?,
val lastTileIdPicked: Int?
)

protected val states = mutableListOf<State>()
private val states = mutableListOf<State>()

override fun commit() {
states += State(map.toMutableMap(), lastCoordsWherePicked, lastTileIdPicked)
val mapCopy = HashMap<Coords<D>, LongArray>(map.size)
mapCopy.putAll(map)
states += State(mapCopy, lastCoordsWherePicked, lastTileIdPicked)
}

override fun canRollback(): Boolean = states.isNotEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ class WaveFunctionTest {
fileDir.delete()
fileDir.mkdirs()

val waveFunction = WaveFunction(tileSet)
val bounds: Bounds2D = Coords2D(0, 0)..Coords2D(25, 25)
val waveFunction = WaveFunction(tileSet, commitStates = false)
val bounds: Bounds2D = Coords2D(-100, -100)..Coords2D(100, 100)
/*
waveFunction.onCollapse = { _, _ ->
ImageIO.write(
Expand Down

0 comments on commit 17ad4a0

Please sign in to comment.