psyche-simulator-cli 0.2.19

CLI simulator for Psyche AI Toolset
use psyche::core::sensor::SensorID;
use psyche::core::Scalar;
use serde::{Deserialize, Serialize};
use serde_json::Result as JsonResult;
use serde_yaml::Result as YamlResult;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Timeline {
    pub playing_mode: PlayingMode,
    pub actions: Vec<Action>,
}

impl Default for Timeline {
    fn default() -> Self {
        Self {
            playing_mode: Default::default(),
            actions: vec![Action {
                time: 0.0,
                action_type: ActionType::IgniteRandomSynapsesByPercentage(1.0, (1.0, 1.0)),
            }],
        }
    }
}

impl Timeline {
    #[inline]
    pub fn from_json(json: &str) -> JsonResult<Self> {
        serde_json::from_str(json)
    }

    #[inline]
    pub fn from_yaml(yaml: &str) -> YamlResult<Self> {
        serde_yaml::from_str(yaml)
    }

    #[inline]
    pub fn to_json(&self) -> JsonResult<String> {
        serde_json::to_string_pretty(self)
    }

    #[inline]
    pub fn to_yaml(&self) -> YamlResult<String> {
        serde_yaml::to_string(self)
    }

    pub fn perform(&self, mut start: Scalar, mut end: Scalar) -> Option<Vec<Action>> {
        match self.playing_mode {
            PlayingMode::Infinite => {
                if let Some(duration) = self
                    .actions
                    .iter()
                    .map(|a| a.time)
                    .max_by(|a, b| a.partial_cmp(&b).unwrap())
                {
                    if start <= duration {
                        Some(
                            self.actions
                                .iter()
                                .filter(|a| a.time >= start && a.time < end)
                                .cloned()
                                .collect(),
                        )
                    } else {
                        Some(vec![])
                    }
                } else {
                    Some(vec![])
                }
            }
            PlayingMode::Loop => {
                if let Some(duration) = self
                    .actions
                    .iter()
                    .map(|a| a.time)
                    .max_by(|a, b| a.partial_cmp(&b).unwrap())
                {
                    while start > duration {
                        start -= duration;
                    }
                    while end > duration {
                        end -= duration;
                    }
                    Some(
                        self.actions
                            .iter()
                            .filter(|a| a.time >= start && a.time < end)
                            .cloned()
                            .collect(),
                    )
                } else {
                    Some(vec![])
                }
            }
            PlayingMode::Once => {
                if let Some(duration) = self
                    .actions
                    .iter()
                    .map(|a| a.time)
                    .max_by(|a, b| a.partial_cmp(&b).unwrap())
                {
                    if start <= duration {
                        Some(
                            self.actions
                                .iter()
                                .filter(|a| a.time >= start && a.time < end)
                                .cloned()
                                .collect(),
                        )
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PlayingMode {
    Infinite,
    Loop,
    Once,
}

impl Default for PlayingMode {
    fn default() -> Self {
        PlayingMode::Once
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Action {
    pub time: Scalar,
    pub action_type: ActionType,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ActionType {
    None,
    TriggerSensorByID(SensorID, (Scalar, Scalar)),
    TriggerSensorByIndex(usize, (Scalar, Scalar)),
    TriggerRandomSensorsByPercentage(Scalar, (Scalar, Scalar)),
    TriggerRandomSensorsByAmount(usize, (Scalar, Scalar)),
    IgniteRandomSynapsesByPercentage(Scalar, (Scalar, Scalar)),
    IgniteRandomSynapsesByAmount(usize, (Scalar, Scalar)),
}