use rand::Rng;
use statistical;
use std::{
sync::{self, mpsc::Sender},
thread,
};
fn calculate(
number_of_toys: usize,
number_of_loops: u32,
sender: Option<Sender<Vec<i32>>>,
) -> Vec<i32> {
let mut probability: Vec<i32> = Vec::new();
for _i in 0..number_of_loops {
let mut prizes = vec![0; number_of_toys];
let mut opens = 0;
while prizes.contains(&0) {
let high = prizes.len();
prizes[rand::thread_rng().gen_range(0, high)] += 1;
opens += 1
}
probability.push(opens)
}
probability.shrink_to_fit();
match sender {
Some(tx) => tx.send(probability.clone()).unwrap(),
None => (),
}
probability
}
#[derive(Debug, Clone)]
pub struct CerealResults {
data: Vec<i32>,
mean: Option<f64>,
median: Option<i32>,
max: Option<i32>,
min: Option<i32>,
cache: bool,
}
impl CerealResults {
fn new(data: Vec<i32>) -> CerealResults {
CerealResults {
data,
mean: None,
median: None,
max: None,
min: None,
cache: false,
}
}
pub fn mean(&self) -> f64 {
statistical::mean(
self.data
.clone()
.into_iter()
.map(|datum| datum as f64)
.collect::<Vec<f64>>()
.as_ref(),
)
}
pub fn median(&self) -> i32 {
statistical::median(self.data.as_slice())
}
pub fn max(&self) -> i32 {
*self.data.iter().max().unwrap()
}
pub fn min(&self) -> i32 {
*self.data.iter().min().unwrap()
}
}
pub fn simulation_change_toys(
number_of_toys: usize,
number_of_loops: u32,
number_of_threads: u32,
) -> CerealResults {
match number_of_loops {
0 => CerealResults::new(vec![0]),
_ => {
let child_load = (number_of_loops as f32 / number_of_threads as f32).floor() as u32;
let (tx, rx) = sync::mpsc::channel();
for _i in 0..number_of_threads {
let tx_clone = sync::mpsc::Sender::clone(&tx);
thread::spawn(move || {
calculate(number_of_toys, child_load.clone(), Some(tx_clone))
});
}
let load = (number_of_loops as f32 / number_of_threads as f32).ceil() as u32;
calculate(number_of_toys, load, Some(tx));
let mut probability = Vec::new();
rx.iter()
.for_each(|mut datum| probability.append(&mut datum));
CerealResults::new(probability)
}
}
}
pub fn simulation(number_of_loops: u32, number_of_threads: u32) -> CerealResults {
simulation_change_toys(6, number_of_loops, number_of_threads)
}
pub fn single_thread_change_toys(number_of_toys: usize, number_of_loops: u32) -> CerealResults {
match number_of_loops {
0 => CerealResults::new(vec![0]),
_ => CerealResults::new(calculate(number_of_toys, number_of_loops, None)),
}
}
pub fn simulation_single_thread(number_of_loops: u32) -> CerealResults {
single_thread_change_toys(6, number_of_loops)
}