How To Develop A Seedable Dice Roll/Number Guess In JavaScript

Recently whilst working on some blockchain specific code, I needed to write a random number generator to simulate generating a range of numbers, except it needed to be predictable. The same input values produce the same output when provided.

In my case, I used values from immutable blockchain data such as the blockchain number, reference block number and transaction ID. I then allow the user to provide a client seed and generate a unique server seed on each roll as well.

For this, we will use the tried and tested and ever-versatile Seedrandom library by David Bau. It provides a wide variety of different algorithms for producing random numbers.

In this post, we won’t do anything outside of the norm. We will just use the default algorithm which for most purposes does what you would expect it to do.

For this example, we are going to assume the random number generator lives on the server in a Node.js environment. This would also work in a browser, but when generating numbers for a game or any serious application, you would never do it server side.

Firstly, make sure you install the seedrandom package by running: npm install seedrandom

const seedrandom = require("seedrandom");

const rng = (seed1, seed2) => {
  const random = seedrandom(`${seed1}${seed2}`).double();
  const randomRoll = Math.floor(random * 100) + 1;

  return randomRoll;
};

The seedrandom method accepts a seed string. This value produces a deterministic result, meaning if our rng function above is provided the same values for seed1 and seed2, the result is the same.

We then use Math.floor to take our random number and multiply it by 100 (the largest number we want to allow) and plussing it by one means the number starts at 1 instead of 0. This will produce a number between 1 and 100. You can change these values to suit.

For example, if you wanted to generate a number between 1 and 2 (for some kind of seedable coin flip) you would do something like this:

const randomRoll = Math.floor(random * 2) + 1;
const headsOrTails = randomRoll === 1 ? 'heads' : 'tails';

You can make your seed as long as you like. I highly suggest allowing the user to provide their own client seed as well as randomly generating a client seed which you reveal to the user after the fact.

With all of these values, users should be able to produce the same result independent of your site, this results in a provably fair algorithm for producing numbers.

A working code sample of what we did above can be found here on Codesandbox.

Leave a Reply

Your email address will not be published. Required fields are marked *