mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +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 wiringGraph = HashMap<BlockAddress, HashMap<ItemID, WiringSimCell>>()
|
||||
private val WIRE_POS_MAP = byteArrayOf(1,2,4,8)
|
||||
private val WIRE_ANTIPOS_MAP = byteArrayOf(4,8,1,2)
|
||||
private val WIRE_POS_MAP = intArrayOf(1,2,4,8)
|
||||
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.
|
||||
@@ -334,11 +334,11 @@ open class GameWorld : Disposable {
|
||||
// figure out wiring graphs
|
||||
val matchingNeighbours = WireActor.WIRE_NEARBY.mapIndexed { index, (tx, ty) ->
|
||||
(getAllWiresFrom(x + tx, y + ty)?.contains(tile) == true).toInt() shl index
|
||||
}.sum().toByte()
|
||||
}.sum()
|
||||
// setup graph of mine
|
||||
setWireGraphOfUnsafe(blockAddr, tile, matchingNeighbours)
|
||||
// setup graph for neighbours
|
||||
for (i in 0.toByte() .. 3.toByte()) {
|
||||
for (i in 0..3) {
|
||||
if (matchingNeighbours and WIRE_POS_MAP[i] > 0) {
|
||||
val (tx, ty) = WireActor.WIRE_NEARBY[i]
|
||||
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 blockAddr = LandUtil.getBlockAddr(this, x, y)
|
||||
return getWireGraphUnsafe(blockAddr, itemID)
|
||||
}
|
||||
|
||||
fun getWireGraphUnsafe(blockAddr: BlockAddress, itemID: ItemID): Byte? {
|
||||
fun getWireGraphUnsafe(blockAddr: BlockAddress, itemID: ItemID): Int? {
|
||||
return wiringGraph[blockAddr]?.get(itemID)?.connections
|
||||
}
|
||||
|
||||
@@ -377,19 +377,19 @@ open class GameWorld : Disposable {
|
||||
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 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)
|
||||
wiringGraph[blockAddr] = HashMap()
|
||||
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) {
|
||||
@@ -647,7 +647,7 @@ open class GameWorld : Disposable {
|
||||
* These values must be updated by none other than [WorldSimulator]()
|
||||
*/
|
||||
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 recvStates: ArrayList<WireRecvState> = ArrayList() // how far away are the power sources
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.utils.Queue
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
@@ -21,6 +22,7 @@ import org.dyn4j.geometry.Vector2
|
||||
import org.khelekore.prtree.*
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.experimental.and
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
@@ -480,105 +482,55 @@ object WorldSimulator {
|
||||
}
|
||||
|
||||
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() {
|
||||
//printdbg(this, "points before deq: $points")
|
||||
points.removeAt(0)
|
||||
//printdbg(this, "points after deq: $points")
|
||||
if (points.size == 0) terminate = true
|
||||
else {
|
||||
point = points[0]
|
||||
//printdbg(this, "new point: $point")
|
||||
}
|
||||
fun getAdjacent(cnx: Int, point: WireGraphCursor): List<WireGraphCursor> {
|
||||
val r = ArrayList<WireGraphCursor>()
|
||||
for (dir in intArrayOf(RIGHT,DOWN,LEFT,UP)) {
|
||||
if (cnx and dir != 0) r.add(point.copy().moveOneCell(dir))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
points.add(point.copy())
|
||||
fixture.worldBlockPos?.let { sourceBlockPos ->
|
||||
|
||||
while (points.isNotEmpty() && !terminate) {
|
||||
// break if there are no available wires underneath
|
||||
if (world.getAllWiresFrom(point.x, point.y)?.filter { WireCodex[it].accepts == wireType }?.isEmpty() != false)
|
||||
break
|
||||
val signal = (fixture as Electric).wireEmission[bbi] ?: Vector2(0.0, 0.0)
|
||||
var point = WireGraphCursor(sourceBlockPos + fixture.blockBoxIndexToPoint2i(bbi))
|
||||
|
||||
//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
|
||||
world.getAllWiresFrom(point.x, point.y)?.filter { WireCodex[it].accepts == wireType }?.forEach { wire ->
|
||||
fun mark(point: WireGraphCursor) {
|
||||
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
|
||||
val cnx = node.connections.toInt() // 1-15
|
||||
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")
|
||||
enq(point)
|
||||
mark(point)
|
||||
|
||||
// mark current position as visited
|
||||
branchesVisited.add(point.copy())
|
||||
|
||||
// termination condition 1
|
||||
if (branchesVisited.linearSearch { it.x == point.x && it.y == point.y }!! < branchesVisited.lastIndex) {
|
||||
//printdbg(this, "(${point.x}, ${point.y}) was already visited")
|
||||
dequeue()
|
||||
}
|
||||
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)
|
||||
}
|
||||
while (points.notEmpty()) {
|
||||
point = deq()
|
||||
// TODO if we found a power receiver, do something to it
|
||||
for (x in getAdjacent(world.getWireGraphOf(point.x, point.y, wire)!!, point)) {
|
||||
if (!isMarked(x)) {
|
||||
mark(x)
|
||||
enq(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printdbg(this, "Point = $point")
|
||||
} // end While
|
||||
|
||||
//printdbg(this, "------------------------------------------")
|
||||
printdbg(this, "------------------------------------------")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,5 +568,7 @@ object WorldSimulator {
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun longHash() = x.toLong().shl(32) or y.toLong()
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,13 @@ class FixtureLogicSignalEmitter(nameFun: () -> String)
|
||||
|
||||
override fun update(delta: Float) {
|
||||
// set emit
|
||||
worldBlockPos?.let { (x, y) ->
|
||||
/*worldBlockPos?.let { (x, y) ->
|
||||
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