Last active
December 24, 2019 09:56
-
-
Save FSMaxB/6201772619a791a7162a4af4dee7feb0 to your computer and use it in GitHub Desktop.
DND statistics
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
[package] | |
name = "DNDCharacterRolls" | |
version = "0.1.0" | |
authors = ["Max Bruckner <max@maxbruckner.de>"] | |
edition = "2018" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
rand = "0.7.2" |
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
use rand::prelude::StdRng; | |
use rand::{SeedableRng, Rng}; | |
use std::fmt::{Display, Formatter, Error}; | |
struct Roll([u16; 3]); | |
impl Roll { | |
fn random(random_number_generator: &mut impl Rng) -> Roll { | |
let mut dice = [0; 4]; | |
for index in 0..4 { | |
dice[index] = random_number_generator.gen_range(1, 7) | |
} | |
dice.sort(); | |
let mut roll = [0u16; 3]; | |
roll.copy_from_slice(&dice[1..4]); | |
Roll(roll) | |
} | |
fn sum(&self) -> u16 { | |
self.0.iter().sum() | |
} | |
} | |
struct Character { | |
stats: [u16; 6], | |
} | |
impl Character { | |
fn random(random_number_generator: &mut impl Rng) -> Character { | |
let mut stats = [0; 6]; | |
for index in 0..6 { | |
stats[index] = Roll::random(random_number_generator).sum(); | |
} | |
Character { | |
stats, | |
} | |
} | |
fn sum(&self) -> u16 { | |
self.stats.iter().sum() | |
} | |
} | |
struct RandomCharacterIterator<RandomNumberGenerator> | |
where RandomNumberGenerator: Rng, | |
{ | |
random_number_generator: RandomNumberGenerator | |
} | |
impl<RandomNumberGenerator> RandomCharacterIterator<RandomNumberGenerator> | |
where RandomNumberGenerator: Rng, | |
{ | |
fn new(random_number_generator: RandomNumberGenerator) -> Self { | |
Self { | |
random_number_generator | |
} | |
} | |
} | |
impl<RandomNumberGenerator> Iterator for RandomCharacterIterator<RandomNumberGenerator> | |
where RandomNumberGenerator: Rng, | |
{ | |
type Item = Character; | |
fn next(&mut self) -> Option<Self::Item> { | |
Some(Character::random(&mut self.random_number_generator)) | |
} | |
} | |
struct Statistics { | |
total: u64, | |
minimum: u16, | |
maximum: u16, | |
amount: usize, | |
under60: usize, | |
over80: usize, | |
over90: usize, | |
over100: usize, | |
} | |
impl Statistics { | |
fn add_character(&mut self, character: Character) { | |
let sum = character.sum(); | |
self.minimum = self.minimum.min(sum); | |
self.maximum = self.maximum.max(sum); | |
self.under60 += if sum < 60 { 1 } else { 0 }; | |
self.over80 += if sum > 80 { 1 } else { 0 }; | |
self.over90 += if sum > 90 { 1 } else { 0 }; | |
self.over100 += if sum > 100 { 1 } else { 0 }; | |
self.amount += 1; | |
self.total += sum as u64; | |
} | |
fn average(&self) -> f64 { | |
(self.total as f64) / (self.amount as f64) | |
} | |
} | |
impl Default for Statistics { | |
fn default() -> Self { | |
Statistics { | |
total: 0, | |
minimum: std::u16::MAX, | |
maximum: std::u16::MIN, | |
amount: 0, | |
under60: 0, | |
over80: 0, | |
over90: 0, | |
over100: 0, | |
} | |
} | |
} | |
impl Display for Statistics { | |
fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), Error> { | |
write!(formatter, | |
r#"Accumulated statistics: | |
total: {} | |
minimum: {} | |
maximum: {} | |
amount: {} | |
average: {} | |
under60: {} | |
over80: {} | |
over90: {} | |
over100: {} | |
"#, | |
self.total, | |
self.minimum, | |
self.maximum, | |
self.amount, | |
self.average(), | |
self.under60, | |
self.over80, | |
self.over90, | |
self.over100, | |
) | |
} | |
} | |
/// Based on https://gist.github.com/Aristamo/693778bc6d614e3d343244650d584f3e | |
fn main() { | |
const ITERATIONS: usize = 100_000_000; | |
let seed = [0; 32]; | |
let random_number_generator = StdRng::from_seed(seed); | |
let statistics = RandomCharacterIterator::new(random_number_generator) | |
.take(ITERATIONS) | |
.fold(Statistics::default(), |mut statistics, character| { | |
statistics.add_character(character); | |
statistics | |
}); | |
let seed = [0; 32]; | |
let average_int = statistics.average() as u16; | |
let random_number_generator = StdRng::from_seed(seed); | |
let average_characters = RandomCharacterIterator::new(random_number_generator) | |
.take(ITERATIONS) | |
.filter(|character| character.sum() == average_int) | |
.count(); | |
println!("{}", statistics); | |
println!("Average characters: {}", average_characters); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment