1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
//! This module contains types and traits related to decision agents.
//!
//! Decision agents are responsible for choosing the best action based on the current
//! state of the simulation. They interact with movable objects on rail tracks, such as trains,
//! to control their movement.
use std::any::Any;
use std::fmt;
use std::time::Duration;
pub mod decision_agent_factory;
mod forward_until_target_agent;
use super::SimulationEnvironment;
pub use forward_until_target_agent::ForwardUntilTargetAgent;
#[cfg(feature = "ai")]
pub use crate::ai::TrainAgentAI;
/// Represents the possible actions a movable object on rail tracks can take in the simulation.
#[derive(PartialEq, Eq, Hash, Clone, Debug, Default)]
pub enum RailMovableAction {
/// Bring the movable object to a stop.
#[default]
Stop,
/// Accelerate the movable object forward with a specified acceleration.
AccelerateForward {
/// Acceleration in millimeters per second squared (mm/s²).
acceleration: i32,
},
/// Accelerate the movable object backward with a specified acceleration.
AccelerateBackward {
/// Acceleration in millimeters per second squared (mm/s²).
acceleration: i32,
},
}
impl fmt::Display for RailMovableAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RailMovableAction::AccelerateForward { .. } => write!(f, "AccelerateForward"),
RailMovableAction::AccelerateBackward { .. } => write!(f, "AccelerateBackward"),
RailMovableAction::Stop => write!(f, "Stop"),
}
}
}
/// A trait that represents a decision agent responsible for choosing the best action
/// based on the current state of the simulation.
pub trait DecisionAgent: Send + Any {
/// The associated action type for this decision agent.
type A;
/// Returns the best action based on the current state of the simulation.
///
/// # Returns
///
/// * `Self::A` - The action chosen by the decision agent.
fn next_action(&self, delta_time: Option<Duration>) -> Self::A;
/// Observes the current environment and updates the agent's internal state.
///
/// # Arguments
///
/// * `environment` - The current environment.
fn observe(&mut self, environment: &SimulationEnvironment);
/// Returns a reference to the `Any` trait for this object.
///
/// This method is useful for downcasting the object to a concrete type
/// when working with trait objects.
///
/// # Returns
///
/// A reference to the `Any` trait for the object.
///
fn as_any(&self) -> &dyn Any;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rail_moveable_actions() {
let actions = vec![
RailMovableAction::Stop,
RailMovableAction::AccelerateForward { acceleration: 50 },
RailMovableAction::AccelerateBackward { acceleration: 20 },
];
if let RailMovableAction::Stop = actions[0] {
assert!(true);
} else {
assert!(false, "Expected Stop action");
}
if let RailMovableAction::AccelerateForward { acceleration } = actions[1] {
assert_eq!(acceleration, 50);
} else {
assert!(false, "Expected AccelerateForward action");
}
if let RailMovableAction::AccelerateBackward { acceleration } = actions[2] {
assert_eq!(acceleration, 20);
} else {
assert!(false, "Expected AccelerateBackward action");
}
}
}