What is best way to create random numbers for dice roller?

What is best way to create random number for dice roller? I’m planning to create LiveView app to help me and my friends remotely play pen & paper RPG using Savage Worlds system.

Define ‘best’… what are the requirements?

Requirements are that user clicks dice of choice on screen then I need to generate random from it based on a chosen dice.

Never done this before so should I created random seed based on time so it will be randomized based on when used clicked? I also don’t know much about different random algorithms so what would be best for D4, D6, D8, D10 and D12 dices?

I did find this

Erlang -- rand
For all these generators except exro928ss and exsss the lowest bit(s) has got a slightly less random behaviour than all other bits. 1 bit for exrop (and exsp), and 3 bits for exs1024s. See for example the explanation in the Xoroshiro128+ generator source code:

So based on that if I will use division remainder to create random for dice I should be using exro928ss or exsss (this seems to be default).

To get stronger and less predictable randomness the recommended API is :crypto.strong_rand_bytes.

5 Likes

Just beware, that changing output of that function to be uniform dice roll isn’t obvious.

@wanton7

def roll(sides, number) do
  Enum.take_random(1..sides, number)
end
1 Like

This produces unexpected results… For instance, rolling 20d6: Enum.take_random(1..6, 20) will take only up to the max available numbers on the list, sample output: [5, 1, 2, 6, 4, 3].

I think that perhaps the :rand module is the easiest option for simple use cases. It’s also what the rollex lib uses internally:

def roll(number, sides) do
  for _ <- 1..number, do: :rand.uniform(sides)
end

PS.: Now I’m also curious about an implementation that uses what @dimitarvp suggested and I’m kind of intrigued by @hauleth’s comment.

@thiagomajesk yeah you’re right, I should have read the docs more carefully.

a replacement that should actually work is something like

def roll(number, sides) do
  Stream.repeatedly(fn -> :rand.uniform(sides) end) |> Enum.take(number)
end
1 Like