All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.unibo.alchemist.model.cognitive.steering.Weighted.kt Maven / Gradle / Ivy

There is a newer version: 35.0.0
Show newest version
/*
 * 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
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy