Skip to content

Instantly share code, notes, and snippets.

@RedL0tus
Last active May 6, 2019 02:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RedL0tus/017d56a4972056644eeae9717eadbb47 to your computer and use it in GitHub Desktop.
Save RedL0tus/017d56a4972056644eeae9717eadbb47 to your computer and use it in GitHub Desktop.
Balls!
#!/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