mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-14 15:46:06 +09:00
new and sane graph traversal; only works for first of the multiple wires tho
This commit is contained in:
@@ -78,8 +78,8 @@ open class GameWorld : Disposable {
|
|||||||
private val wirings: HashMap<BlockAddress, WiringNode>
|
private val wirings: HashMap<BlockAddress, WiringNode>
|
||||||
|
|
||||||
private val wiringGraph = HashMap<BlockAddress, HashMap<ItemID, WiringSimCell>>()
|
private val wiringGraph = HashMap<BlockAddress, HashMap<ItemID, WiringSimCell>>()
|
||||||
private val WIRE_POS_MAP = byteArrayOf(1,2,4,8)
|
private val WIRE_POS_MAP = intArrayOf(1,2,4,8)
|
||||||
private val WIRE_ANTIPOS_MAP = byteArrayOf(4,8,1,2)
|
private val WIRE_ANTIPOS_MAP = intArrayOf(4,8,1,2)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the renderer. When wirings are updated, `wirings` and this properties must be synchronised.
|
* Used by the renderer. When wirings are updated, `wirings` and this properties must be synchronised.
|
||||||
@@ -334,11 +334,11 @@ open class GameWorld : Disposable {
|
|||||||
// figure out wiring graphs
|
// figure out wiring graphs
|
||||||
val matchingNeighbours = WireActor.WIRE_NEARBY.mapIndexed { index, (tx, ty) ->
|
val matchingNeighbours = WireActor.WIRE_NEARBY.mapIndexed { index, (tx, ty) ->
|
||||||
(getAllWiresFrom(x + tx, y + ty)?.contains(tile) == true).toInt() shl index
|
(getAllWiresFrom(x + tx, y + ty)?.contains(tile) == true).toInt() shl index
|
||||||
}.sum().toByte()
|
}.sum()
|
||||||
// setup graph of mine
|
// setup graph of mine
|
||||||
setWireGraphOfUnsafe(blockAddr, tile, matchingNeighbours)
|
setWireGraphOfUnsafe(blockAddr, tile, matchingNeighbours)
|
||||||
// setup graph for neighbours
|
// setup graph for neighbours
|
||||||
for (i in 0.toByte() .. 3.toByte()) {
|
for (i in 0..3) {
|
||||||
if (matchingNeighbours and WIRE_POS_MAP[i] > 0) {
|
if (matchingNeighbours and WIRE_POS_MAP[i] > 0) {
|
||||||
val (tx, ty) = WireActor.WIRE_NEARBY[i]
|
val (tx, ty) = WireActor.WIRE_NEARBY[i]
|
||||||
val old = getWireGraphOf(x + tx, y + ty, tile) ?: 0
|
val old = getWireGraphOf(x + tx, y + ty, tile) ?: 0
|
||||||
@@ -347,13 +347,13 @@ open class GameWorld : Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWireGraphOf(x: Int, y: Int, itemID: ItemID): Byte? {
|
fun getWireGraphOf(x: Int, y: Int, itemID: ItemID): Int? {
|
||||||
val (x, y) = coerceXY(x, y)
|
val (x, y) = coerceXY(x, y)
|
||||||
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
||||||
return getWireGraphUnsafe(blockAddr, itemID)
|
return getWireGraphUnsafe(blockAddr, itemID)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWireGraphUnsafe(blockAddr: BlockAddress, itemID: ItemID): Byte? {
|
fun getWireGraphUnsafe(blockAddr: BlockAddress, itemID: ItemID): Int? {
|
||||||
return wiringGraph[blockAddr]?.get(itemID)?.connections
|
return wiringGraph[blockAddr]?.get(itemID)?.connections
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,19 +377,19 @@ open class GameWorld : Disposable {
|
|||||||
return wiringGraph[blockAddr]?.get(itemID)?.recvStates
|
return wiringGraph[blockAddr]?.get(itemID)?.recvStates
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWireGraphOf(x: Int, y: Int, itemID: ItemID, byte: Byte) {
|
fun setWireGraphOf(x: Int, y: Int, itemID: ItemID, cnx: Int) {
|
||||||
val (x, y) = coerceXY(x, y)
|
val (x, y) = coerceXY(x, y)
|
||||||
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
||||||
return setWireGraphOfUnsafe(blockAddr, itemID, byte)
|
return setWireGraphOfUnsafe(blockAddr, itemID, cnx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWireGraphOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, byte: Byte) {
|
fun setWireGraphOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, cnx: Int) {
|
||||||
if (wiringGraph[blockAddr] == null)
|
if (wiringGraph[blockAddr] == null)
|
||||||
wiringGraph[blockAddr] = HashMap()
|
wiringGraph[blockAddr] = HashMap()
|
||||||
if (wiringGraph[blockAddr]!![itemID] == null)
|
if (wiringGraph[blockAddr]!![itemID] == null)
|
||||||
wiringGraph[blockAddr]!![itemID] = WiringSimCell(byte)
|
wiringGraph[blockAddr]!![itemID] = WiringSimCell(cnx)
|
||||||
|
|
||||||
wiringGraph[blockAddr]!![itemID]!!.connections = byte
|
wiringGraph[blockAddr]!![itemID]!!.connections = cnx
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWireEmitStateOf(x: Int, y: Int, itemID: ItemID, vector: Vector2) {
|
fun setWireEmitStateOf(x: Int, y: Int, itemID: ItemID, vector: Vector2) {
|
||||||
@@ -647,7 +647,7 @@ open class GameWorld : Disposable {
|
|||||||
* These values must be updated by none other than [WorldSimulator]()
|
* These values must be updated by none other than [WorldSimulator]()
|
||||||
*/
|
*/
|
||||||
data class WiringSimCell(
|
data class WiringSimCell(
|
||||||
var connections: Byte = 0, // connections
|
var connections: Int = 0, // connections
|
||||||
var emitState: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power
|
var emitState: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power
|
||||||
var recvStates: ArrayList<WireRecvState> = ArrayList() // how far away are the power sources
|
var recvStates: ArrayList<WireRecvState> = ArrayList() // how far away are the power sources
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.torvald.terrarum.gameworld
|
package net.torvald.terrarum.gameworld
|
||||||
|
|
||||||
import com.badlogic.gdx.Input
|
import com.badlogic.gdx.Input
|
||||||
|
import com.badlogic.gdx.utils.Queue
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.AppLoader.printdbg
|
import net.torvald.terrarum.AppLoader.printdbg
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
@@ -21,6 +22,7 @@ import org.dyn4j.geometry.Vector2
|
|||||||
import org.khelekore.prtree.*
|
import org.khelekore.prtree.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.experimental.and
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -480,105 +482,55 @@ object WorldSimulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun traverseWireGraph(world: GameWorld, fixture: FixtureBase, wireType: String, bbi: BlockBoxIndex) {
|
private fun traverseWireGraph(world: GameWorld, fixture: FixtureBase, wireType: String, bbi: BlockBoxIndex) {
|
||||||
fixture.worldBlockPos?.let { sourceBlockPos ->
|
|
||||||
val branchesVisited = ArrayList<WireGraphCursor>()
|
|
||||||
val points = ArrayList<WireGraphCursor>() // a queue, enqueued at the end
|
|
||||||
var point = WireGraphCursor(sourceBlockPos + fixture.blockBoxIndexToPoint2i(bbi))
|
|
||||||
var terminate = false
|
|
||||||
|
|
||||||
fun dequeue() {
|
fun getAdjacent(cnx: Int, point: WireGraphCursor): List<WireGraphCursor> {
|
||||||
//printdbg(this, "points before deq: $points")
|
val r = ArrayList<WireGraphCursor>()
|
||||||
points.removeAt(0)
|
for (dir in intArrayOf(RIGHT,DOWN,LEFT,UP)) {
|
||||||
//printdbg(this, "points after deq: $points")
|
if (cnx and dir != 0) r.add(point.copy().moveOneCell(dir))
|
||||||
if (points.size == 0) terminate = true
|
|
||||||
else {
|
|
||||||
point = points[0]
|
|
||||||
//printdbg(this, "new point: $point")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
points.add(point.copy())
|
fixture.worldBlockPos?.let { sourceBlockPos ->
|
||||||
|
|
||||||
while (points.isNotEmpty() && !terminate) {
|
val signal = (fixture as Electric).wireEmission[bbi] ?: Vector2(0.0, 0.0)
|
||||||
// break if there are no available wires underneath
|
var point = WireGraphCursor(sourceBlockPos + fixture.blockBoxIndexToPoint2i(bbi))
|
||||||
if (world.getAllWiresFrom(point.x, point.y)?.filter { WireCodex[it].accepts == wireType }?.isEmpty() != false)
|
|
||||||
break
|
|
||||||
|
|
||||||
//printdbg(this, branchesVisited)
|
world.getAllWiresFrom(point.x, point.y)?.filter { WireCodex[it].accepts == wireType }?.forEach { wire ->
|
||||||
|
// this makes sure that only the emitters with wires installed will get traversed
|
||||||
|
world.getWireGraphOf(point.x, point.y, wire)?.let { _ ->
|
||||||
|
printdbg(this, wire)
|
||||||
|
|
||||||
|
val points = Queue<WireGraphCursor>() // a queue, enqueued at the end
|
||||||
|
var marked = HashSet<Long>()
|
||||||
|
|
||||||
// get all wires that matches 'accepts' (such as Red/Green/Blue wire) and propagate signal for each of them
|
fun mark(point: WireGraphCursor) {
|
||||||
world.getAllWiresFrom(point.x, point.y)?.filter { WireCodex[it].accepts == wireType }?.forEach { wire ->
|
marked.add(point.longHash())
|
||||||
|
// do some signal action
|
||||||
|
world.setWireEmitStateOf(point.x, point.y, wire, signal)
|
||||||
|
}
|
||||||
|
|
||||||
world.getAllWiringGraph(point.x, point.y)?.get(wire)?.let { node ->
|
fun isMarked(point: WireGraphCursor) = marked.contains(point.longHash())
|
||||||
|
fun enq(point: WireGraphCursor) = points.addFirst(point.copy())
|
||||||
|
fun deq() = points.removeLast()
|
||||||
|
|
||||||
val signal = Vector2(1.0, 0.0)//node.emitState // FIXME branching wires somehow fetches wrong signal value
|
enq(point)
|
||||||
val cnx = node.connections.toInt() // 1-15
|
mark(point)
|
||||||
val nextDirBit = cnx and (15 - point.fromWhere) // cnx minus where the old cursur was; also 1-15
|
|
||||||
//printdbg(this, "(${point.x}, ${point.y}) from ${point.fromWhere} to $nextDirBit")
|
|
||||||
|
|
||||||
// mark current position as visited
|
while (points.notEmpty()) {
|
||||||
branchesVisited.add(point.copy())
|
point = deq()
|
||||||
|
// TODO if we found a power receiver, do something to it
|
||||||
// termination condition 1
|
for (x in getAdjacent(world.getWireGraphOf(point.x, point.y, wire)!!, point)) {
|
||||||
if (branchesVisited.linearSearch { it.x == point.x && it.y == point.y }!! < branchesVisited.lastIndex) {
|
if (!isMarked(x)) {
|
||||||
//printdbg(this, "(${point.x}, ${point.y}) was already visited")
|
mark(x)
|
||||||
dequeue()
|
enq(x)
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
when (nextDirBit.bitCount()) {
|
|
||||||
in 5..64 -> { throw IllegalArgumentException("Bad nextDirBit: $nextDirBit") }
|
|
||||||
// nowhere to go
|
|
||||||
0 -> {
|
|
||||||
dequeue()
|
|
||||||
}
|
|
||||||
// only one direction to go
|
|
||||||
1 -> {
|
|
||||||
// move the "cursor"
|
|
||||||
point.moveOneCell(nextDirBit)
|
|
||||||
|
|
||||||
// propagate the signal to next position
|
|
||||||
world.setWireEmitStateOf(point.x, point.y, wire, signal)
|
|
||||||
}
|
|
||||||
// two, three or four (starting point only) directions to go
|
|
||||||
else -> {
|
|
||||||
// mark this branch
|
|
||||||
//branchesVisited.add(point.copy())
|
|
||||||
|
|
||||||
// spawn and move the "cursor" by try right, down, left then up
|
|
||||||
val movableDirs = IntArrayStack(4)
|
|
||||||
for (s in 3 downTo 0) { // so that top of the stack holds lowest of the direction-number
|
|
||||||
(nextDirBit and (1 shl s)).let {
|
|
||||||
if (it != 0) movableDirs.push(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//printdbg(this, movableDirs.depth) // stack size is correct..?
|
|
||||||
// take top of the stack as mine
|
|
||||||
val mine = movableDirs.pop()
|
|
||||||
|
|
||||||
while (movableDirs.isNotEmpty()) {
|
|
||||||
// obviously 'point' must not me altered beforehand
|
|
||||||
movableDirs.pop().let { dir ->
|
|
||||||
points.add(point.copy().moveOneCell(dir))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//printdbg(this, points) // and points are also correct...
|
|
||||||
|
|
||||||
// finally move the cursor of mine
|
|
||||||
point.moveOneCell(mine)
|
|
||||||
|
|
||||||
// propagate the signal to next position
|
|
||||||
world.setWireEmitStateOf(point.x, point.y, wire, signal)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//printdbg(this, "Point = $point")
|
printdbg(this, "------------------------------------------")
|
||||||
} // end While
|
|
||||||
|
|
||||||
//printdbg(this, "------------------------------------------")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,5 +568,7 @@ object WorldSimulator {
|
|||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun longHash() = x.toLong().shl(32) or y.toLong()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,11 +35,13 @@ class FixtureLogicSignalEmitter(nameFun: () -> String)
|
|||||||
|
|
||||||
override fun update(delta: Float) {
|
override fun update(delta: Float) {
|
||||||
// set emit
|
// set emit
|
||||||
worldBlockPos?.let { (x, y) ->
|
/*worldBlockPos?.let { (x, y) ->
|
||||||
WireCodex.getAll().filter { it.accepts == "digital_bit" }.forEach { prop ->
|
WireCodex.getAll().filter { it.accepts == "digital_bit" }.forEach { prop ->
|
||||||
world?.setWireEmitStateOf(x, y, prop.id, wireEmission[0]!!)
|
// only set a state of wire that actually exists on the world
|
||||||
|
if (world?.getWireGraphOf(x, y, prop.id) != null)
|
||||||
|
world?.setWireEmitStateOf(x, y, prop.id, wireEmission[0]!!)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user