How to create random number with machine code?

Here you can ask questions or provide insights about how to use efficiently 6502 assembly code on the Oric.
User avatar
peacer
Flight Lieutenant
Posts: 451
Joined: Wed Jun 09, 2010 9:23 pm
Location: Turkey
Contact:

How to create random number with machine code?

Post by peacer »

Can you help me how to create a random number with machine code?

I need 4 different cases when I call the routine. So what ı want is ;

For example.. As basic commands
CALL x
P=PEEK(0)

So, P will get 0,1,2 or 3 randomly from memory adress 0

To explain it briefly Its like P=INT (4*RND(0))

Thanks
User avatar
Symoon
Archivist
Posts: 2307
Joined: Sat Jan 14, 2006 12:44 am
Location: Paris, France

Re: How to create random number with machine code?

Post by Symoon »

Short reply (sorry, in a hurry): I would read the timer's low byte and keep the 2 lower bits from it.

Something like
LDA $0308
then any other instruction to set the 6 bits to 0, giving 000000xy
(than would probably be AND #$03 but please double check, I have to leave now ;) )

then A = 0, 1, 2 or 3.
Store it in $00 with
STA $00

and don't forget to end the program with
RTS
User avatar
peacer
Flight Lieutenant
Posts: 451
Joined: Wed Jun 09, 2010 9:23 pm
Location: Turkey
Contact:

Re: How to create random number with machine code?

Post by peacer »

Thank you, short and easy :)
User avatar
Badger
Pilot Officer
Posts: 84
Joined: Sat Sep 22, 2018 10:04 am
Location: Wigan, England

Re: How to create random number with machine code?

Post by Badger »

I can confirm Symoon's answer is correct.

In basic you can just do :-
POKE 0,PEEK(#308)AND3

and in assembly

lda $0308
and #$03
sta $00
rts
flag_uk Amateurs built the Ark, Professionals built the Titanic.
User avatar
peacer
Flight Lieutenant
Posts: 451
Joined: Wed Jun 09, 2010 9:23 pm
Location: Turkey
Contact:

Re: How to create random number with machine code?

Post by peacer »

Thank you too :)
User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: How to create random number with machine code?

Post by NekoNoNiaow »

How are you using the generated random numbers?
I ask because if you are generating them inside a loop there is a high chance that they will repeat if the timing of the loop is more or less constant. What I would recommend actually is to use a simple modulo based random generator (*) and initialize it using the number read from the timer.

(*) here is a simple enough one that gives very acceptable results for a relatively good performance (if you use a multiplication table): https://en.m.wikipedia.org/wiki/Lehmer_ ... _generator.
There was a very good article about random number generation in STMag back in the day which implemented that type of particular generator. If someone recalls which issue that was then please mention it, as it is probably very simple to adapt to the Oric.
User avatar
Badger
Pilot Officer
Posts: 84
Joined: Sat Sep 22, 2018 10:04 am
Location: Wigan, England

Re: How to create random number with machine code?

Post by Badger »

I discovered this online somewhere to give integers upto 255 :-

Code: Select all

getrand
.(
	lda $01
	beq doEor
    	asl
	beq noEor ;if the input was $80, skip the EOR
	bcc noEor
doEor   
	eor #$1d
noEor  
	sta $01
	rts
.)
All you need to do is seed $01 with any number at the start or again later with something like the value of the timer after a keypress.
I put together the below to show this. It waits for a keypress and seeds the random number generator (shown above) with the timer value. Prints the seed on the status line, then prints 200 random numbers to the main part of the screen.

Code: Select all

