From 7bb921321f6ad58f99cbf353e801d75c85a9d8b3 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Wed, 11 Aug 2021 16:45:39 +0900 Subject: [PATCH] wire: off-to-on traversal of nonbranching wire connection --- src/net/torvald/terrarum/Terrarum.kt | 2 + .../terrarum/gameworld/WorldSimulator.kt | 138 ++++++++++++------ .../gameitems/WireGraphDebugger.kt | 4 +- 3 files changed, 100 insertions(+), 44 deletions(-) diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 80c7b53f7..6d182b81d 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -531,6 +531,8 @@ fun Int.abs() = this.absoluteValue fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit) fun Boolean.toInt() = if (this) 1 else 0 +fun Int.bitCount() = java.lang.Integer.bitCount(this) +fun Long.bitCount() = java.lang.Long.bitCount(this) fun absMax(left: Double, right: Double): Double { diff --git a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt index f4069e9b6..9bb1f7f1a 100644 --- a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt +++ b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.gameworld import com.badlogic.gdx.Input import net.torvald.terrarum.* +import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex @@ -476,58 +477,111 @@ object WorldSimulator { } private fun traverseWireGraph(world: GameWorld, fixture: FixtureBase, wireType: String, bbi: BlockBoxIndex) { - fixture.worldBlockPos?.let { - val branchesVisited = ArrayList() - val branchingStack = Stack() - val point = it + fixture.blockBoxIndexToPoint2i(bbi) - branchingStack.push(point.copy()) + fixture.worldBlockPos?.let { sourceBlockPos -> + val branchesVisited = ArrayList() + val points = ArrayList() // a queue, enqueued at the end + var point = WireGraphCursor(sourceBlockPos + fixture.blockBoxIndexToPoint2i(bbi)) + var terminate = false + + fun dequeue() { + points.removeAt(0) + if (points.size == 0) terminate = true + else point = points[0] + } + + points.add(point.copy()) + + 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 + + printdbg(this, branchesVisited) - while (branchingStack.isNotEmpty()) { // 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 -> + world.getAllWiringGraph(point.x, point.y)?.get(wire)?.let { node -> - val cnx = node.connections.toInt() - when (wireConToStatus[cnx]) { - WireConStatus.THRU -> { - // TODO - } - WireConStatus.END -> { - // TODO - } - WireConStatus.BRANCH -> { - // TODO - branchingStack.push(point.copy()) + + val signal = node.emitState + 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") + + // 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 4..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 or three directions to go + else -> { + return + + // propagate the signal + + // mark this branch + points.add(point.copy()) + + // move the "cursor" by try right, down, left then up + + } } } } } - } + + printdbg(this, "Point = $point") + } // end While + + printdbg(this, "------------------------------------------") } } - private enum class WireConStatus { THRU, END, BRANCH } - private val wireConToStatus = arrayOf( - WireConStatus.END, // 0000 - WireConStatus.END, // 0001 - WireConStatus.END, // 0010 - WireConStatus.THRU,// 0011 - WireConStatus.END, // 0100 - WireConStatus.THRU,// 0101 - WireConStatus.THRU,// 0110 - WireConStatus.BRANCH,// 0111 - WireConStatus.END, // 1000 - WireConStatus.THRU,// 1001 - WireConStatus.THRU,// 1010 - WireConStatus.BRANCH,// 1011 - WireConStatus.THRU,// 1100 - WireConStatus.BRANCH,// 1101 - WireConStatus.BRANCH,// 1110 - WireConStatus.BRANCH // 1111 - ) + private fun getNearbyTilesPos(x: Int, y: Int): Array { + return arrayOf( + Point2i(x + 1, y), + Point2i(x, y - 1), + Point2i(x - 1, y), + Point2i(x, y + 1) // don't know why but it doesn't work if I don't flip Y + ) + } - data class WireGraphBranch( - val x: Int, - val y: Int, - val con: Byte - ) + data class WireGraphCursor( + var x: Int, + var y: Int, + var fromWhere: Int, //1: right, 2: down, 4: left, 8: up, 0: *shrug* + var len: Int + ) { + constructor(point2i: Point2i): this(point2i.x, point2i.y, 0, 0) + + fun moveOneCell(dir: Int) { + when (dir) { + 1 -> { x += 1; fromWhere = 4 } + 2 -> { y += 1; fromWhere = 8 } + 4 -> { x -= 1; fromWhere = 1 } + 8 -> { y -= 1; fromWhere = 2 } + else -> throw IllegalArgumentException("Unacceptable direction: $dir") + } + len += 1 + } + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt index f15202d52..b89ba4279 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/WireGraphDebugger.kt @@ -46,11 +46,11 @@ class WireGraphDebugger(originalID: ItemID) : GameItem(originalID) { sb.clear() Terrarum.ingame!!.world.getAllWiringGraph(mx, my)?.let { - it.forEachIndexed { index, (itemID, simCell) -> + it.forEach { (itemID, simCell) -> if (sb.isNotEmpty()) sb.append('\n') - val connexionIcon = (simCell.con + 0xE0A0).toChar() + val connexionIcon = (simCell.connections + 0xE0A0).toChar() val wireName = WireCodex[itemID].nameKey val emit = simCell.emitState