From dcbfaeb033f3e4a9ce30c555846d68027e59e59a Mon Sep 17 00:00:00 2001 From: tursom Date: Tue, 17 Aug 2021 13:46:27 +0800 Subject: [PATCH] add FlowGraphic --- ts-core/build.gradle.kts | 1 + ts-core/src/test/kotlin/FlowExample.kt | 259 ++++++++++++++++++ .../cn/tursom/core/ws/WebSocketClient.kt | 2 +- 3 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 ts-core/src/test/kotlin/FlowExample.kt diff --git a/ts-core/build.gradle.kts b/ts-core/build.gradle.kts index 2be6f61..9267b40 100644 --- a/ts-core/build.gradle.kts +++ b/ts-core/build.gradle.kts @@ -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") diff --git a/ts-core/src/test/kotlin/FlowExample.kt b/ts-core/src/test/kotlin/FlowExample.kt new file mode 100644 index 0000000..0934794 --- /dev/null +++ b/ts-core/src/test/kotlin/FlowExample.kt @@ -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 = 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 { + companion object { + inline operator fun invoke( + builder: GraphicBuilder.() -> Unit, + ) = GraphicBuilder().also(builder).build() + } + + private val edgeList = ArrayList() + 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> { + return edgeList.map { it[FlowChannel.A] to it[FlowChannel.B] } + } + + override fun iterator(): Iterator = edgeList.iterator() + + class GraphicBuilder { + var precision: Int = 8 + val edgeMap = ArrayList() + 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() + 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) + } + } +} diff --git a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt index 2c4c1eb..472e3ab 100644 --- a/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt +++ b/ts-core/ts-ws-client/src/main/kotlin/cn/tursom/core/ws/WebSocketClient.kt @@ -218,7 +218,7 @@ open class WebSocketClient, H : WebSocketHandler