Compare commits
6 commits
918d9faeca
...
77c8b82728
Author | SHA1 | Date | |
---|---|---|---|
77c8b82728 | |||
44a021f0b0 | |||
d73ce30692 | |||
ef279ae4f4 | |||
1709084904 | |||
c102a5e40a |
8 changed files with 5999 additions and 1 deletions
4707
1_billion.log
Normal file
4707
1_billion.log
Normal file
File diff suppressed because it is too large
Load diff
1067
1_billion_with_multithread_rand.log
Normal file
1067
1_billion_with_multithread_rand.log
Normal file
File diff suppressed because it is too large
Load diff
11
1_milion.log
Normal file
11
1_milion.log
Normal file
|
@ -0,0 +1,11 @@
|
|||
HIGH_SCORE: 0
|
||||
ROLL_COUNT: 0
|
||||
HIGH_SCORE: 92
|
||||
ROLL_COUNT: 423264
|
||||
HIGH_SCORE: 92
|
||||
ROLL_COUNT: 856018
|
||||
HIGH_SCORE: 92
|
||||
ROLL_COUNT: 1000000
|
||||
HIGH_SCORE: 92
|
||||
ROLL_COUNT: 1000000
|
||||
realtime 0:04.40
|
7
1_milion_with_multithread_rand.log
Normal file
7
1_milion_with_multithread_rand.log
Normal file
|
@ -0,0 +1,7 @@
|
|||
HIGH_SCORE: 74
|
||||
ROLL_COUNT: 337
|
||||
HIGH_SCORE: 91
|
||||
ROLL_COUNT: 1000000
|
||||
HIGH_SCORE: 91
|
||||
ROLL_COUNT: 1000000
|
||||
realtime 0:01.00
|
23
Cargo.toml
Normal file
23
Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "graveler-softlockpicking-years-wasted-calculator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
|
||||
[profile.release.package."*"]
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
#panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
rand = { version = "0.8.5", optional = true }
|
||||
num_cpus = { version = "1.16.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["rust_random", "auto_thread_count"]
|
||||
rust_random = ["dep:rand"]
|
||||
auto_thread_count = ["dep:num_cpus"]
|
47
README.md
47
README.md
|
@ -1,3 +1,48 @@
|
|||
# graveler-softlockpicking-years-wasted-calculator
|
||||
|
||||
This repo is a short and sweet response to Austins most recent video 'The Science of Soft Lock Picking Pokemon' available here https://www.youtube.com/watch?v=M8C8dHQE2Ro
|
||||
This repo is a short and sweet response to Austins most recent video 'The Science of Soft Lock Picking Pokemon' available here https://www.youtube.com/watch?v=M8C8dHQE2Ro
|
||||
|
||||
## Programs
|
||||
[`time`](https://www.gnu.org/software/time/) to record execution time
|
||||
|
||||
[`rustup`](https://rustup.rs/) to install cargo, and all other tools used by the rust ecosystem
|
||||
|
||||
[`cargo`](https://github.com/rust-lang/cargo) to compile the program
|
||||
|
||||
# Building
|
||||
|
||||
`cargo build --release`
|
||||
|
||||
the built program will be stored under `target/release` or `target/debug` if you forgot to use the `--release` flag (not recommended as there will be a significant performance hit due to additional debugging and status information, as well as additional runtime verification of the code)
|
||||
|
||||
you can also replace `build` with `run` to run the program after the compilation process is done, however this may interfere with any external timing software such as gnu time (see the Programs section) since it will include the compilation time and however long it takes for cargo to start the built program
|
||||
|
||||
# Features
|
||||
|
||||
You can disable default features to switch to less performant code like so
|
||||
|
||||
`cargo build --release --no-default-features`
|
||||
|
||||
however this will require you provide a seed to seed the manual random implementation
|
||||
|
||||
`cargo build --release --no-default-features -- 789124`
|
||||
|
||||
to enable specific features just use the -F flag like so
|
||||
|
||||
`cargo build --release --no-default-features -F auto_thread_count -- 789124`
|
||||
|
||||
or
|
||||
|
||||
`cargo build --release --no-default-features -F auto_thread_count,rust_random`
|
||||
|
||||
# Timings
|
||||
|
||||
### 1 billion
|
||||
comparable to the python implementation: 39:12.67
|
||||
|
||||
multithreading and a better random library: 8:51.31
|
||||
|
||||
### 1 million
|
||||
comparable to the python implementation: 0:04.40
|
||||
|
||||
multithreading and a better random library: 0:01.00
|
||||
|
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
|||
hard_tabs=true
|
137
src/main.rs
Normal file
137
src/main.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
use std::{
|
||||
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
const ITER_COUNT: usize = 1_000_000_000;
|
||||
//const ITER_COUNT: usize = 1_000_000;
|
||||
|
||||
static THREAD_STOP: AtomicBool = AtomicBool::new(false);
|
||||
static ROLL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
static HIGH_SCORE: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(feature = "rust_random"))]
|
||||
{
|
||||
// forgive this mess, i just cant be arsed to make a proper command line interface
|
||||
// in case youre wondering a usize is a non floating point number that can fit inside your cpus max bit size
|
||||
let seed = std::env::args()
|
||||
.collect::<Vec<String>>()
|
||||
.get(1) // we use 1 here because 90% of platforms use the path/program name as the first argument
|
||||
.expect("You must supply a usize argument, for example 75293")
|
||||
.parse::<usize>()
|
||||
.expect("First argument is not a valid usize, for example 926304");
|
||||
SEED.store(seed, Ordering::SeqCst);
|
||||
|
||||
// give it some time to become a tad more "random"
|
||||
for _ in 0..seed {
|
||||
seeded_random();
|
||||
}
|
||||
}
|
||||
|
||||
// get the total thread count we wish to use
|
||||
#[cfg(feature = "auto_thread_count")]
|
||||
let thread_count: usize = num_cpus::get();
|
||||
#[cfg(not(feature = "auto_thread_count"))]
|
||||
let thread_count: usize = 1; // Change me to any number you want to use as the thread count, please note you must not be using the 'auto_thread_count' feature, see README.md for details
|
||||
|
||||
// divide the total iter count among multiple threads
|
||||
let thread_dispatch = {
|
||||
let mut vec = vec![0; thread_count];
|
||||
|
||||
for i in 0..(thread_count) {
|
||||
vec[i] = ITER_COUNT / thread_count;
|
||||
}
|
||||
|
||||
// add the remainder of the division to the last thread as not ever number is cleanly divisible by an unknown thread count
|
||||
vec[thread_count - 1] = vec[thread_count - 1] + (ITER_COUNT % thread_count);
|
||||
vec
|
||||
};
|
||||
|
||||
// for verification purposes
|
||||
//let mut adder = 0;
|
||||
//for i in &thread_dispatch {
|
||||
// adder += i;
|
||||
//}
|
||||
//println!("{adder}");
|
||||
|
||||
let mut thread_join_handles = vec![];
|
||||
|
||||
for i in thread_dispatch {
|
||||
thread_join_handles.push(thread::spawn(move || number_cruncher(i)));
|
||||
}
|
||||
|
||||
loop {
|
||||
println!("HIGH_SCORE: {}", HIGH_SCORE.load(Ordering::SeqCst));
|
||||
println!("ROLL_COUNT: {}", ROLL_COUNT.load(Ordering::SeqCst));
|
||||
|
||||
// if all threads are done break the loop
|
||||
{
|
||||
let mut any_thread_running = false;
|
||||
for i in &thread_join_handles {
|
||||
if !i.is_finished() {
|
||||
any_thread_running = true;
|
||||
}
|
||||
}
|
||||
if !any_thread_running {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
|
||||
println!("HIGH_SCORE: {}", HIGH_SCORE.load(Ordering::SeqCst));
|
||||
println!("ROLL_COUNT: {}", ROLL_COUNT.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
fn number_cruncher(iter_count: usize) {
|
||||
{
|
||||
for _ in 0..iter_count {
|
||||
if THREAD_STOP.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
ROLL_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
let mut correct_count = 0;
|
||||
|
||||
// turns
|
||||
for _ in 0..231 {
|
||||
#[cfg(feature = "rust_random")]
|
||||
let rand = rand::Rng::gen_range(&mut rand::thread_rng(), 0..4);
|
||||
#[cfg(not(feature = "rust_random"))]
|
||||
let rand = seeded_random() % 4;
|
||||
match rand {
|
||||
0 => {
|
||||
correct_count += 1;
|
||||
}
|
||||
_ => { /* do nothing */ }
|
||||
}
|
||||
|
||||
if correct_count > HIGH_SCORE.load(Ordering::SeqCst) {
|
||||
HIGH_SCORE.swap(correct_count, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if correct_count > 177 {
|
||||
THREAD_STOP.store(true, Ordering::SeqCst);
|
||||
println!("HIT: {correct_count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "rust_random"))]
|
||||
static SEED: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[cfg(not(feature = "rust_random"))]
|
||||
pub fn seeded_random() -> usize {
|
||||
SEED.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |mut random| {
|
||||
random ^= random << 13;
|
||||
random ^= random >> 17;
|
||||
random ^= random << 5;
|
||||
Some(random)
|
||||
})
|
||||
.unwrap()
|
||||
}
|
Loading…
Add table
Reference in a new issue