switch to fastrand
This commit is contained in:
parent
73f70e4fa9
commit
0c7bbbe200
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
|
*.etl*
|
||||||
|
63
Cargo.lock
generated
63
Cargo.lock
generated
@ -13,7 +13,7 @@ name = "cup"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enum-map",
|
"enum-map",
|
||||||
"rand",
|
"fastrand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -37,27 +37,22 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "fastrand"
|
||||||
version = "0.2.8"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"instant",
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "instant"
|
||||||
version = "0.2.139"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
[[package]]
|
"cfg-if",
|
||||||
name = "ppv-lite86"
|
]
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
@ -77,36 +72,6 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.107"
|
version = "1.0.107"
|
||||||
@ -123,9 +88,3 @@ name = "unicode-ident"
|
|||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
11
Cargo.toml
11
Cargo.toml
@ -6,5 +6,12 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
"enum-map" = "2.4.2"
|
enum-map = "2.4.2"
|
||||||
"rand" = "0.8.5"
|
fastrand = "1.8.0"
|
||||||
|
|
||||||
|
# [profile.release]
|
||||||
|
# lto = true
|
||||||
|
|
||||||
|
[profile.perf]
|
||||||
|
inherits = "release"
|
||||||
|
debug = true
|
||||||
|
41
src/game.rs
41
src/game.rs
@ -1,9 +1,5 @@
|
|||||||
use enum_map::{Enum, EnumMap};
|
use enum_map::{Enum, EnumMap};
|
||||||
use rand::{
|
use fastrand::Rng;
|
||||||
Rng,
|
|
||||||
seq::SliceRandom,
|
|
||||||
distributions::{Distribution, Uniform},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::stack::Stack;
|
use crate::stack::Stack;
|
||||||
|
|
||||||
@ -84,11 +80,11 @@ impl Game {
|
|||||||
// new game with random starting positions
|
// new game with random starting positions
|
||||||
pub fn new_random() -> Self {
|
pub fn new_random() -> Self {
|
||||||
let mut game = Self::default();
|
let mut game = Self::default();
|
||||||
let mut rng = rand::thread_rng();
|
let rng = Rng::new();
|
||||||
let mut dice = *&COLORS;
|
let mut dice = *&COLORS;
|
||||||
dice.shuffle(&mut rng);
|
rng.shuffle(&mut dice);
|
||||||
for color in dice {
|
for color in dice {
|
||||||
let roll = rng.gen_range(1..=3);
|
let roll = rng.usize(1..=3);
|
||||||
game.squares[roll - 1].assume_stack_mut().push(color);
|
game.squares[roll - 1].assume_stack_mut().push(color);
|
||||||
game.camels[color] = roll - 1;
|
game.camels[color] = roll - 1;
|
||||||
}
|
}
|
||||||
@ -187,8 +183,7 @@ impl Game {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_leg_random(&mut self) -> Option<Color> {
|
fn finish_leg_random(&mut self, rng: &Rng) -> Option<Color> {
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let mut leg_dice: Stack<Color, 5> = Stack::new();
|
let mut leg_dice: Stack<Color, 5> = Stack::new();
|
||||||
for (color, rolled) in self.dice {
|
for (color, rolled) in self.dice {
|
||||||
if !rolled {
|
if !rolled {
|
||||||
@ -196,9 +191,9 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(&mut leg_dice[..]).shuffle(&mut rng);
|
rng.shuffle(&mut leg_dice[..]);
|
||||||
for color in leg_dice.iter() {
|
for color in leg_dice.iter() {
|
||||||
let roll = rng.gen_range(1..=3);
|
let roll = rng.usize(1..=3);
|
||||||
if let Some(winner) = self.advance(*color, roll) {
|
if let Some(winner) = self.advance(*color, roll) {
|
||||||
return Some(winner);
|
return Some(winner);
|
||||||
}
|
}
|
||||||
@ -206,22 +201,19 @@ impl Game {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_game_random(&mut self) -> Color {
|
fn finish_game_random(&mut self, rng: &Rng) -> Color {
|
||||||
if let Some(winner) = self.finish_leg_random() {
|
if let Some(winner) = self.finish_leg_random(rng) {
|
||||||
return winner;
|
return winner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut dice = COLORS; // makes a copy of the constant
|
||||||
// we are now guaranteed to be at the start of a new leg,
|
// we are now guaranteed to be at the start of a new leg,
|
||||||
// so we don't need to check the dice state
|
// so we don't need to check the dice state
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let roll_dist = Uniform::from(1..=3);
|
|
||||||
let mut dice = COLORS; // makes a copy of the constant
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// easiest if we shuffle at the start of the leg
|
// easiest if we shuffle at the start of the leg
|
||||||
dice.shuffle(&mut rng);
|
rng.shuffle(&mut dice);
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
let roll = roll_dist.sample(&mut rng);
|
let roll = rng.usize(1..=3);
|
||||||
if let Some(winner) = self.advance(dice[i], roll) {
|
if let Some(winner) = self.advance(dice[i], roll) {
|
||||||
return winner;
|
return winner;
|
||||||
}
|
}
|
||||||
@ -234,8 +226,9 @@ impl Game {
|
|||||||
let mut projection = *self;
|
let mut projection = *self;
|
||||||
|
|
||||||
let mut scores: EnumMap<Color, usize> = EnumMap::default();
|
let mut scores: EnumMap<Color, usize> = EnumMap::default();
|
||||||
|
let rng = Rng::new();
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let winner = projection.finish_game_random();
|
let winner = projection.finish_game_random(&rng);
|
||||||
scores[winner] += 1;
|
scores[winner] += 1;
|
||||||
projection.set_state(&orig_camels, &orig_dice);
|
projection.set_state(&orig_camels, &orig_dice);
|
||||||
}
|
}
|
||||||
@ -324,7 +317,8 @@ mod test {
|
|||||||
for _ in 0..100 {
|
for _ in 0..100 {
|
||||||
let mut projection = game; // copy?
|
let mut projection = game; // copy?
|
||||||
assert_eq!(projection.squares[1].assume_stack(), &Stack::from([Purple, Blue]));
|
assert_eq!(projection.squares[1].assume_stack(), &Stack::from([Purple, Blue]));
|
||||||
projection.finish_leg_random();
|
let rng = Rng::new();
|
||||||
|
projection.finish_leg_random(&rng);
|
||||||
// since we already rolled Green, it can't have moved
|
// since we already rolled Green, it can't have moved
|
||||||
assert_eq!(projection.camels[Green], 3);
|
assert_eq!(projection.camels[Green], 3);
|
||||||
// likewise purple
|
// likewise purple
|
||||||
@ -349,7 +343,8 @@ mod test {
|
|||||||
game.set_state(&camel_state, &Default::default());
|
game.set_state(&camel_state, &Default::default());
|
||||||
|
|
||||||
// since there are no tiles involved, and multiple camels are on 15, there must be a winner
|
// since there are no tiles involved, and multiple camels are on 15, there must be a winner
|
||||||
assert!(matches!(game.finish_leg_random(), Some(_)));
|
let rng = Rng::new();
|
||||||
|
assert!(matches!(game.finish_leg_random(&rng), Some(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
34
src/main.rs
34
src/main.rs
@ -3,24 +3,38 @@ use std::time::Instant;
|
|||||||
mod stack;
|
mod stack;
|
||||||
mod game;
|
mod game;
|
||||||
|
|
||||||
use game::Game;
|
use game::{Game, Color::*};
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let n_games = 10_000_000;
|
let n_games = 200_000;
|
||||||
|
|
||||||
let start = Instant::now();
|
|
||||||
let game = Game::new_random();
|
let game = Game::new_random();
|
||||||
let _scores = game.project_outcomes(n_games);
|
// let mut game = Game::new();
|
||||||
|
// let camel_state = [
|
||||||
|
// (Blue, 5),
|
||||||
|
// (Purple, 5),
|
||||||
|
// (Red, 7),
|
||||||
|
// (Yellow, 8),
|
||||||
|
// (Green, 10),
|
||||||
|
// ];
|
||||||
|
// game.set_state(&camel_state, &Default::default());
|
||||||
|
let start = Instant::now();
|
||||||
|
let scores = game.project_outcomes(n_games);
|
||||||
let end = Instant::now();
|
let end = Instant::now();
|
||||||
|
|
||||||
let elapsed = end.duration_since(start);
|
let elapsed = end.duration_since(start);
|
||||||
let secs = elapsed.as_secs();
|
let secs = (elapsed.as_secs_f64() * 100f64).round() / 100f64;
|
||||||
let hundredths = elapsed.subsec_millis() / 10; // technically not accurate but good enough for now
|
let rate = (n_games as f64) / elapsed.as_secs_f64();
|
||||||
|
|
||||||
let rate = (10_000_000 as f64) / elapsed.as_secs_f64();
|
|
||||||
|
|
||||||
println!("Test completed:");
|
println!("Test completed:");
|
||||||
println!("{n_games} in {secs}.{hundredths:02} seconds", );
|
println!("{n_games} in {secs} seconds", );
|
||||||
println!("Games per second: {rate}");
|
println!("Games per second: {rate}\n");
|
||||||
|
|
||||||
|
let total = scores.values().sum::<usize>() as f64;
|
||||||
|
for (color, score) in scores {
|
||||||
|
let fract = (score as f64) / total;
|
||||||
|
let pct = (fract * 10_000f64).round() / 100f64;
|
||||||
|
println!("{color:?}: {pct}%");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user