Lack of randomness sometimes when compiling for Glulx

Here’s something of a gaffer tape non-I6 workaround that can be easily implemented across the board in 6M62 and 10.1.2:

Summary
Section - Fix the Glulx/Git pseudo-random number generator bug

[This fixes a bug with the pseudo-random number generator of the Glulx and Git interpreters shipped with the Windows IDE up to at least Ver 10.1.2]
[The bug causes partially-predictable sequences of values to be generated when a random range is 1 to 2^n wide, e.g. 1 to 4, 1 to 16 etc.]
[After any given number of calls to the PRNG the values will follow within one of 2^n distinct and predictable sequences, although which of the 2^n sequences they will follow is not predictable in advance]
[This does however mean that at certain points in the sequence the result is completely predictable- when all sequences have the same value-, e.g. for the first random number generated with the Glulx PRNG, if the range is 1-4 the result is ALWAYS 3, because all 4 potential sequences start with 3]
[
(sequence 1)   3424412223...
(sequence 2)   3214332411...
(sequence 3)   3444212243...
(sequence 4)   3234132431...
]
[This means for example that if we start the game by 'randomly' picking one of 4 passwords, or saying one of 4 phrases 'purely at random' it will invariably be the 3rd password that is picked, or the third phrase that is said.]
[similarly, the 4th time the PRNG is run, if the range is 1-4 the result is always 4, the 10th time the result is always 1 or 3 etc.]
[Furthermore, if it is possible to establish which sequence is being followed and from where, ALL subsequent results are ENTIRELY predictable]
[This faulty behaviour appears intrinsic to the PRGN algorithm and is independent of how it is seeded]
[Other versions of Git and Glulx in the wild may use different PRGN algorithms, or may use different operating system algorithms, and may not be affected by the bug at all.]
[It is easy to test for this with the Glulx interpreter:
	
First when play begins: say "This story is brought to you by the number [one of]1[or]2[or]3[or]4[purely at random]."

If the bug is present, the number will always be 3.

Or for Git:

First when play begins:
	let n be a random number between 1 and 32633;
	let n be a random number between 1 and 32633;
	say "This story is brought to you by the number [one of]1[or]2[or]3[or]4[purely at random]."

If the bug is present, the number will always be 4 (the third number in all 4 sequences is 4, for the Git interpreter).
]
[One workaround is to prime randomisation before play beegins by calling the PRGN a random number of times, so that it is unknown both from where, and in which, of the potential fixed sequences subsequent results are being drawn.  This will work well for situations likely to arise in IF, where the random range is likely to be quite low- under 1000]
[Another approach is to replace I6's random() function to eliminate this bug, which can be easily done before Ver 10 but is not so straightforward thereafter.]
[This fix adopts the former approach and should work for any version of Inform 7 shipped with the affected Glulx or Git interpreter]
[Again, due to the quirks of the PRNG, it's more effective to choose a prime number (possibly simply an odd number) for the upper bound of the number of times the PRNG will run during priming]
[And, with Git, we also need to 'warm up' the PRNG before even calling our high prime random range]

The prime the random number generator rule is listed after the seed random number generator rule in the startup rules.
The prime the random number generator rule is listed before the update chronological records rule in the startup rules.
This is the prime the random number generator rule:
	let dummy be a number;
	repeat with n running from 1 to 100
		now dummy is a random number between 1 and 4; [warm up the RNG for Git]
	let b be a random number between 1 and 32633; [a high prime number, but not so high as to cause a significant delay to start-up]
	repeat with n running from 1 to b:
		now dummy is a random number between 1 and 4; [range used here makes no difference]

EDIT: updated to ensure proper working for Git- see post below

1 Like