Mouse In A Hole, the platform game the course builds in Xtal BASIC 4.2, running on the Tatung Einstein: the mouse mid-jump between platforms, two cats and the cheese
← Back to Courses
module
16

Chance

Introduction

A program that does the same thing every time is a demonstration. A game needs the cats to start somewhere different, the dice to fall differently, the question to be one you have not just had.

RND is where that comes from, and it has one detail on this machine that will give you an off-by-one bug the first time you use it.

RND

Two forms, and they do different things.

RND(1) gives a fraction between 0 and 1 - something like .171944.

RND(n), for any n of 2 or more, gives a whole number from 0 to n-1.

Read that second one again, because it is the trap. RND(6) does not give you 1 to 6. It gives you 0 to 5. Two hundred throws in a row produced a lowest of 0 and a highest of 5, and never a 6.

So a die is:

RND(6)+1

and a card from a pack of 52 is RND(52)+1, and a coin is RND(2), which is 0 or 1 and needs nothing added.

The rule in general: RND(n)+1 for 1 to n, and RND(n) when you are happy to count from 0 - which, since arrays count from 0 too (S14), is often exactly what you want:

PRINT NAME$(RND(4))

picks one of NAME$(0) to NAME$(3).

Getting Any Range You Like

From the fraction form you can build anything:

INT(RND(1)*100)

gives 0 to 99 - multiply the fraction by how many you want and throw the fraction away with INT. That is the long way round for whole numbers, but it is the only way when you want a range that does not start at 0, or a fractional value:

X=RND(1)*255

gives a position anywhere across the screen, decimal places and all.

It Is Different Every Time

Some computers give you the same "random" numbers every time they start, which is a nuisance in a game and a blessing when you are trying to find a bug. This one does not. The numbers depend on exactly how long after BASIC started the program first asks for one, and nobody types at exactly the same moment twice. Start the machine afresh, run the same program, and you get a different sequence - and there is no way to ask for a particular one.

That has a practical consequence worth knowing now: a program that uses RND cannot be tested by running it twice and comparing. If something goes wrong once and you cannot make it happen again, that is why. When you are hunting a bug in a program with chance in it, take the RND out temporarily - put a fixed number in its place - find the bug, then put it back.

The Code

10 PRINT "TEN THROWS OF A DIE:"
20 FOR I=1 TO 10
30 PRINT RND(6)+1;
40 NEXT I
50 PRINT
60 PRINT "A FRACTION:";RND(1)
70 PRINT "A COIN:";
80 IF RND(2)=0 THEN PRINT "HEADS":ELSE PRINT "TAILS"

Starting from

A fresh boot, or NEW.

What you should see

Something like this - and not exactly this, which is the point:

RUN
TEN THROWS OF A DIE:
 6  2  1  3  6  6  4  4  1  6
A FRACTION: .171944
A COIN:TAILS
Ready

Run it again and the numbers change:

RUN
TEN THROWS OF A DIE:
 6  5  3  1  3  6  5  4  1  6
A FRACTION: .700281
A COIN:TAILS
Ready

Two runs of the same program, giving different numbers

Every throw is between 1 and 6 because of the +1 on line 30. Take it off and you will see a 0 within a few runs.

Change One Thing

  • Take the +1 off line 30 and run it a few times. What is the lowest number you can get, and the highest?
  • Change line 30 to PRINT RND(1); and run it. What comes out now, and how would you turn those into die throws?
  • Change line 80 to IF RND(2)=1 THEN .... Does the coin still work? Would RND(2)=2 work?

Exercises

16.1 Throw two dice a hundred times and count how many times the total is 7. (Two separate RND(6)+1s, not one RND(11).)

16.2 Put six sayings in DATA, read them into an array, and print one at random each time the program runs.

16.3 Write the guessing game from S11 again, but have the machine pick the secret number with RND so that it is different every time - and keep asking, using a loop from S13, until the guess is right.

Worked solutions are in Appendix II.

When It Goes Wrong

SymptomCause
A die sometimes throws 0RND(6) is 0 to 5. Add 1.
A die never throws 6The same thing from the other end.
RND always gives a fractionYou asked for RND(1). Any number of 2 or more gives a whole number.
Qty ErrorA negative argument. RND(-1) is not a way of seeding it; there is no way. (RND(0) gives the last number again.)
A bug you cannot reproduceThe sequence is different every run. Replace the RND with a fixed number while you hunt it.
An array subscript from RND gives Range ErrorRND(n) reaches n-1, so RND(n)+1 reaches n - one past a DIM(n-1). Count carefully.

Summary

RND(1) gives a fraction from 0 to 1. RND(n) gives a whole number from 0 to n-1, so a die is RND(6)+1. INT(RND(1)*n) does the same job the long way and handles ranges that do not start at 0. The sequence depends on the moment it is first used and cannot be set, so a program with chance in it cannot be run twice the same way.

Next

S17, Colour And Where Text Goes - the first of the screen sections, and the beginning of the game.

Get the Newsletter

New guides, disk images and community finds, roughly once a quarter. No spam, we promise, this isn't Tatung's marketing department.
Your subscription could not be saved. Please try again.
Your subscription has been successful.

Newsletter

Subscribe to our newsletter and stay updated.