use crate::types::AgentId;
use rand::seq::SliceRandom;
use rand::Rng;
use crate::{model::Model, standard::HasAgentIds};
pub trait Scheduler<M> {
fn schedule_into(&mut self, model: &M, buf: &mut Vec<AgentId>);
}
#[derive(Debug, Default)]
pub struct Fastest;
impl Fastest {
pub const fn new() -> Self {
Self
}
}
impl<M> Scheduler<M> for Fastest
where
M: HasAgentIds,
{
fn schedule_into(&mut self, model: &M, buf: &mut Vec<AgentId>) {
model.agent_ids_into(buf);
}
}
#[derive(Debug, Default)]
pub struct ById;
impl ById {
pub fn new() -> Self {
Self
}
}
impl<M> Scheduler<M> for ById
where
M: HasAgentIds,
{
fn schedule_into(&mut self, model: &M, buf: &mut Vec<AgentId>) {
model.agent_ids_into(buf);
buf.sort_unstable();
}
}
#[derive(Debug, Default)]
pub struct Randomly;
impl Randomly {
pub fn new() -> Self {
Self
}
}
impl<M> Scheduler<M> for Randomly
where
M: HasAgentIds + Model,
{
fn schedule_into(&mut self, model: &M, buf: &mut Vec<AgentId>) {
model.agent_ids_into(buf);
buf.shuffle(&mut *model.rng_mut());
}
}
#[derive(Debug)]
pub struct PartiallyRandom {
probability: f64,
}
impl PartiallyRandom {
pub fn new(probability: f64) -> Self {
Self { probability }
}
}
impl<M> Scheduler<M> for PartiallyRandom
where
M: HasAgentIds + Model,
{
fn schedule_into(&mut self, model: &M, buf: &mut Vec<AgentId>) {
model.agent_ids_into(buf);
let mut rng = model.rng_mut();
buf.retain(|_| rng.gen_bool(self.probability));
}
}
#[derive(Debug)]
pub struct ByProperty<F> {
selector: F,
}
impl<F> ByProperty<F> {
pub fn new(selector: F) -> Self {
Self { selector }
}
}
impl<M, F, K> Scheduler<M> for ByProperty<F>
where
M: HasAgentIds + Model,
F: Fn(&M::Agent) -> K,
K: Ord,
{
fn schedule_into(&mut self, model: &M, buf: &mut Vec<AgentId>) {
model.agent_ids_into(buf);
buf.retain(|id| model.agent(*id).is_some());
let selector = &self.selector;
buf.sort_by(|a, b| {
let agent_a = model.agent(*a);
let agent_b = model.agent(*b);
match (agent_a, agent_b) {
(Some(agent_a), Some(agent_b)) => {
let ka = selector(&agent_a);
let kb = selector(&agent_b);
kb.cmp(&ka)
}
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => std::cmp::Ordering::Equal,
}
});
}
}