
Predictably Random - Fudgel
https://remysharp.com/2019/08/06/predictably-random
======
OskarS
Hubba bubba. This is maybe not the article to read if you want to learn how to
implement randomness correctly. There's... many things wrong with it.

Of course randomA is terrible, you're modding it with 16! It's never going to
have a period longer than 16 like that! Same with randomB, just with a
slightly larger number. Both of these are just bog-standard linear
congruential generators. LCGs are pretty bad for anything "serious", but for
picking Tetris pieces they're fine, and they're easy to implent (or at least I
thought they were, but then you see an article like this where one of them has
period 16...). I don't immediately recognie randomC(), but it also looks
terrible. Just shifting some bits around and adding a counter. At least it has
some internal state so it it's not stupidly periodic.

I haven't read up on what's the issue with V8's Math.random(), but I would
have to imagine it's superior to all these three. I'm also sure there's plenty
of excellent randomness libraries (and plenty of terrible ones) on NPM.

Also, this kind of visual inspection will weed out truly garbage PRNGs, but
it's not a good test in general. Testing for pseudo-randomness is hard, and
best left to people who know what they are doing.

Also also: for Tetris, you shouldn't just pick pieces at random, that's not
how Tetris works nowadays. Tetris works by putting all 7 pieces in a bag, and
then pulling them out at random. When the bag is empty, you fill it again with
the seven pieces and start over. More info here: [0]. If you're new to
programming, implementing the 7-bag system properly is a good little
challenge, you'll get to learn all about the Fisher-Yates shuffle [1].

