add FlowGraphic

This commit is contained in:
tursom 2021-08-17 13:46:27 +08:00
parent 3610737e47
commit dcbfaeb033
3 changed files with 261 additions and 1 deletions

View File

@ -9,6 +9,7 @@ dependencies {
compileOnly("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
compileOnly(group = "com.google.code.gson", name = "gson", version = "2.8.6")
compileOnly(group = "io.netty", name = "netty-all", version = "4.1.43.Final")
testImplementation(group = "junit", name = "junit", version = "4.12")
}
@kotlin.Suppress("UNCHECKED_CAST")

View File

@ -0,0 +1,259 @@
import org.junit.Test
data class Flow(
val source: Edge,
val sourceFlowChannel: Int,
val targetFlowChannel: Int,
val fraction: Int = 0,
)
enum class FlowChannel(val index: Int) {
A(0), B(1)
}
class Edge {
companion object {
val invMap = intArrayOf(1, 0)
}
private val sourceList: ArrayList<Flow> = ArrayList()
private val flow: IntArray = IntArray(2)
private val flowCache: IntArray = IntArray(2)
operator fun get(channel: FlowChannel) = flow[channel.index]
operator fun set(channel: FlowChannel, value: Int) {
flow[channel.index] = value
}
fun addFlow(flow: Flow) {
sourceList.add(flow)
}
fun addFlow(vararg flows: Flow) {
flows.forEach { flow ->
sourceList.add(flow)
}
}
fun calc() {
flowCache.fill(0)
sourceList.forEach { (source, sourceFlowId, targetFlowId, fraction) ->
flowCache[targetFlowId] += source.flow[sourceFlowId] shr fraction
}
}
fun finishCalc() {
repeat(2) { index ->
flow[index] = flowCache[index]
}
}
fun finishCalc(channel: FlowChannel) {
flow[channel.index] = flowCache[channel.index]
}
fun changed(): Boolean {
repeat(2) { index ->
if (flow[index] != flowCache[index]) {
return true
}
}
return false
}
override fun toString(): String {
return "Edge(flow=${flow.contentToString()}, flowCache=${flowCache.contentToString()})"
}
}
class Graphic(
var precision: Int = 8,
) : Iterable<Edge> {
companion object {
inline operator fun invoke(
builder: GraphicBuilder.() -> Unit,
) = GraphicBuilder().also(builder).build()
}
private val edgeList = ArrayList<Edge>()
var input: Int = 0
var inputFlowChannel: FlowChannel = FlowChannel.A
fun addEdge(edge: Edge): Int {
edgeList.add(edge)
return edgeList.size - 1
}
fun getEdge(id: Int): Edge = edgeList[id]
fun calc() {
edgeList[input][inputFlowChannel] = 1 shl precision
edgeList.forEach { edge ->
edge.calc()
}
}
fun changed(): Boolean {
edgeList[input].finishCalc(inputFlowChannel)
edgeList.forEach { edge ->
if (edge.changed()) {
return true
}
}
return false
}
fun finishCalc() {
edgeList.forEach { edge ->
edge.finishCalc()
}
}
fun result(): List<Pair<Int, Int>> {
return edgeList.map { it[FlowChannel.A] to it[FlowChannel.B] }
}
override fun iterator(): Iterator<Edge> = edgeList.iterator()
class GraphicBuilder {
var precision: Int = 8
val edgeMap = ArrayList<EdgeBuilder>()
inline fun edge(builder: EdgeBuilder.() -> Unit) {
edgeMap.add(EdgeBuilder(edgeMap.size).also(builder))
}
fun build(): Graphic {
val graphic = Graphic(precision)
repeat(edgeMap.size) {
graphic.addEdge(Edge())
}
edgeMap.forEach { builder ->
builder.init(graphic)
}
return graphic
}
}
class EdgeBuilder(private val id: Int) {
private val flowList = ArrayList<FlowBuilder>()
fun init(graphic: Graphic) {
val edge = graphic.getEdge(id)
flowList.forEach { (source, sourceFlowChannel, targetFlowChannel, fraction) ->
edge.addFlow(Flow(
graphic.getEdge(source),
sourceFlowChannel, targetFlowChannel, fraction
))
}
}
fun flow(
source: Int,
sourceFlowChannel: Int,
targetFlowChannel: Int,
fraction: Int = 0,
) {
flowList.add(FlowBuilder(source, sourceFlowChannel, targetFlowChannel, fraction))
}
}
data class FlowBuilder(
val source: Int,
val sourceFlowChannel: Int,
val targetFlowChannel: Int,
val fraction: Int = 0,
)
}
class FlowExample {
@Test
fun test() {
val graphic = getTestGraphic()
graphic.precision = 8
var changed = true
var it = 0
while (changed) {
it++
graphic.calc()
changed = graphic.changed()
println("step $it changed $changed")
graphic.finishCalc()
println(graphic.result())
}
}
fun getTestGraphic() = Graphic {
// 0
edge {
flow(1, 1, 1, 1)
flow(6, 1, 1, 1)
}
// 1
edge {
flow(0, 0, 0, 1)
flow(6, 1, 0, 1)
flow(7, 1, 1, 1)
flow(2, 1, 1, 1)
}
// 2
edge {
flow(1, 0, 0, 1)
flow(7, 1, 0, 1)
flow(8, 1, 1, 1)
flow(3, 1, 1, 1)
}
// 3
edge {
flow(1, 0, 0, 1)
flow(8, 1, 0, 1)
flow(9, 1, 1, 1)
flow(4, 0, 1, 1)
}
// 4
edge {
flow(5, 0, 0, 1)
flow(10, 1, 0, 1)
flow(3, 0, 1, 1)
flow(9, 1, 1, 1)
}
// 5
edge {
flow(6, 0, 0, 1)
flow(11, 1, 0, 1)
flow(4, 1, 1, 1)
flow(0, 1, 1, 1)
}
// 6
edge {
flow(0, 0, 0, 1)
flow(1, 1, 0, 1)
flow(5, 1, 1, 1)
flow(11, 1, 1, 1)
}
// 7
edge {
flow(1, 0, 0, 1)
flow(2, 1, 0, 1)
}
// 8
edge {
flow(2, 0, 0, 1)
flow(3, 1, 0, 1)
}
// 9
edge {
flow(3, 0, 0, 1)
flow(4, 0, 0, 1)
}
// 10
edge {
flow(5, 0, 0, 1)
flow(4, 1, 0, 1)
}
// 11
edge {
flow(6, 0, 0, 1)
flow(5, 1, 0, 1)
}
}
}

View File

@ -218,7 +218,7 @@ open class WebSocketClient<in T : WebSocketClient<T, H>, H : WebSocketHandler<T,
companion object {
private val threadId = AtomicInteger()
private val group: EventLoopGroup = NioEventLoopGroup(0, ThreadFactory {
val group: EventLoopGroup = NioEventLoopGroup(0, ThreadFactory {
val thread = Thread(it, "WebSocketClient-${threadId.incrementAndGet()}")
thread.isDaemon = true
thread