Programming Randomness

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
User avatar
MonkZy
Manic Miner
Posts: 278
Joined: Thu Feb 08, 2018 1:01 pm

Programming Randomness

Post by MonkZy »

I am writing a simple game for the cgc. This is my first ever attempt at writing a machine code routine.

Problem #1 .. Random Numbers.

In my game I require two tables of random 1's and 0's. Table A (roaddata) will be 2 columns x 4 rows, table B (trafficdata) will be 3 columns x 5 rows. There is a couple of rules : No table row should contain all zero's, Table B must not have a row containing all 1's. The tables should feel random.

Each game cycle, the two tables are moved forward, row 2 being copied to row 1 etc. and the last row is filled with a new line of random 1's and 0's

I tried a few things to simulate randomness including using the R register to point to a ROM location. All attempts looked awful, the tables produced did not feel random at all. I guess the ROM contains many patterns which are far from random.

Here is my code as it stands now :

Code: Select all

advanceroad:
ld de,roaddata_row1	;load DE with address of 1st row of roaddata
ld hl,roaddata_row2	;load HL with address of 2nd row
ld bc,6			;copy 6 bytes
ldir			;move road data forward one row

ld de,trafficdata_row1	;load DE with address of 1st row of roaddata
ld hl,trafficdata_row2	;load HL with address of 2nd row
ld bc,12		;copy 12 bytes
ldir			;move traffic data forward one row

ld a,(rndpos)		;load C with the random number pointer
ld c,a
ld b,0
ld hl,randomness	;load HL with adress of the start of random numbers
add hl,bc		;add BC to HL to find next random number address
inc a			;increment the random number pointer
ld (rndpos),a
ld a,(hl)		;load A with the random number


ld de,trafficdata_row5	;load DE with address of 5th row
ld hl,trafficstyle	;load HL with start address of the traffic styles
ld c,a
add hl,bc		;add the random number to the traffic style address
ld bc,3			;copy 3 bytes
ldir

and %00000011	        ;strip to two bytes (random 0 - 3)

ld de,roaddata_row4	;load DE with address of 4th row
ld hl,roadstyle		;load HL with start address of the road styles
ld c,a			;load BC with the random number in A
ld b,0			
add hl,bc		;add the random number to the road style address
ld bc,2			;copy 2 bytes
ldir

ret

roadstyle:
defb 1,1,0,1,1

trafficstyle:
defb 1,1,0,1,0,0,1,1,0,1

roaddata_row1:
defb 0,0
roaddata_row2:
defb 0,0,0,0
roaddata_row4:
defb 0,0,23

trafficdata_row1:
defb 0,0,0
trafficdata_row2:
defb 0,0,0,0,0,0,0,0,0
trafficdata_row5:  
defb 0,0,0

rndpos:
defb 0
randomness:
defb 4, 2, 7, 3, 0, 6, 1, 5
defb 2, 6, 0, 7, 5, 1, 4, 3
defb 4, 1, 3, 6, 2, 0, 5, 7
defb 2, 4, 0, 5, 6, 1, 3, 7
defb 0, 6, 7, 2, 3, 1, 4, 5
defb 1, 7, 5, 6, 2, 3, 0, 4
defb 6, 3, 5, 7, 4, 0, 2, 1
defb 6, 2, 3, 7, 5, 4, 1, 0
defb 3, 4, 1, 0, 7, 2, 6, 5
defb 1, 5, 0, 4, 3, 2, 6, 7
defb 1, 7, 4, 6, 0, 2, 5, 3
defb 4, 5, 1, 7, 0, 3, 2, 6
defb 4, 6, 2, 0, 5, 3, 7, 1
defb 6, 4, 3, 2, 5, 1, 7, 0
defb 7, 5, 2, 3, 0, 1, 6, 4
defb 1, 6, 4, 7, 5, 3, 0, 2
defb 1, 6, 7, 5, 2, 0, 4, 3
defb 6, 0, 1, 7, 5, 3, 2, 4
defb 7, 1, 2, 5, 6, 4, 3, 0
defb 2, 3, 1, 0, 6, 7, 5, 4
defb 3, 1, 2, 5, 4, 0, 7, 6
defb 1, 5, 3, 7, 6, 2, 0, 4
defb 7, 5, 3, 4, 6, 0, 1, 2
defb 1, 7, 6, 5, 4, 0, 3, 2
defb 2, 3, 0, 1, 6, 4, 5, 7
defb 5, 4, 0, 3, 1, 2, 7, 6
defb 3, 2, 7, 1, 5, 6, 0, 4
defb 3, 1, 0, 5, 6, 4, 2, 7
defb 4, 5, 6, 1, 3, 7, 0, 2
defb 7, 2, 5, 6, 0, 3, 4, 1
defb 2, 0, 1, 6, 5, 7, 3, 4
defb 3, 2, 5, 0, 6, 7, 1, 4
I found a method of storing all the good combinations of road/traffic pattern in a list, the list can be accessed with a random number 0-3 or 0-7 (see roadstyle/traffic style). Next I grabbed a set of 256 random numbers from RANDOM.ORG. I have a pointer stored in a memory address, I pull a number from the list, increment the pointer. I have to strip the numbers down to 2 bytes for (0-3). It seem very natural when I look at the output.

My question is this..Is this how it is done? Is there a ROM call that produces good random numbers? Is there a way to avoid the 256B look up table?
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2640
Joined: Mon Nov 13, 2017 3:16 pm

