use std::thread;
use crate::traits::{Agent, Environment};
pub type EnvResult = Result<Box<dyn Environment>, &'static str>;
pub type VoidResult = Result<(), &'static str>;
pub fn generate_default_env<A>(pop_size: u64) -> EnvResult
where
A: 'static + Agent,
{
let mut pop: Vec<Box<dyn Agent>> = vec![];
for _ in 0..pop_size {
let agent: Box<dyn Agent> = A::generate()?;
pop.push(agent);
}
let env: Box<DefaultEnvironment> = DefaultEnvironment::generate(pop)?;
Ok(env)
}
pub fn tick(environment: &mut Box<dyn Environment>) -> VoidResult {
environment.tick()?;
Ok(())
}
pub fn tick_collect(environment: &mut Box<dyn Environment>) -> VoidResult {
environment.tick()?;
environment.collect()?;
Ok(())
}
pub fn collect(environment: Box<dyn Environment>) -> VoidResult {
environment.collect()?;
Ok(())
}
pub fn generate_default_tick_collect<A>(pop_size: u64, ticks: u64, runs: u64) -> VoidResult
where
A: 'static + Agent,
{
let mut v = vec![];
for _ in 0..runs{
v.push(thread::spawn(move || -> Result<(), &'static str> {
let mut env: Box<dyn Environment> = generate_default_env::<A>(pop_size)?;
for _ in 0..ticks {
tick(&mut env)?;
}
collect(env)?;
Ok(())
}));
}
for handle in v {
handle.join().unwrap().unwrap();
}
Ok(())
}
pub fn generate_env<E, A>(pop_size: u64) -> EnvResult
where
E: 'static + Environment,
A: 'static + Agent,
{
let mut pop: Vec<Box<dyn Agent>> = vec![];
for _ in 0..pop_size {
let agent: Box<dyn Agent> = A::generate()?;
pop.push(agent);
}
let env: Box<E> = E::generate(pop)?;
Ok(env)
}
pub fn generate_tick_collect<E, A>(pop_size: u64, ticks: u64, runs: u64) -> VoidResult
where
E: 'static + Environment,
A: 'static + Agent,
{
let mut v = vec![];
for _ in 0..runs {
v.push(thread::spawn(move || -> Result<(), &'static str> {
let mut env: Box<dyn Environment> = generate_env::<E, A>(pop_size)?;
for _ in 0..ticks {
tick(&mut env)?;
}
collect(env)?;
Ok(())
}));
}
for handle in v {
handle.join().unwrap().unwrap();
}
Ok(())
}
struct DefaultEnvironment {
population: Vec<Box<dyn Agent>>,
}
impl Environment for DefaultEnvironment {
fn generate(population: Vec<Box<dyn Agent>>) -> Result<Box<Self>, &'static str> {
Ok(Box::new(Self { population }))
}
fn collect(&self) -> Result<String, &'static str> {
for agent in &self.population {
agent.collect()?;
}
Ok("".into())
}
fn tick(&mut self) -> VoidResult {
let mut pop: Vec<Box<dyn Agent>> = vec![];
for _ in 0..self.population.len() {
let agent: Option<Box<dyn Agent>> = self.population.pop();
if let Some(mut agent) = agent {
agent.tick()?;
pop.push(agent);
};
}
self.population = pop;
Ok(())
}
fn add_agent(&mut self, agent: Box<dyn Agent>) -> VoidResult {
self.population.push(agent);
Ok(())
}
fn add_agents(&mut self, agents: Vec<Box<dyn Agent>>) -> VoidResult {
for agent in agents {
self.population.push(agent);
}
Ok(())
}
}