1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
// TODO: Make number of cereal boxes (length of Vec) variable.
// TODO: Generic number types?

use rand::Rng;
use statistical;
use std::{
    sync::{self, mpsc::Sender},
    thread,
};

fn calculate(number_of_loops: i32, sender: Option<Sender<Option<Vec<i32>>>>) -> Option<Vec<i32>> {
    match number_of_loops {
        0 => {
            match sender {
                Some(tx) => tx.send(None).unwrap(),
                None => (),
            }
            None
        }
        _ => {
            let mut probability: Vec<i32> = Vec::new();
            // Simulation loop
            for _i in 0..number_of_loops {
                let mut prizes: [i32; 6] = [0, 0, 0, 0, 0, 0];
                let mut opens: i32 = 0;
                // loop until owns every prize
                while prizes.contains(&0) {
                    prizes[rand::thread_rng().gen_range(0, 6)] += 1;
                    opens += 1
                }
                probability.push(opens)
            }
            probability.shrink_to_fit();
            let probability = Some(probability);
            match sender {
                Some(tx) => tx.send(probability.clone()).unwrap(),
                None => (),
            }
            probability
        }
    }
}

pub fn simulation(number_of_loops: i32, number_of_threads: i32) -> Vec<i32> {
    if number_of_loops < 0 {
        panic!(
            "Set number of loops greater than -1. You set it to {}.",
            number_of_loops
        )
    } else if number_of_threads < 0 {
        panic!(
            "Set number of threads greater than -1. You set it to {}",
            number_of_threads
        )
    }
    // Avoid divide by zero errors with this check
    match number_of_loops {
        0 => vec![0],
        _ => {
            let child_load = (number_of_loops as f32 / number_of_threads as f32).floor() as i32;
            // Create channel
            let (tx, rx) = sync::mpsc::channel();
            for _i in 0..number_of_threads {
                // Create a sender and a number of loop for the other thread
                let tx_clone = sync::mpsc::Sender::clone(&tx);
                let child_load_clone = child_load.clone();
                // Spawn thread for calculations
                thread::spawn(move || calculate(child_load_clone, Some(tx_clone)));
            }
            let load = (number_of_loops as f32 / number_of_threads as f32).ceil() as i32;
            calculate(load, Some(tx));
            let mut probability = Vec::new();
            for data in rx {
                match data {
                    Some(mut vec) => {
                        probability.append(&mut vec);
                    }
                    None => (),
                }
            }
            probability
        }
    }
}

pub fn simulation_single_thread(number_of_loops: i32) -> Vec<i32> {
    if number_of_loops < 0 {
        panic!(
            "Set number of loops greater than -1. You set it to {}.",
            number_of_loops
        )
    }
    // Avoid divide by zero errors with this check
    match number_of_loops {
        0 => vec![0],
        _ => calculate(number_of_loops, None).unwrap(),
    }
}

pub fn statistics(data: Vec<i32>) -> (f64, i32, i32, i32) {
    let mut floating_data = Vec::new();
    for datum in data.clone() {
        floating_data.push(datum as f64)
    }
    let mean: f64 = statistical::mean(floating_data.as_slice());
    let median = statistical::median(data.as_slice());
    let max = data.iter().max().unwrap();
    let min = data.iter().min().unwrap();
    (mean, median, *max, *min)
}