Random numbers, electronic dice and the C64
“Alea iacta est”, the dice has been cast. It was Caesar who said these famous words 2000 years ago, but little did he know that dice and dice games would still be around in the 21st century. Indeed, many popular games feature the dice as the tool to introduce randomness in the game. Whether it be the number of spaces your player marker can move or the power of an attack/defense in the game of Risk or the difference between win or lose in a casino, the dice remains a popular item in games.
With the multitude of tablets out in the marketplace though, many games have been ported to the mobile platform and have removed the need for physical dice. The plastic or wooden cubes have been replaced by a random number generator on a computer. Although I am a big fan of the traditional boardgame, I do enjoy a game on the iPad as well (it’s quick to setup, easy when there are no opponents around, and you always have the game with you). Nonetheless, the notion of chance seems a bit artificial on a computer as it’s no longer you, who with the flick of the wrist, throws the dice on the table, hoping for that perfect roll.
To counter this, the company Game Technologies has started to produce “Dice+”. Physical dice, that via a Bluetooth connection transmit the rolled value to the game on your tablet, hence re-introducing the true randomness of the roll into the game.
It’s exactly this true randomness of the roll that is key to the unpredictability of the outcome of the game and something that has “plagued” random generators on computers since day one.
Since the 1950’s random generators on computers have been referred to as pseudo-random generators. The term pseudo reflects the fact that although the numbers may seem random, they express a pattern.
Let’s take a look at the RND function of the Commodore 64 (a more detailed review can be found in Nick Montfort’s book “10 PRINT CHR$(205.5+RND(1));:GOTO 10“, in which he has devoted an entire chapter to this subject).
The RND produces a new and different random number between 0 and 1. Each of those numbers however, is generated based on the value of its predecessor, so if the initial number of 2 random sequences is the same, the two entire sequences will be the same. With the Commodore 64, when “seeding” the sequence with a positive value, such as RND(1), RND(25), RND(.1111), the next value will always be 0.185564016 (it is the one copied from ROM to locations $8B-$8F when you turn the computer on and hence will always be the same). To counter this, the RND implementation on the C64 has 2 other way of introducing randomness.
The first one uses a negative seed value. Contrary to RND(1), seeding the sequence with RND(-1) or RND(-25) or any other negative value, will take a different starting value every time. So negative seeding will be more random, but again, the randomness is predictable. Whereas indeed RND(any positive value) will always produce the same initial result and RND(any negative value) will produce a different initial value, seeding the sequence with the same negative number will still always produce the same initial value. So RND(-654321) will always produce 0.333675369, replacing it with any other negative value will give you a different initial value. So again, pseudo randomness, but at least, it’s a little less predictable.
The second one is a combination of the negative seed value, and the clock time of the computer. Basically the sequence is seeded with RND(-TI). The value of TI depends on how many sixtieths of a second have elapsed since you turned on the computer and produce as described above a positive value to start the sequence. The only time you would now get two exactly the same sequences would be when you run the sequence at exactly the same time after powering on the breadbox.
To introduce even more randomness, you could change the seed value from the clock time to something more exotic the C64 has to offer: the SID chip. Yes, the C64’s synthesizer has the ability to generate random values, as was demonstrated by Neil Boyle back in 1986 (Compute! Issue 72).
All that’s needed is to select the noise waveform for the SID’s voice 3 oscillator and set voice 3’s frequency to some nonzero value (the higher the frequency, the faster the random numbers are generated). Once this is done, random values appear in location $D41B. The parameters need only be set once, as shown in this example:
LDA #$FF ; maximum frequency value
STA $D40E ; voice 3 frequency low byte
STA $D40F ; voice 3 frequency high byte
LDA #$80 ; noise waveform, gate bit off
STA $D412 ; voice 3 control register
Once this code is executed, the SID chip continuously produces random byte values, which you can retrieve with a statement like LDA $D41B. Values obtained from the SID chip do seem to be random: Each of the values in the range 0-255 occurs at about the same frequency, and the series does not repeat in the first 34,000 values.
A Million Random Digits with 100,000 Normal Deviates (RAND Corporation, 1955)
Whether the random number generation approach on the Commodore is truly random has been the subject of some interesting studies (and provides interesting reading for anyone interested in statistical algorithms), such as “Algorithms for randomness in the behavioral sciences: A tutorial – Marc Brysbaert”, “The pseudo-random number generators in Commodore and Apple microcomputers – Afflerbach L.” and “Evaluating pseudo-random number generators – Richard Bowman”.
Some consider it to be random enough (as in the Bowman study), others have their doubts.
Nonetheless, it’s interesting to see that something so trivial as the rolling of a dice, has been the subject of so many discussions and researches. Perhaps buying that iDice might not be such a bad idea after all…
In today’s post, I mention the SID chip as a way of introducing the initial seeding value of the sequence, but how about putting things upside down and using the SID to produce “random” music. Noah Vawter, one of the co-authors of the “10 PRINT” book has done exactly that. He has created a single-line program: 10 POKE 54272+INT(RND(1)*25),INT(RND(1)*256) : GOTO 10
Basically by putting random values into the memory locations beginning at 54272 (which are mapped to the registers of the SID), the SID starts to produce random sounds
Give it a try!