The concept of random is pretty interesting when you think about it from a computer’s point of view, because without some external input, random is impossible.

Computers (hardware and software) are deterministic. Meaning you give some input and get an output, and if you repeat the input, you’ll get the same output. Random numbers are, from a philosophical stand point, indeterministic.

[I’ve published 38 videos for new developers, designers, UX, UI, product owners and anyone who needs to conquer the command line today.](https://training.leftlogic.com/buy/terminal/cli2?coupon=BLOG\&utm_source=blog\&utm_medium=banner\&utm_campaign=remysharp-discount)

So random functions in software, like Math.random() starts with a seed value and roughly speaking, the result of the random function call is used as the next seed, and the next and so on. This means that computers can generate a random sequence of values but to start it needs a seed. A good candidate for a seed is the current time in millisecond for instance.

In "most" cases, these pseudo random values are fine, though if you want to do some in depth reading on random number generation in V8 there’s a great article on Medium entitled [TIFU by using Math.random()](https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d) ([archived copy](https://web.archive.org/web/20190418034608/https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d)).

Random for games[](#random-for-games)

Lately I’ve been playing with my own [Tetris clone](https://tetris.isthe.link/) and added an (undocumented) two player option. When the game plays, the [tetrominos](https://en.m.wikipedia.org/wiki/Tetromino) are selected "at random". However in a two player game both players should get the same "random" sequence of blocks.

Using Math.random() won’t fly because I can’t control the seed value. In this instance, I have to write my own (or copy tried and tested) random function. This way I am to set the seed value when both players join.

Additionally to this, I’ve created a game that creates a random board layout and if the player decides to publish their score, the software can take their starting seed value and their sequence of moves to validate their score is legitimate.

Let’s write our own random function[](#lets-write-our-own-random-function)

RFC 1149.5 specifies 4 as the standard IEEE-vetted random number [via xkcd](https://xkcd.com/221/)

A bit of searching on the web will turn up a number of different algorithms for a random number. My problem is that I’m not entirely sure I a) understand the given code and b) trust the code actually does what it says it does.

For example, here’s three functions I found:

let seed = Date.now();

// based on a worst case random (not random really!)
function randomA() {
  seed = (5 * seed + 3) % 16;
  return seed / 16;
}

// a version I'd used for a *very* old PalmPilot game
function randomB() {
  seed = (seed * 7919 + 1) & 0xffff;
  // upper range is 0xffff (65535) so bring it down to 0-1
  return seed / 0xffff;
}

// the 1984 original NES tetris random algo
let ctr = 0;
let randCSeed = Date.now() & 0xFF; // clamp to 8 bit
function randomC(n = 7) {
  ctr++;
  let value = ((((randCSeed >> 9) & 1) ^ ((randCSeed >> 1) & 1)) << 15) | (randCSeed >> 1);

  randCSeed = value;
  value >>= 8; // high byte
  value += ctr;
  value %= n;

  return value / n;
}

I’d generally gravitate towards the more complicated looking function, but that’s based entirely on looks. Reading these functions I can’t quite imagine what they’re doing and running them in a browser won’t really confirm whether their numbers are random (enough) even if I ran the functions over and over and over.

Quite honestly these functions look like they’re mooshing together numbers in the way you might moosh together [Opal Fruits](https://en.m.wikipedia.org/wiki/Starburst_\(confectionery\)) and end up with some colour that doesn’t resemble anything.

What’s useful here is a visualisation of noise distribution the functions make. You might have seen these before:

![random noise](/images/noise.png)

What I’m looking for in these images is any visual patterns, and patterns are bad. This is an example of a "bad" random number generator - since there’s a pattern, the sequence can be predicted:

![bad random noise](/images/bad-noise.png)

Originally I found some python code that generates these kinds of images, but I figured with HTML5-like tech, it should be viable to run in the browser and even generate the random function code on the fly to get a good impression if my algorithm works for my purposes.

So sketched out some code and came up with this mini tool: https://random.isthe.link

This way I can instantly see the effects of the three functions:

I’m sure there’s better functions out there, but the randomC is "good enough" for my particular needs. Though interestingly it works well for the 7 values I need, but when the range of values goes up, to 7777 or even [77777](https://random.isthe.link/?code=let+seed+%3D+Date.now%28%29%3B%0A%0A%0Alet+ctr+%3D+0%3B%0Afunction+randomC%28n+%3D+77777%29+%7B%0Actr%2B%2B%3B%0Alet+value+%3D+%28%28%28%28seed+%3E%3E+9%29+%26+1%29+%5E+%28%28seed+%3E%3E+1%29+%26+1%29%29+%3C%3C+15%29+%7C+%28seed+%3E%3E+1%29%3B%0A%0Aseed+%3D+value%3B%0Avalue+%3E%3E%3D+8%3B+%2F%2F+high+byte%0Avalue+%2B%3D+ctr%3B%0Avalue+%25%3D+n%3B%0A%0A+return+value%2F+n%3B%0A%7D%0A%0Aexport+default+randomC%3B) you start to see gradients (which I presume the upper bounds of the bit shifting is being hit…but really, I’m not sure!).

I hope that’s useful or a useful tool if you’re thinking of adding your own random function. Oh, and if anyone wants to take a shot at explaining the code above, feel free to in the comments below 😉

Published 6-Aug 2019 under #code. [Edit this post](https://github.com/remy/remysharp.com/blob/main/public/blog/predictably-random.md)

👍 34 likes

[![Haroen](/images/no-user.svg "Haroen")](![Arabi Alhumsi(/images/no-user.svg "Arabi Alhumsi")](![Ville(/images/no-user.svg "Ville")](![Chris Sedlmayr(/images/no-user.svg "Chris Sedlmayr")](![João Mamede(/images/no-user.svg "João Mamede")](![Joseph(/images/no-user.svg "Joseph")](![Julian Nicholls(/images/no-user.svg "Julian Nicholls")](![@nickautomatic@mastodon.social(/images/no-user.svg "@nickautomatic@mastodon.social")](![Tommy Noe(/images/no-user.svg "Tommy Noe")](![Alex Fuentes(/images/no-user.svg "Alex Fuentes")](![Thierri.Oliveira(/images/no-user.svg "Thierri.Oliveira")](![Johnny Mnemonic(/images/no-user.svg "Johnny Mnemonic")](![Leonid(/images/no-user.svg "Leonid")](![절대Solitude(/images/no-user.svg "절대Solitude")](![Selva Ganesh(/images/no-user.svg "Selva Ganesh")](![James Starkie 💚(/images/no-user.svg "James Starkie 💚")](![nunete(/images/no-user.svg "nunete")](![Simon Gordon(/images/no-user.svg "Simon Gordon")](![Laura Beaufort(/images/no-user.svg "Laura Beaufort")](![Amine(/images/no-user.svg "Amine")](![MatthewTyleeAtkinson(/images/no-user.svg "MatthewTyleeAtkinson")](![Kriszti Z.(/images/no-user.svg "Kriszti Z.")](![Fynn Becker(/images/no-user.svg "Fynn Becker")](![José Pedro Dias(/images/no-user.svg "José Pedro Dias")](![Perry Brandiezs(/images/no-user.svg "Perry Brandiezs")](![teen coder(/images/no-user.svg "teen coder")](![Ant Stanley 🤦🏻‍♂️(/images/no-user.svg "Ant Stanley 🤦🏻‍♂️")](![litenjacob(/images/no-user.svg "litenjacob")](![Shaun O’Neill(/images/no-user.svg "Shaun O’Neill")](![Ricardo Machado(/images/no-user.svg "Ricardo Machado")](![Sibelius Seraphini(/images/no-user.svg "Sibelius Seraphini")](![Zach Attack(/images/no-user.svg "Zach Attack")](![Andrew Hammond 🤘🏻(/images/no-user.svg "Andrew Hammond 🤘🏻")](![Martin Bommeli(/images/no-user.svg "Martin Bommeli")](https://twitter.com/MBommeli)

Comments

Lock Thread

Login

Add Comment[M ↓   Markdown]()

[Upvotes]()[Newest]()[Oldest]()

![](/images/no-user.svg)[Chad von Nau](http://vonnau.com)

0 points

4 years ago

Thanks, Remy! Your visualization tool is useful.

I did a deep dive on seedable PRNGs a while back and discovered that besides patterns in the results, there are a few other things to look out for.

  1. The distribution of numbers can bunch up around certain values.

  2. The first result can always be a [similar value](https://gist.github.com/blixt/f17b47c62508be59987b#gistcomment-2787679), regardless of seed.

  3. Similar seeds (e.g. a seed of 1 and 2) can cause correlations, resulting in the output having similar properties (such as randomly generated levels being similar).

  4. Different environments (Node, Chrome, Safari, Firefox, etc) can produce inconsistent results for the same seed. PRNGs based on Math.sin() are susceptible in particular.

Visualization can help detect these flaws. For #1, graph the distribution like this http://jsfiddle.net/bhrLT/17/. For #2 and #3, initialize the generator several times with sequential seeds and display the results together.

This SO answer by bryc contains several good generators, and guidance on how to avoid the problems above: https://stackoverflow.com/a/47593316/490592

![](/images/no-user.svg)

Dannii Willis

0 points

4 years ago

One of the best and simplest PRNG algorithms is Xorshift. Not that it matters for your current project, but just something to remember for next time.

[Commento](https://commento.io)