#![feature(coroutines, coroutine_trait)]
use std::collections::HashMap;
use std::fmt::{Display, Formatter, Result};
use rand::{
distributions::{Distribution, Uniform},
rngs::SmallRng as Rng,
SeedableRng,
};
use rand_distr::Exp;
use desim::prelude::*;
use desim::resources::SimpleResource;
use CarState::*;
const NUM_MACHINES: usize = 4; const NUM_CARS: usize = 40_000; const SIM_TIME: f64 = 10000.0; const LAMBDA_DRIVE: f32 = 5.0; const LAMBDA_WASH: f32 = 2.0;
#[derive(Copy, Clone, Debug)]
enum CarState {
Drive(f32),
WaitMachine(ResourceId),
Wash(f32),
Leave(ResourceId),
}
impl SimState for CarState {
fn get_effect(&self) -> Effect {
match self {
Drive(t) => Effect::TimeOut(*t as f64),
WaitMachine(r) => Effect::Request(*r),
Wash(t) => Effect::TimeOut(*t as f64),
Leave(r) => Effect::Release(*r),
}
}
fn set_effect(&mut self, _: Effect) {
}
fn should_log(&self) -> bool {
true
}
}
impl Display for CarState {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Drive(t) => write!(f, "Drive for {} minutes", t),
WaitMachine(_) => write!(f, "Waiting a machine"),
Wash(t) => write!(f, "Washing for {} minutes", t),
Leave(_) => write!(f, "Clean! Leaving carwash"),
}
}
}
fn car_process<'a>(
carwash: ResourceId,
rng: &'a mut Rng,
distr_drive: &'a impl Distribution<f32>,
distr_wash: &'a impl Distribution<f32>,
) -> Box<Process<CarState>> {
let t_drive = distr_drive.sample(rng);
let t_wash = distr_wash.sample(rng);
Box::new(move |_| {
yield Drive(t_drive);
yield WaitMachine(carwash);
yield Wash(t_wash);
yield Leave(carwash);
})
}
fn main() {
let mut sim = Simulation::new();
let carwash = sim.create_resource(Box::new(SimpleResource::new(NUM_MACHINES)));
let mut rng = Rng::from_entropy();
let unif = Uniform::new(0.0, SIM_TIME);
let distr_drive = Exp::new(1.0 / LAMBDA_DRIVE).unwrap();
let distr_wash = Exp::new(1.0 / LAMBDA_WASH).unwrap();
for t in unif.sample_iter(rng.clone()).take(NUM_CARS) {
let p = sim.create_process(car_process(carwash, &mut rng, &distr_drive, &distr_wash));
sim.schedule_event(t, p, CarState::Drive(0.0));
}
sim = sim.run(EndCondition::NoEvents);
for (e, state) in sim.processed_events() {
println!("{}\t{}", e.time(), state);
}
let mut wait_start_time = HashMap::new();
let sum: (f64, f64) = sim
.processed_events()
.iter()
.filter_map(|(e, state)| match state {
WaitMachine(_) => {
wait_start_time.insert(e.process(), e.time());
None
}
Wash(_) => Some(e.time() - wait_start_time.remove(&e.process()).unwrap()),
_ => None,
})
.fold((0.0, 0.0), |(t, c), t0| (t + t0, c + 1.0));
println!("The average waiting time was: {}", sum.0 / sum.1);
}