[0]:
[https://tetris.fandom.com/wiki/Random_Generator](https://tetris.fandom.com/wiki/Random_Generator)

[1]:
[https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)

~~~
defertoreptar
> you shouldn't just pick pieces at random, that's not how Tetris works
> nowadays.

It's a purely abstract game with endless possibilities for how it can be made.
That's what makes it timeless. There's no reason you have to use bag
randomizer in your own personal projects. That is, unless you feel some
strange need to check off boxes to comply with what the current IP holders
happen to prescribe at a particular moment in time.

In fact, there's an argument for using a memoryless randomizer: it maximizes
variation, unpredictability, and increases challenge.

~~~
OskarS
You speak of Tetris like it's some abstract concept that has always existed
and is like some eternal truth. It's not: it's a game that was created by one
man, Alexey Pajitnov, who also just happen to be "the current IP holder" you
dismiss so easily (he's the co-owner of the Tetris Company).

So no, it's not an "abstract game with endless possibilities". Tetris is
Tetris, a concrete game made by a great game designer. It gets cloned and
copied constantly, so much so that people forget that it was actually authored
by a person. Comments like yours erase Pajitnov's authorship and ownership,
which he has rightly earned.

Nobody talks of any other kind of media this way, we shouldn't do it about
games either. When speaking of Harry Potter, no one thinks of JK Rowling as
just "the current IP holder" (she's the author!), and no one considers fan
fiction on the same level as the real thing.

The article states "when the game plays, the tetrominos are selected at
random". When it comes to standard Tetris, as defined by the Tetris Company,
this is incorrect. I was correcting the error. Obviously you can do it however
you want, but that is how Tetris does it.

As for what's more fun, obviously opinions can differ. But as someone who
plays a lot (A LOT) of Tetris, I personally vastly prefer the 7-bag system. It
really opens up the game strategically, and it allows you to play much faster.

~~~
defertoreptar
I agree that credit is due to the wonderfully creative game designer, Mr.
Pajitnov. I don't see this as contradictory to my point.

> So no, it's not an "abstract game with endless possibilities". Tetris is
> Tetris, a concrete game

While protecting their IP in a court of law, The Tetris Company successfully
argued that it does not exhibit scènes à faire because it is a purely abstract
game.

> Moreover, Xio does not dispute that Tetris is a purely fanciful game,
> meaning it has no grounding in the real world, unlike a video game
> simulating a karate match or a golf game. Therefore, the analyses in Data
> East and Incredible Technologies are largely inapplicable; the scènes à
> faire doctrine has little weight in instances such as this because there are
> no expressive elements “standard, stock, or common” to a unique puzzle game
> that is divorced from any real world representation.

> [https://law.justia.com/cases/federal/district-courts/new-
> jer...](https://law.justia.com/cases/federal/district-courts/new-
> jersey/njdce/3:2009cv06115/235418/61/)

------
soVeryTired
RNGs are like crypto: don't roll your own! There's some really deep number
theory behind many of them. Every RNG I've seen lets you control the seed, so
I'm not sure what he gains by writing his own.

~~~
ChrisSD
Javascript doesn't allow setting the seed: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)

~~~
strenholme
Probably time to use a third party RNG for Javascript then. For example,
[https://gist.github.com/banksean/300494](https://gist.github.com/banksean/300494)
or, if you don’t like MT19937 (shameless plug)
[https://github.com/samboy/rg32hash/blob/master/rg32.js](https://github.com/samboy/rg32hash/blob/master/rg32.js)

------
FabHK
The article is amateurish, and it neither reflects the range and complexity of
issues surrounding PRNGs, nor does it offer any good advice (except maybe
"don't just use the first PRNG you come across").

A better introduction is the PCG website (it's biased towards PCG, but a)
that's not a bad choice for many use cases, and b) it raises and discusses
many issues regarding PRNG choice).

[http://www.pcg-random.org](http://www.pcg-random.org)

EDIT to add: and FWIW, any serious PRNG of course allows seeding, and then the
issue boils down to choosing a shared seed.

------
strenholme
Which random number generator to use can be a heated discussion, with strong
opinions. math.random() and rand() can have issues using poor random number
generators like LCGs instead of good random number generators.

The default “good” random number generator is the “Mersenne Twister” (most of
the time, the 32-bit MT19937 version). It generates numbers which look quite
random while not being cryptographically strong (the problem with crypto-
strong generators is that they tend to be slower, and can still cause legal
issues in some jurisdictions). A lot of languages use this for the default
random number generator.

Some people really like using xorshift generators; with the right parameters,
xorshift can generate high quality numbers while being much simpler than
MT19937. One version of this which some use is JKISS32; it’s small and makes
good numbers.

Random number generators can be tested using a series of tests called
“dieharder”; another test for RNGs is “bigcrush” which takes hours, sometimes
days, to fully run. These tests make sure the random number generators are
statistically random, using a large number of tests of the generator.

My favorite pseudo random number generator is a cryptographically strong one:
RadioGatún[32]. It’s simple, fast, doesn’t require special seeding of its
state (unlike MT19937), and allows the seed to be an arbitrary string instead
of just being a number. It passes all dieharder tests, but I haven’t had a
chance to test it with bigcrush yet. I have a GitHub repo with implementations
of it I have done in various languages (C, Python2, Python3, Javascript, C++,
etc.)

~~~
edflsafoiewq
I would not recommend MT. It fails many tests, that state is big, the code is
complex, and it's not very fast. For non-crypto PRNGs, I'd reach for PCG or
one of Vigna's generators.

~~~
strenholme
I tend to agree, but I need to point out that MT19937 doesn’t fail “many”
tests. It fails, at most, two of the bigcrush tests:
[https://en.wikipedia.org/wiki/Talk:Mersenne_Twister](https://en.wikipedia.org/wiki/Talk:Mersenne_Twister)
and look for the “TestU01” discussion on that page.

The biggest problem with MT19937, besides its complexity and large state size,
is that it needs to have its state properly seeded.

Like I said, it’s a heated debate which random number generator is the best
one.

~~~
FabHK
It is surprisingly heated debate, and it's hard to extract good advice from
experts (I've asked Art Owen, Monte Carlo expert at Stanford, for up-to-date
advice (he recommended MT19937 some 15 years ago), and he was very hesitant to
utter any strong recommendations...)

Having said that, I think most projects should move on from MT19937 by now,
defaulting to a cryptographically secure PRNG, and allowing to switch to a
faster one (such as PCG or xoroshiro) when desired.

~~~
strenholme
MT19937 is probably not the best PRNG out there, but the nice thing about it
is that, for a long time, there was a pretty strong consensus among
programmers that it was the PRNG to use. It’s a better choice than a simple
LCG, which is what programmers tend to use if they’re not using MT.

There are a lot of crypto-strong RNGs out there (AES on OFB mode? Counter
Mode? SHA-3 in SHAKE128 or SHAKE256? Salsa20 or ChaCha? Or, do what I do and
use RadioGatún[32]), so not much standardization on that front.

With non crypto, we have in this thread already mentioned PCG (
[http://www.pcg-random.org/](http://www.pcg-random.org/) ), JKISS32,
xoroshiro, and Vigna’s generators. There are others. Again, not much
standardization.

~~~
FabHK
I thought the xoroshiros are basically Vigna's? Developed further from
precursors.

But you're right, there's no successor anointed yet to MT19937, but it's about
time. Wish some real expert in the field would publish an authoritative
account (but opinionated enough to make real choices) that programming
language devs could point to, and across the board implement:

* safe (ie, a cryptographically secure PRNG) <\- default

* fast (if your application needs speed more than security against adversaries, such as Monte Carlo integration)

* others (if you really know what you're doing)

EDIT to add: it feels a bit like the old chestnut about IBM: nobody ever gets
fired for choosing the Mersenne Twister...

------
Pinbenterjamin
Kind of unrelated, but I recently tested out a scenario for the Dotnet
Environment that worked really well;

I created a 'Random' service that lives for the length of the execution of the
application.

This service has an instance of Random that persists with the object, and
exposes simple methods with min/max parameters.

I register the service in a unity container, and then immediately resolve it,
causing the Random type inside of the random service to instantiate.

Then anywhere I want to generate a random number, I inject that service.

This works because, as long as you persist a single instance of 'Random', two
calls to 'Next' or 'NextDouble' won't result in the same number.

------
perspective1
I'm not in the cryptography or random space beyond using libraries, but these
visualizations are very clever. It's easy to see major problems.

edit: It shows small-periods but otherwise it's not all that useful (see
below).

~~~
jgrahamc
It's easy to see some major problems, but take a look at this:
[https://random.isthe.link/?code=let+x+%3D+Date.now%28%29+%26...](https://random.isthe.link/?code=let+x+%3D+Date.now%28%29+%26+0xFFFFFFFF%3B%0Alet+y+%3D+45342%3B%0Alet+z+%3D+65453%3B%0Alet+w+%3D+z+%5E+y%3B%0Aw+%26%3D+0xFFFFFFFF%3B%0A%0Afunction+randomD%28%29+%0A%7B%0A+++++let+t+%3D+x%3B%0A+++++t+%5E%3D+t+<<+11%3B%0A+++++t+%26%3D+0xFFFFFFFF%3B%0A+++++t+%5E%3D+t+>>+8%3B%0A+++++t+%26%3D+0xFFFFFFFF%3B%0A%0A+++++x+%3D+y%3B+y+%3D+z%3B+z+%3D+w%3B%0A+%0A+++++w+%5E%3D+w+>>+19%3B%0A+++++w+%26%3D+0xFFFFFFFF%3B%0A+++++w+%5E%3D+t%3B%0A+++++w+%26%3D+0xFFFFFFFF%3B%0A%0A++++return+w%2F0xFFFFFFFF%3B%0A%7D%0A%0Aexport+default+randomD%3B)

The random number generator here is used quite often in projects and it looks
pretty random. But if you look at the code you can see that it has four
numbers that store state and its output can be entirely predicted from those
four numbers that are consecutive outputs of the RNG.

~~~
perspective1
Oh wow. At some point I've thrown up my hands and just used Pcg64 because
people I trust but can't possibly verify recommended it. Your post reaffirms
that that was the right decision (trusting others).

~~~
jgrahamc
Worth reading Knuth on this and his attempt to create his own RNG and fail
horribly:
[http://www.informit.com/articles/article.aspx?p=2221790](http://www.informit.com/articles/article.aspx?p=2221790)

------
willis936
Why not use RDRAND?

Also you can always choose well-established, arbitrarily complex psuedo random
algorithms. If you want to guarantee low correlation you could use PRBS
(whatever shift amount you need, 31 may be enough for most scenarios) with the
same shift register values and seeds that are maximally equidistant.

~~~
lvh
Article mentions he wants to make the seed explicit so he can reproduce the
same (randomly selected) environment.

You can use any stream cipher you want instead, of course, but in my
experience for video games the problem isn’t “I need a random bit” (which AES
CTR is very good at but MT or any PCG/LCG is really just as fit for purpose)
but “I need to sample from this weird distribution”. Stuff goes wrong as soon
as someone needs to do something as simple as sampling from a set of
cardinality not exactly a power of two let alone something more complex.

------
grayed-down
Test and debate all you want, but if your application needs random data and it
has access or intermittent access to the internet, use the Cesium isotope 137
:)

[https://www.fourmilab.ch/hotbits/](https://www.fourmilab.ch/hotbits/)

------
woliveirajr
TL;DR: random is hard because computers are deterministic; we use Pseudo-
Random, and each function that generates pseudo-random must be tested to see
how random the results are.