Re: Programming Randomness

Post by Ast A. Moore »

First, a quick tip on code optimization. You can get rid of the LD B,0 instructions: since they follow the LDIRs, the B register is already zero.

There are plenty or random number generators for the Z80, do look them up. The ROM contains chunks of pretty orderly data, so if you want to use it for pseudo random numbers, you need to manually limit the address range. I sometimes use either a cyclic ROM address range, or the R register itself, when I need a quick and dirty random number. The results are, well, mostly acceptable. Here’s a combination of the two:

Code: Select all


random		ld hl,($+1)		;pointer (self-modifying code)
		res 5,h			;limit the range to the 8k of ROM
		ld a,(hl)		;fetch a value
		inc hl			;next address
		ld (random+1),hl	;write back into the HL,(**) instruction above
		ret

		...
		...
		...

		call random
		ld b,a
		ld a,r
		xor b
This is targeted toward speedy execution, rather than true randomness, but it works okay for some situations, especially when the numbers are not required too often (otherwise a pattern might become more obvious).

If I need an even quicker method for, say, ORing with a sprite byte, I might just use the R register alone and occasionally perform shifts on it and combine it with another register or two, depending on how fast I want the routine to be. This is crucial for real–time direct-to-screen drawing.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
R-Tape
Site Admin
Posts: 6353
Joined: Thu Nov 09, 2017 11:46 am

Re: Programming Randomness

Post by R-Tape »

I can't recommend Patrik Rak's RN routine enough:

viewtopic.php?f=6&t=303&hilit=patrik+rak#p3555

You CALL the routine (remember that it corrupts DE and HL) and it returns with a random number 0-255 in A. If you only need 1 or 0 then AND 1 after calling.

Your lookup table is another good way but with only 256 choices repetition may become apparent. You can use the ROM as a rough lookup table, this works ~okay:

Code: Select all

getrandom:	;call routine, return with 'random' value 0-255 in A, HL corrupted
	ld hl,(rndseed)	;point HL at stored place in ROM
	inc hl		;move along
	ld a,h
	and 31	;keep it in lower ROM, upper ROM is repetitive
	ld h,a
	ld (rndseed),hl	;store it for next time
	ld a,(hl)	;get random number in A
	ret
	;
rndseed:	dw	0
	;
But this is the CGC innit? So you should stick with LD A,R :mrgreen:
User avatar
MonkZy
Manic Miner
Posts: 278
Joined: Thu Feb 08, 2018 1:01 pm

Re: Programming Randomness

Post by MonkZy »

This is great.

Ast A. Moore - Self modifying code is an incredibly efficient way of performing the increment of the pointer. This is really interesting.

R-Tape - I may have been picking numbers from the upper part of ROM, so this routine has a better filter than I was using.

Thank you :D
User avatar
Spud
Manic Miner
Posts: 372
Joined: Sun Nov 12, 2017 8:50 pm
Contact:

Re: Programming Randomness

Post by Spud »

Ast A. Moore wrote: Mon Feb 26, 2018 9:58 am First, a quick tip on code optimization. You can get rid of the LD B,0 instructions: since they follow the LDIRs, the B register is already zero.
Along a similar vein to R-Tape, you should be advising on how to make it less optimized! :)
User avatar
MonkZy
Manic Miner
Posts: 278
Joined: Thu Feb 08, 2018 1:01 pm

Re: Programming Randomness

Post by MonkZy »

My game will be crap, I promise. The crapness with be inherent in the game itself. Any chinese factory can attach a rubber ball to a plastic bat with elastic and produce a 'paddle ball', a famously crap game. If rolls royce put all their efforts into producing a paddle ball, using aero-grade materials and technology, it would still be a crap game.
User avatar
R-Tape
Site Admin
Posts: 6353
Joined: Thu Nov 09, 2017 11:46 am

Re: Programming Randomness

Post by R-Tape »

First, a quick tip on code optimization. You can get rid of the LD B,0 instructions: since they follow the LDIRs, the B register is already zero.
I don't think this is helpful when you're starting out, it can cause more confusion if you decide to make changes later. If the memory becomes so full that a few bytes matter (rare) it can be sorted at the end of the project.
User avatar
MonkZy
Manic Miner
Posts: 278
Joined: Thu Feb 08, 2018 1:01 pm

Re: Programming Randomness

Post by MonkZy »

@R-Tape - This was my fear and I have been shuffling code backwards and forwards which is likely to result in a situation where B is not 0. I will put the ld b,0 instructions behind a comment. Hopefully if things break, I will notice the commented out instruction.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Programming Randomness

Post by Nomad »

While the game should be crap, it does not have to be technically crap. :lol:

Pseudo randomness is a tough one, because a lot of the simple techniques don't fool anyone. But to get very nice distributions requires quite a lot of work/complex code.

Sweet spot is going for just enough to fit the job in hand. The Algo (Patrik Rak's) that R-tape is recommending is fine for your application. You can get a lot from figuring out what it does.

If your looking for applied z80 stuff then the Lance L books are great for that, just plug in the spectrum memory location you want to use and you are away.

https://archive.org/details/Z80_Assembl ... _Leventhal

The applications book is also very nice.

https://computerarchive.org/files/comp/ ... utines.pdf

And Zaks

https://archive.org/details/How_to_Program_the_Z80
Post Reply