it.unibo.alchemist.model.cognitive.steering.Weighted.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alchemist-cognitive-agents Show documentation
Show all versions of alchemist-cognitive-agents Show documentation
Abstraction for group of pedestrians capable of influence each other emotionally.
/*
* Copyright (C) 2010-2023, Danilo Pianini and contributors
* listed, for each module, in the respective subproject's build.gradle.kts file.
*
* This file is part of Alchemist, and is distributed under the terms of the
* GNU General Public License, with a linking exception,
* as described in the file LICENSE in the Alchemist distribution's top directory.
*/
package it.unibo.alchemist.model.cognitive.steering
import it.unibo.alchemist.model.Node
import it.unibo.alchemist.model.cognitive.GroupSteeringAction
import it.unibo.alchemist.model.cognitive.SteeringAction
import it.unibo.alchemist.model.cognitive.SteeringActionWithTarget
import it.unibo.alchemist.model.cognitive.SteeringStrategy
import it.unibo.alchemist.model.environments.Euclidean2DEnvironment
import it.unibo.alchemist.model.positions.Euclidean2DPosition
/**
* A [SteeringStrategy] performing a weighted sum of steering actions (see [computeNextPosition]).
*
* @param environment
* the environment in which the node moves.
* @param node
* the owner of the steering actions combined by this strategy.
* @param weight
* lambda used to assign a weight to each steering action: the higher the weight, the greater the
* importance of the action.
*/
open class Weighted(
private val environment: Euclidean2DEnvironment,
private val node: Node,
private val weight: SteeringAction.() -> Double,
) : SteeringStrategy {
/**
* [actions] are partitioned in group steering actions and non-group steering actions. The overall next position
* for each of these two sets of actions is computed via weighted sum. The resulting vectors are then summed
* together (with unitary weight).
*/
override fun computeNextPosition(actions: List>): Euclidean2DPosition =
actions.partition { it is GroupSteeringAction }.let { (groupActions, steerActions) ->
groupActions.calculatePosition() + steerActions.calculatePosition()
}
/**
* If there's no [SteeringActionWithTarget] among the provided [actions], a zero vector is returned. Otherwise,
* the closest target is picked.
*/
override fun computeTarget(actions: List>): Euclidean2DPosition =
environment.getPosition(node).let { currPos ->
actions.filterIsInstance>()
.map { it.target() }
.minByOrNull { it.distanceTo(currPos) }
?: currPos
}
private fun List>.calculatePosition(): Euclidean2DPosition = when {
size > 1 ->
map { it.nextPosition() to it.weight() }.run {
val totalWeight = map { it.second }.sum()
map { it.first * (it.second / totalWeight) }.reduce { acc, pos -> acc + pos }
}
else -> firstOrNull()?.nextPosition() ?: environment.origin
}
}