True RANDOM Numbers.

166 views
Skip to first unread message

Alard Eales

unread,
Mar 21, 2017, 8:33:50 AM3/21/17
to RC2014-Z80
To All Programmers out there,

Is there a way to generate TRUE random numbers in basic on the RC2014.

I have noticed in my STAR TREK Game I am doing the random number generator for
making the Galaxy is not a TRUE random number.

If you start the game from a COLD BOOT UP, then load the game then run it,
You get the same galaxy map each time, if you break the game and run it again
you get a different galaxy.

It seems to generate random numbers from a predefined table I think.
is there anyway in basic 4.7b to do real random numbers.

In QBASIC you can use the command RANDIMUZE or RANDOMIZE TIMER
which used the real time clock of the PC to generate a seed number for random numbers.

The RC2014 as a basic machine does not have a time clock or a randomize command.

HHEELLPP......

Thanks.....AJ

Scott Lawrence

unread,
Mar 21, 2017, 9:43:02 AM3/21/17
to rc201...@googlegroups.com
not sure if you want to dive into the ASM side of things, but you could always write an asm routine to generate a better random number using some other resources.

- Years ago I wrote a game for Z80/Pac-Man hardware, which had a 60hz interrupt, which i used to count ticks.  I used this to count the number of ticks between when a user dropped in a coin and when they hit start (iirc).  I used this as the seed for a RNG.  (https://github.com/BleuLlama/bleu-romtools/blob/master/code/z80kernel/Core/rand.asm is the code, it may require tweaking to get it to work on whatever assembler you'd use.)

- The "r" register in the z80 has the number of cycles that the Z80 has run % 255.  This can also be used to provide randomness.

About the only way you'll get true random is to make a hardware module to provide that. Perhaps a photocell or some sort of analog noise generator, digitize it in 16 bit and only look at the noisy bottom bits. ;)

-s

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+unsubscribe@googlegroups.com.
To post to this group, send email to rc201...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/rc2014-z80/3b957f08-c5c6-4860-8df2-738eb51195f5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Scott Lawrence
yor...@gmail.com
Message has been deleted

Alard Eales

unread,
Mar 21, 2017, 10:13:02 AM3/21/17
to RC2014-Z80
Hi Scott,

Thanks for the idea's, but I don't want people to build special circuits to play my game.
I want it to be as normal as possible for everyone to play.

The (R) Register seems a good way to go, how do you read the register in basic and what memory location is it at to read??
255 game chances is better than the same game from Cold Booting every time....

Thanks... 



Scott Lawrence

unread,
Mar 21, 2017, 10:17:00 AM3/21/17
to rc201...@googlegroups.com
it's a register in the CPU so you'd need an asm call to get it... I'm not at my home computer right now, but i believe i can write up a small thing to do it tonight.

-s

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+unsubscribe@googlegroups.com.
To post to this group, send email to rc201...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Scott Lawrence
yor...@gmail.com

Alard Eales

unread,
Mar 21, 2017, 10:29:13 AM3/21/17
to RC2014-Z80
That would be great, but I would need it as data statements to program it in to memory as I don't know Z80 ASM CODE.
and the reading would need to be in a specific memory location to peek it out of memory I suppose
( the highest 32K memory location available that isn't being used by the system or basic.

My program once it is running has about 1K free memory on a 32K system so it is going to be a tight squeeze.

LOL....   Thanks...


On Wednesday, March 22, 2017 at 1:17:00 AM UTC+11, Scott Lawrence wrote:

Scott Lawrence

unread,
Mar 21, 2017, 10:35:29 AM3/21/17
to rc201...@googlegroups.com
Understood. I'll provide BASIC code, with the machine language as DATA.  ;)  Actually, I'm going to write up a blog post about it too.

-s

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+unsubscribe@googlegroups.com.
To post to this group, send email to rc201...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Scott Lawrence
yor...@gmail.com

Alard Eales

unread,
Mar 21, 2017, 10:48:20 AM3/21/17
to rc201...@googlegroups.com
Excellent... (RUBBING HANDS AND SPEAKING LIKE MR BURNS)


Sent from Aj's iPhone.
You received this message because you are subscribed to a topic in the Google Groups "RC2014-Z80" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rc2014-z80/mPqfeuTUUFo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rc2014-z80+...@googlegroups.com.

To post to this group, send email to rc201...@googlegroups.com.

Daniel Quadros

unread,
Mar 21, 2017, 11:02:40 AM3/21/17
to RC2014-Z80
Here is a crude idea that may work: a counter while waiting for the user to press a key. I am away from my RC2014 right now, so I've not tested this code!

10 OUT 128,22
20 PRINT "Hit any key"
30 CONT=-1
30 IF (INP(128) & 1) <> 0 THEN GOTO 60
40 CONT = CONT - 1
50 GOTO 30
60 X = INP(129)
70 OUT 128,150
70 PRINT RND(COUNT)

The OUTs will turn off the Rx interrupt at the beginning and on at the end, so we can test if a key is pressed by checking the status of the ACIA. The key itself is consumed (and ignored) by X=INP(129)

Daniel

Alard Eales

unread,
Mar 21, 2017, 11:20:21 AM3/21/17
to rc201...@googlegroups.com
Sounds good as well Daniel, ill have a play later tonight as it is 2:19 am and i need my ugly sleep.  Lol



Sent from Aj's iPhone.
--
You received this message because you are subscribed to a topic in the Google Groups "RC2014-Z80" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rc2014-z80/mPqfeuTUUFo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rc2014-z80+...@googlegroups.com.
To post to this group, send email to rc201...@googlegroups.com.

A A

unread,
Mar 21, 2017, 6:51:13 PM3/21/17
to RC2014-Z80


On Tuesday, March 21, 2017 at 9:20:21 AM UTC-6, Alard Eales wrote:
Sounds good as well Daniel, ill have a play later tonight as it is 2:19 am and i need my ugly sleep.  Lol

Yes as Daniel mentions, what everyone does is set up a counter and wait for a key press.  Use the count value to seed the random number generator and all done.  In the C version of the game this is what's done too.  A nice side effect is you can allow the player to enter a game number (the seed value) to repeat a specific game.

This is the sort of thing that is done in a lot of z80 games:

    in_wait_nokey();
    for (counter = 31416; !in_test_key(); counter += 10061) ;
    srand(counter);

where the counter increment is a prime and is chosen to generate rapidly changing 16-bit seed values even for brief loops.

There are some high quality and fast random number routines available for the z80 (marsaglia xor and cmwc) if one is looking for such a thing.  You have to dodge 99% of the web search returns to avoid the poor quality ones.  But the built in basic one is likely completely adequate given randomized initial seed.


Scott Lawrence

unread,
Mar 22, 2017, 1:24:47 AM3/22/17
to rc201...@googlegroups.com
Okay, here's the deal.

My routine i posted earlier in here, references a sine function which uses a 128 byte table which is a bit much for this. ;)  However, the 'register r' method should still work... although not in the emulator.  oops.  Anyway, the ASM used here will work in both, although it's less than random in the emulator. Sorry about that.

Here's the ASM:

; example code for a BASIC USR function

DEINT      = 0x0a07

ABPASS     = 0x117D


.area   .CODE (ABS)

.org    0xF800

usr:

        ld      a, r            ; a = r

        inc     a               ; a++

        ld      r, a            ; r = a


        ld      b, a

        xor     a

        jp      ABPASS


Essentially:
- it reads the R register, increments it (so it works in the emulator), then saves the value back in R
- It then moves that value into B, and sets a=0.  (moving it as an 8 bit number into the "AB" register pair
- Then it jumps to ABPASS which is the NASCOM BASIC function to take the value in AB and return it from the USR() function.

The following BASIC code fills the above code (lines 9001, 9002) into RAM, sets the USR hook to point to this code.

Then there's an example of using it too.

20 REM == poke at 0xF800 ==

30 let mb=&HF800


100 print "Poking in the program...";

110 read op

120 if op = 999 then goto 160

130 poke mb, op

140 let mb = mb + 1

150 goto 110

160 print "...Done!"


200 REM == JP start address (c3 00 f8) jp f800 ==

210 mb = &H8048

220 poke mb, &HC3

230 poke mb+1, &H00

240 poke mb+2, &HF8


250 print "Calling usr()..."

260 print usr(0)

270 end


9000 REM == program == 

9001 DATA 237, 95, 60, 237, 79, 71, 175, 195, 125, 17

9003 DATA 999


Obviously, you can rework this for your own use.  Just make sure you have that "999" value at the end of the DATA list so that it knows when to stop poking!  :D

-s 


--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+unsubscribe@googlegroups.com.
To post to this group, send email to rc201...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Scott Lawrence
yor...@gmail.com

James Harland

unread,
Oct 22, 2025, 8:41:19 AMOct 22
to RC2014-Z80
Hi sorry this is a blast from the past, but I would like to have a routine like this, as I can't get INKEY$ working at the moment. I cleaned up the line numbers of your code and made sure the variable was called COUNT throughout, but I'm getting SN at line 40. Running this on 32k BASIC on a RC 2014 Classic II.

10 OUT 128,22
20 PRINT "Hit any key"
30 COUNT = -1
40 IF (INP(128) & 1) <> 0 THEN GOTO 60
50 COUNT = COUNT -1
60 GOTO 30
70 X = INP(129)
80 OUT 128,150
90 PRINT COUNT

James Harland

unread,
Oct 23, 2025, 11:57:43 AM (14 days ago) Oct 23
to RC2014-Z80
Again for posterity, here is the fixed version of the code, which produces a negative number based on how long it took the user to press any key and works on Nascom BASIC on the RC 2014 Classic ][. This number, which is negative, can then be fed into RND to reseed the random numbers table.

10 OUT 128,22
20 PRINT "Hit any key"
30 COUNT = -1
40 IF (INP(128) AND 1) = 0 THEN GOTO 100
50 X = INP(129)
60 OUT 128,150
70 PRINT COUNT
80 END
100 COUNT = COUNT - 1
110 GOTO 40

James Harland

unread,
Oct 23, 2025, 12:04:57 PM (14 days ago) Oct 23
to RC2014-Z80
X is the ASCII code of the keypress, so this is a fairly good reproduction of INKEY$ 

James Harland

unread,
Oct 23, 2025, 12:13:38 PM (14 days ago) Oct 23
to RC2014-Z80
10 REM Inkey$ for Nascom BASIC
20 OUT 128,22
30 PRINT "Hit any key"
40 IF (INP(128) AND 1) = 0 THEN 40

50 X = INP(129)
60 OUT 128,150
70 PRINT "You pressed "; CHR$(X)
80 END
Reply all
Reply to author
Forward
0 new messages