5

How you I generate a random dice roll in Rust?

I know I can use rand::random, but that requires I want to generate a value of an integer type. Using rand::random<u8>() % 6 introduces a bias.

1
  • 4
    rand::thread_rng().gen_range(1,7) might work. See this page on Programming a Guessing Game. Make sure to put lines extern crate rand; and use rand::Rng; in your program. Commented Sep 22, 2018 at 8:17

2 Answers 2

9

Use Rng::gen_range for a one-off value:

use rand::{self, Rng}; // 0.8.0

fn main() {
    let mut rng = rand::thread_rng();

    let die = rng.gen_range(1..=6);

    println!("The die was: {}", die);
}

Under the hood, this creates a Uniform struct. Create this struct yourself if you will be getting multiple random numbers:

use rand::{
    self,
    distributions::{Distribution, Uniform},
}; // 0.8.0

fn main() {
    let mut rng = rand::thread_rng();
    let die_range = Uniform::new_inclusive(1, 6);

    let die = die_range.sample(&mut rng);

    println!("{}", die);
}

Uniform does some precomputation to figure out how to map the complete range of random values to your desired range without introducing bias. It translates and resizes your original range to most closely match the range of the random number generator, discards any random numbers that fall outside this new range, then resizes and translates back to the original range.

See also:

Sign up to request clarification or add additional context in comments.

3 Comments

unfortunately this does not even compile
no method named gen_rng found for type rand::prelude::ThreadRng in the current scope
@nikoss it worked fine, even before I updated. Did you use the same version of the crate specified in the answer? Did you copy the entire example? Did you import the appropriate trait? Did you fully read the error message? For example, you get that error if you don't import Rng and it tells you how to fix it: the following trait is implemented but not in scope, perhaps add a use for it: use rand::Rng;
3

You're correct that a bias is introduced; whenever you want to map from set A to set B where the cardinality of set B is not a factor or multiple of set A, you will have bias.

In your case, 42*6=252. So you can just throw away any u8 values of 252 or greater (and call random again).

Your output can then be safely mapped with the modulus operator. Finally add 1 to achieve the standard [1,6] dice output.

It might seem unclean to call random again but there is no way of mapping a set of 256 values to a set of 6 without introducing bias.

Edit: looks like the rand crate has something which takes bias into account: https://docs.rs/rand/latest/rand/distributions/uniform/struct.Uniform.html

1 Comment

Thanks. This is a correct answer, but I hoped that rust would have something to do this for me :) (looks like Uniform might do it)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.