#define STATUS_LINE ($BB80+2)		;first char of status line ignoring attribute chars
#define DISPLAY_ADDRESS ($BB82+40) 	;first char of non-status line ignoring attribute columns
#define RANDLOC $01  			;memory location of random number - change as you like
.text
main
.(
	jsr clrscreen			;clears the screen


nokey					;check for any keypress
	lda $208
	cmp #56
	beq nokey	
	
	
setseed	
	lda #<STATUS_LINE		;set up memory to print seed on status line
	sta write+1
	lda #>STATUS_LINE
	sta write+2
	jsr gettimer 			;seed random generator with current value of timer 1
	lda RANDLOC	
	jsr PrDec			;Print value of random number seeded to screen

	
	lda #<DISPLAY_ADDRESS		;set up memory of 1st character to display random numbers
	sta write+1
	lda #>DISPLAY_ADDRESS
	sta write+2
	ldx #200 			; loop counter 
mainloop
	jsr getrand			; random number generator
	jsr PrDec			
	jsr addspace			;add spaces between numbers
	dex	
	bne mainloop
	rts

write				; write char and advance 1 position
	sta $0123
	clc			; Calc new scren address
	lda write+1
	adc #01
	sta write+1
	lda write+2
	adc #0
	sta write+2
	rts

addspace			;add spaces between numbers
	clc			
	lda write+1
	adc #2
	sta write+1
	lda write+2
	adc #0
	sta write+2
	rts


PrDec						; routine to print out decimals to screen
	ldy #$FF
	sec     
PrDec100
	iny
	sbc #100
	bcs PrDec100  				;\ Count how many 100s
   	adc #100
	jsr PrDecDigit    			;\ Print the 100s
   	ldy #$FF
	sec               			;\ Prepare for subtraction
PrDec10
	iny
	sbc #10
	bcs PrDec10    				;\ Count how many 10s
	adc #10
	jsr PrDecDigit     			;\ Print the 10s
	tay	                        	;\ Pass 1s into X
PrDecDigit
	pha
	tya			                ;\ Save A, pass digit to A
	ora #$30
	jsr write
	pla
	rts


.)


gettimer			;get current value of timer 1
.(
lda $304
sta RANDLOC			; store as seed for random number generator
.)

clrscreen			; clears text screen
.(
	lda #<DISPLAY_ADDRESS
	sta write2+1
	lda #>DISPLAY_ADDRESS
	sta write2+2
	
	ldy #27			;row to loop
clearloop2
	ldx #38			;cols to loop
clearloop1
	lda #32			;ASCII of char to write to screen
	jsr write2
	jsr add1		; advance to next screen position
	dex
	bne clearloop1
	jsr newline		; advance to next line and skip attribute columns
	dey
	bne clearloop2
	rts

write2
	sta $0123
	rts
add1
	clc			
	lda write2+1
	adc #1
	sta write2+1
	lda write2+2
	adc #0
	sta write2+2
	rts

newline
	clc			
	lda write2+1
	adc #2
	sta write2+1
	lda write2+2
	adc #0
	sta write2+2
	rts

	

.)

getrand				; random number generator
.(
	lda RANDLOC			;loads A with last value of random generator (either the seed or last random)
	beq doEor
    	asl
	beq noEor 			;if the input was $80, skip the EOR
	bcc noEor
doEor   
	eor #$1d
noEor  
	sta RANDLOC
	rts
.)
As an aside to this, I've found that the PrDec routine to the status line is ideal for watching the values of memory or registers without using the monitor or over-writing anything on the main screen.

Hope this helps.
flag_uk Amateurs built the Ark, Professionals built the Titanic.
User avatar
iss
Wing Commander
Posts: 1641
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: How to create random number with machine code?

Post by iss »

@Badger: +1!
IMO this is the best way to produce random numbers too: keypress+timer+algo.
I'm using the same algorithm and the original comes from HERE. ;)
User avatar
Chema
Game master
Posts: 3014
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: How to create random number with machine code?

Post by Chema »

This is the routine I use in my games. I remember I tested its randomness and it was quite good!

Code: Select all

