Last active
May 6, 2019 02:23
-
-
Save RedL0tus/017d56a4972056644eeae9717eadbb47 to your computer and use it in GitHub Desktop.
Balls!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env run-cargo-script | |
//! A verification of the question with boxes and balls. | |
//! | |
//! ```cargo | |
//! [dependencies] | |
//! rand = "0.6" | |
//! num_cpus = "1.10" | |
//! ``` | |
extern crate rand; | |
extern crate num_cpus; | |
use std::env; | |
use std::thread; | |
use std::panic::catch_unwind; | |
use rand::Rng; | |
use rand::seq::SliceRandom; | |
const usage: &str = r#" | |
Usage: ./chance.rs [METHOD] [TIME] | |
Available methods: "one", "another" | |
"#; | |
const boxes_one: &[&[bool]] = &[&[true, true], &[true, false]]; // Let's assume that we alreay pick a red ball. | |
const boxes_another: &[&[bool]] = &[&[true, true], &[false, false], &[true, false]]; | |
/// Result of this function will be approximately 50% (1/2). | |
fn one(times: usize) -> (usize, usize) { | |
let mut success: usize = 0; | |
let mut total: usize = 0; | |
let mut rng = rand::thread_rng(); | |
for _ in 0..times { | |
let choosed_box = boxes_one.choose(&mut rng).unwrap(); | |
let index: usize = rng.gen_range(0, 2); | |
if choosed_box == &[true, true] { | |
success += 1; | |
} | |
} | |
(success, times) | |
} | |
/// Result of this function will be approximately 67% (2/3). | |
fn another(times: usize) -> (usize, usize) { | |
let mut success: usize = 0; | |
let mut total: usize = 0; | |
let mut rng = rand::thread_rng(); | |
for _ in 0..times { | |
let choosed_box = boxes_another.choose(&mut rng).unwrap(); | |
let index: usize = rng.gen_range(0, 2); | |
if choosed_box[index] == false { | |
continue | |
} | |
total += 1; | |
if choosed_box[1 - index] == true { | |
success += 1; | |
} | |
} | |
(success, total) | |
} | |
fn wrapper(times: usize, method: impl Fn(usize) -> (usize, usize) + Sync + Send + Copy + 'static) -> (usize, usize) { | |
if times < 10000 { | |
return method(times); | |
} | |
let num_threads: usize = num_cpus::get() + 1; | |
let times_per_thread: usize = times / num_threads; | |
let remainder = times % num_threads; | |
let mut handles: Vec<thread::JoinHandle<(usize, usize)>> = vec!(); | |
for index in 0..num_threads { | |
handles.push(thread::spawn(move || { | |
method(times_per_thread) | |
})); | |
} | |
let (mut total_success, mut total_total) = method(remainder); | |
for handle in handles { | |
let (success, total) = handle.join().unwrap(); | |
total_success += success; | |
total_total += total; | |
} | |
(total_success, total_total) | |
} | |
fn main() -> Result<(), ()>{ | |
let args: Vec<String> = env::args().collect(); | |
let result = catch_unwind(|| { | |
let times = args[2].parse::<usize>().unwrap(); | |
println!("Going to run {} times", times); | |
let results = match args[1].as_str() { | |
"one" => { | |
Some(wrapper(times, one)) | |
}, | |
"another" => { | |
Some(wrapper(times, another)) | |
}, | |
_ => None, | |
}; | |
if results.is_none() { | |
println!("Available methods: \"one\", \"another\"."); | |
return Err(()); | |
} | |
let (success, total) = results.unwrap(); | |
let percentage: f32 = success as f32 / total as f32 * 100 as f32; | |
println!("Success: {}, Total: {}, Percentage: {}", success, total, percentage); | |
return Ok(()); | |
}); | |
if let Err(err) = result { | |
println!("Error: {:#?}\n{}", err, usage); | |
return Err(()); | |
} else { | |
return Ok(()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment