From 9c29769e454dbae3ebb4f22cac98c291df7c70eb Mon Sep 17 00:00:00 2001 From: giacomoaccursi Date: Wed, 22 Nov 2023 09:46:33 +0100 Subject: [PATCH] feat: neighborhood now observe nodes movement from environment --- src/main/kotlin/entity/Environment.kt | 4 +- src/main/kotlin/entity/EnvironmentImpl.kt | 23 ++++--- src/main/kotlin/entity/Neighborhood.kt | 9 +++ src/main/kotlin/entity/NodeEvent.kt | 32 +++++++++ src/main/kotlin/entity/SimpleNeighborhood.kt | 70 +++++++++++++++----- 5 files changed, 110 insertions(+), 28 deletions(-) create mode 100644 src/main/kotlin/entity/NodeEvent.kt diff --git a/src/main/kotlin/entity/Environment.kt b/src/main/kotlin/entity/Environment.kt index 348a31f..cf8e9b9 100644 --- a/src/main/kotlin/entity/Environment.kt +++ b/src/main/kotlin/entity/Environment.kt @@ -31,13 +31,13 @@ interface Environment { * Add a Node to the environment. * @param node the node to add. */ - fun addNode(node: Node) + suspend fun addNode(node: Node, position: Position) /** * Remove node from the environment. * @param node the node to remove */ - fun removeNode(node: Node) + suspend fun removeNode(node: Node) /** * Moves node in a new position. diff --git a/src/main/kotlin/entity/EnvironmentImpl.kt b/src/main/kotlin/entity/EnvironmentImpl.kt index 88a8dc1..b189b4c 100644 --- a/src/main/kotlin/entity/EnvironmentImpl.kt +++ b/src/main/kotlin/entity/EnvironmentImpl.kt @@ -8,35 +8,38 @@ package entity +import kotlinx.coroutines.flow.MutableSharedFlow + /** * An implementation of the environment. */ -class EnvironmentImpl : Environment { - override val nodes = ArrayList() -class EnvironmentImpl(override val nodes: ArrayList = ArrayList(), private val linkingRule: LinkingRule) : +class EnvironmentImpl(private val linkingRule: LinkingRule) : Environment { - override val neighborhoods: ArrayList = ArrayList( - nodes.map { - SimpleNeighborhood(it, this, linkingRule) - }, - ) + override val nodes: ArrayList = ArrayList() + override val nodeToPosition: HashMap = HashMap() + override val neighborhoods: ArrayList = ArrayList() + private val nodeChangeFlow: MutableSharedFlow = MutableSharedFlow() - override fun addNode(node: Node) { + override suspend fun addNode(node: Node, position: Position) { nodes.add(node) - neighborhoods.add(SimpleNeighborhood(node, this, linkingRule)) nodeToPosition[node.id] = position val neighborhood = SimpleNeighborhood(node, this, linkingRule, nodeChangeFlow) neighborhoods.add(neighborhood) + nodeChangeFlow.emit(NodeEvent.NodeAdded(node)) } override suspend fun removeNode(node: Node) { nodes.remove(node) nodeToPosition.remove(node.id) neighborhoods.remove(neighborhoods.find { it.getCenter() == node }) + nodeChangeFlow.emit(NodeEvent.NodeRemoved(node)) + } + override suspend fun moveNode(node: Node, position: Position) { println("node ${node.id} moved in position $position") nodeToPosition[node.id] = position + nodeChangeFlow.emit(NodeEvent.NodeMoved(node)) } override fun getNodePosition(node: Node): Position { diff --git a/src/main/kotlin/entity/Neighborhood.kt b/src/main/kotlin/entity/Neighborhood.kt index 4b4d650..799ce36 100644 --- a/src/main/kotlin/entity/Neighborhood.kt +++ b/src/main/kotlin/entity/Neighborhood.kt @@ -8,10 +8,19 @@ package entity +import kotlinx.coroutines.CoroutineScope + /** * Interface for a neighborhood. */ interface Neighborhood { + + /** + * Starts to observing environment nodes. + * @param scope the coroutine scope. + */ + suspend fun startObservingNodes(scope: CoroutineScope) + /** * @return the center of the neighborhood. */ diff --git a/src/main/kotlin/entity/NodeEvent.kt b/src/main/kotlin/entity/NodeEvent.kt new file mode 100644 index 0000000..46ab78c --- /dev/null +++ b/src/main/kotlin/entity/NodeEvent.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023. Accursi Giacomo + * + * Use of this source code is governed by an MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT. + */ + +package entity + +/** + * Interface for change events of a node. + */ +sealed interface NodeEvent { + /** + * New Node is added to the environment. + * @param node the added node. + */ + class NodeAdded(val node: Node) : NodeEvent + + /** + * A node is removed from the environment. + * @param node the removed node. + */ + class NodeRemoved(val node: Node) : NodeEvent + + /** + * A node is moved in the environment. + * @param node the moved node. + */ + class NodeMoved(val node: Node) : NodeEvent +} diff --git a/src/main/kotlin/entity/SimpleNeighborhood.kt b/src/main/kotlin/entity/SimpleNeighborhood.kt index 61bf2f7..545b93f 100644 --- a/src/main/kotlin/entity/SimpleNeighborhood.kt +++ b/src/main/kotlin/entity/SimpleNeighborhood.kt @@ -9,8 +9,10 @@ package entity import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch -import java.util.concurrent.CountDownLatch +import kotlin.coroutines.CoroutineContext /** * A simple implementation of a neighborhood. @@ -19,29 +21,65 @@ class SimpleNeighborhood( private val center: Node, private val environment: Environment, private val linkingRule: LinkingRule, + private val nodeChangeFlow: MutableSharedFlow, + coroutineContext: CoroutineContext = Dispatchers.Default, ) : Neighborhood { - private var neighbors: Set = setOf() - override fun startObservingNodes(scope: CoroutineScope): CountDownLatch { - val latch = CountDownLatch(environment.nodes.size) - environment.nodes.forEach { node -> - latch.countDown() - scope.launch { - node.observeNodePosition().collect { - if (node != center) { - if (linkingRule.isNeighbor(center, node)) { - neighbors += node - } else { - neighbors -= node - } - } + init { + CoroutineScope(coroutineContext).launch { + startObservingNodes(this) + } + } + + private var neighbors: Set = + linkingRule.computeNeighbors(center, environment) + + override suspend fun startObservingNodes(scope: CoroutineScope) { + scope.launch { + nodeChangeFlow.collect { event -> + when (event) { + is NodeEvent.NodeAdded -> onNodeAdded(event.node) + is NodeEvent.NodeMoved -> onNodeMoved(event.node) + is NodeEvent.NodeRemoved -> onNodeRemoved(event.node) + } + } + } + } + + private fun onNodeMoved(node: Node) { + if (node != center) { + if (linkingRule.isNeighbor(center, node, environment)) { + if (!neighbors.contains(node)) { + neighbors += node + } + } else { + if (neighbors.contains(node)) { + neighbors -= node } } + } else { + neighbors = linkingRule.computeNeighbors(center, environment) + } + } + + private fun onNodeAdded(node: Node) { + if (node != center) { + if (linkingRule.isNeighbor(center, node, environment)) { + if (!neighbors.contains(node)) { + neighbors += node + } + } + } + } + + private fun onNodeRemoved(node: Node) { + if (neighbors.contains(node)) { + neighbors -= node } - return latch } override fun getCenter() = center + override fun getNeighbors() = neighbors override fun addNeighbor(node: Node) {