Skip to content

Instantly share code, notes, and snippets.

@FSMaxB
Last active December 24, 2019 09:56
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 FSMaxB/6201772619a791a7162a4af4dee7feb0 to your computer and use it in GitHub Desktop.
Save FSMaxB/6201772619a791a7162a4af4dee7feb0 to your computer and use it in GitHub Desktop.
DND statistics
[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"
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