; A real random generator... 
randseed .word $dead 	; will it be $dead again? 
randgen 
.(
   lda randseed     	; get old lsb of seed. 
   ora $308		; lsb of VIA T2L-L/T2C-L. 
   rol			; this is even, but the carry fixes this. 
   adc $304		; lsb of VIA TK-L/T1C-L.  This is taken mod 256. 
   sta randseed     	; random enough yet. 
   sbc randseed+1   	; minus the hsb of seed... 
   rol			; same comment than before.  Carry is fairly random. 
   sta randseed+1   	; we are set. 
   rts			; see you later alligator. 
.)
User avatar
goyo
Officer Cadet
Posts: 52
Joined: Sat Jan 12, 2019 10:16 am

Re: How to create random number with machine code?

Post by goyo »

Badger wrote: Fri Feb 01, 2019 10:23 am I discovered this online somewhere to give integers upto 255 :-

Code: Select all

getrand
.(
	lda $01
	beq doEor
    	asl
	beq noEor ;if the input was $80, skip the EOR
	bcc noEor
doEor   
	eor #$1d
noEor  
	sta $01
	rts
.)
All you need to do is seed $01 with any number at the start or again later with something like the value of the timer after a keypress.
I put together the below to show this. It waits for a keypress and seeds the random number generator (shown above) with the timer value. Prints the seed on the status line, then prints 200 random numbers to the main part of the screen.
I tried to call your method from c but it's look like a répétitive séquence ... :

Code: Select all

unsigned char b;
asm("lda %b;"
         "beq doEor;"
         "asl;"
         "beq noEor;"
         "bcc noEor;"
"doEor:    eor #$1d;"
"noEor:  sta %b;");
with this following program we can see the repetitive sequence (graphics):

Code: Select all

// unsigned int randgen();

unsigned i;
unsigned char b;

void main()
{
	
	unsigned adr=0xA000;
	b=65;
	hires();
	//cls();
	for (i=0;i<8000;i++)
	{
	
		
		asm("lda %b;"
         "beq doEor;"
         "asl;"
         "beq noEor;"
         "bcc noEor;"
	"doEor:    eor #$1d;"
	"noEor:  sta %b;");
		

			//printf("b=%d \n",b);
			if ((b>0)&&(b<128))
			{
				if ((b>7)&&(b<16))
				{
				}
				else	
				{
					if ((b<24)||(b>31))
					{
					
							poke(adr+i,b);
						
					}
				}
			}
	}	
	
		
}
User avatar
iss
Wing Commander
Posts: 1641
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: How to create random number with machine code?

Post by iss »

Well spotted, goyo!
This algo actually generates chains with period of 256 and "will cycle through the values $00-$ff exactly once, in a scrambled order". I.e it's like doing "shuffle" but with 256 cards :). I recall that I've used this code because it was small and I needed only numbers in range 0..3, so I've used only 2 low bits.

For a "more real" random generator why not use the OSDK's one but see the Dbug's note here.
User avatar
Badger
Pilot Officer
Posts: 84
Joined: Sat Sep 22, 2018 10:04 am
Location: Wigan, England

Re: How to create random number with machine code?

Post by Badger »

Yes Goyo, there is a trade off between small fast code and randomness and if the seed isnt altered then it will be repetetive.

In a game with lots of keypresses you could just re-seed the routine with the value of the timer ($304) on each keypress which would probably make it as close to random as possible.

I guess, it all depends on what you need and how random you need it to be. In a card game for instance you might actually not want repeating numbers when you shuffle the pack.
flag_uk Amateurs built the Ark, Professionals built the Titanic.
User avatar
Chema
Game master
Posts: 3014
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: How to create random number with machine code?

Post by Chema »

Just for the records. The routine I posted before (made by a friend of mine) produces a repeatable series of numbers between 0 and 32768 (repeatable if the seed is re-used, that is), with quite nice randomness properties. Matlab's randomness test shows:

Code: Select all

[h,p]=runstest(v, median(v))
Warning: X values exactly equal to V are omitted. 
> In runstest (line 167) 
h =
     0
p =
    0.8864
Which apparently means it cannot discard it is a random sequence (which is quite good).

Also this is the histogram of generated values:
hist.png
hist.png (7.3 KiB) Viewed 15957 times
And the routine is small and fast...
Post Reply