Jump to content



0

Random in ranges


13 replies to this topic

#1 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,105 posts
  • Location:Baden-Württemberg, Germany

Posted Mon Jul 16, 2007 12:07 PM

what is your fave routine to get random values between x and y?

right now i am using this:

;input x,y (range)
;output a = random[x,y]

get_random: 
rand00	stx rand0+1;20
		sty rand1+1;10
;check x<y if so then switch order 
		cpy rand0+1
		beq rand01
		bcs rand
		stx rand1+1
		sty rand0+1
rand	lda 53770;atari800 random register (0-255)
rand0	cmp #0;20
		bcc rand
rand1	cmp #0;10
		bcs rand
		rts
rand01	txa	;x=y=a
		rts

but is there a quicker solution?

Edited by Heaven/TQA, Mon Jul 16, 2007 12:08 PM.


#2 DEBRO OFFLINE  

DEBRO

    Stargunner

  • 1,862 posts
  • Location:Atlanta, GA

Posted Mon Jul 16, 2007 1:35 PM

Hi there,

What I do is get the number between 0 and max - min and add min to the value. For instance, when I needed a number between 9 and 136 I'd call the random routine which would generate a byte so the value would be 0 <= a <= 255. Then I'd divide the value by 2 so it's now 0 <= a <= 127. Next I'd add 9 so now the value is 9 <= a <= 136.

I hope that makes sense.

#3 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,105 posts
  • Location:Baden-Württemberg, Germany

Posted Mon Jul 16, 2007 1:50 PM

but what if you dont know the range as the range could be as well completly random?

#4 DEBRO OFFLINE  

DEBRO

    Stargunner

  • 1,862 posts
  • Location:Atlanta, GA

Posted Mon Jul 16, 2007 5:11 PM

View PostHeaven/TQA, on Mon Jul 16, 2007 3:50 PM, said:

but what if you dont know the range as the range could be as well completly random?
Maybe I'm suffering from tunnel vision. When would you not know the range you're trying to achieve? I guess I could see that if you were trying to make a generic routine.

#5 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,105 posts
  • Location:Baden-Württemberg, Germany

Posted Tue Jul 17, 2007 3:09 AM

Debro...

i am coding an action RPG at the moment and in the game a lot of things are based on randomness, sometimes in a controlled way. f.e the damage of a weapon is based on the weapon stats and the player stats... simplified think about a dagger with attack range of 2-4 hitpoints... other weapons might have a range from 10-20 etc... and even the attack itself is based on rolling a dice (0-99) and testing against some values...

the issue here is that i do not know what kind of ranges are needed...thats why i would like to have a fast but generic random routine. the only random routine which could be optimised (and i guess i will do that...) is the RAND(100) function...

i hope its little bit clearer now.

#6 Robert M OFFLINE  

Robert M

    Stargunner

  • 1,481 posts
  • Rootbeer!
  • Location:Western NY state

Posted Wed Jul 18, 2007 10:18 PM

I don't know if I can offer a faster routine in all cases, but the one below does have a guaranteed worst case execution time.

Cheers!
Rob

	SUBROUTINE
	
Answer	DS.W	1; Allocate 16-bits 
Adder	DS.W	1; Allocate 16-bits
Mult	DS.B	1;
lobyte 	EQU 	0; byte offsets into Answer and Adder.
hibyte	EQU		1	
	
RangedRandom
; Given X = min, and Y = max; where 0 <= X <= Y <= 254
; Returns a random number in A, between min and max inclusive
; in linear time.

	STX Answer.hibyte; Start at the minimum posible value.
	TYA; A = max
	SEC		; Calculate the number of possible values
	SBC	min	; that could be returned as max - min + 1
	ADC	#0	; Carry is always set by previous subtraction.
	STA	Adder.lobyte; Fraction to be mulitplied 0 - 255 times.
					; and added to min to form the answer.
	
	LDA	#0
	STA	Adder+hibyte; Adder  =  00:max-min+1
	STA Answer+lobyte; Answer = min:00
	
	LDA 53770;atari800 random register (0-255)	

whileMultNotZeroDo	; This loop executes 0 to 8 times.
	BEQ	.Done
	
	LSR				; check if next bit in Mult is set.
	STA	Mult
	BCC .skipAdd		
	
	CLC				; Add Adder to Answer (16-bit addition).
	LDA	Answer+lobyte
	ADC	Adder+lobyte
	STA	Answer+lobyte
	LDA	Answer+hibyte
	ADC	Adder+hibyte
	STA	Answer+hibyte
.skipAdd	

	ASL	Adder+lobyte; Multiply the 16-bit adder by 2 every
	ROL	Adder+hibyte; time through the loop. x1,x2,x4,...,x128
	
	LDA	Mult
	BCC	whileMultNotZeroDo; branch is always taken.

.Done	
	LDA	Answer+hibyte; A = random # in range min to max.
	RTS				; X = min; Y = max


#7 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,105 posts
  • Location:Baden-Württemberg, Germany

Posted Thu Jul 19, 2007 2:20 AM

Thanks Rob,

have to check on weekend.

btw. could be a RAND(100) done like that?

lda 53770 ; (random value 0-255)
lsr
lsr
clc
adc #36

???

Edited by Heaven/TQA, Thu Jul 19, 2007 2:21 AM.


#8 Kurt_Woloch OFFLINE  

Kurt_Woloch

    Dragonstomper

  • 705 posts

Posted Thu Jul 19, 2007 2:37 PM

View PostHeaven/TQA, on Thu Jul 19, 2007 10:20 AM, said:

btw. could be a RAND(100) done like that?

lda 53770 ; (random value 0-255)
lsr
lsr
clc
adc #36

???

I don't think this would work... you convert the random value 0-255 to 0-63, and then add #36 to that... which gives a random value in the range of 36 to 99... not 0 to 99 as you probably would like it to be (unless the LSR command does something else than I expect).

#9 Robert M OFFLINE  

Robert M

    Stargunner

  • 1,481 posts
  • Rootbeer!
  • Location:Western NY state

Posted Thu Jul 19, 2007 10:23 PM

View PostHeaven/TQA, on Thu Jul 19, 2007 2:20 AM, said:

Thanks Rob,

have to check on weekend.

btw. could be a RAND(100) done like that?

lda 53770 ; (random value 0-255)
lsr
lsr
clc
adc #36

???

When you say a RAND(100) function, I am guessing that you mean you want the random value returned to be in BCD format. If that is what you mean, then it is possible. We just need to feed the routine min and max numbers in BCD format, and use BCD math internally. My untested BCD version of the routine is below. The routine is slowed a bit by using BCD, but not much.

Cheers!

	SUBROUTINE
	
Answer	DS.W	1; Allocate 16-bits 
Adder	DS.W	1; Allocate 16-bits
Mult	DS.B	1;
lobyte 	EQU 	0; byte offsets into Answer and Adder.
hibyte	EQU		1	
	
BCDRangedRandom
; NOTE: This routine assumes inputs in BCD format, and returns
; a BCD value in A.  
; Given X = min, and Y = max; where 0 <= X <= Y <= 99 [BCD]
; Returns a random number in A, between min and max inclusive
; in BCD format.

	SED		; Put the processor in BCD math mode.

	STX Answer.hibyte; Start at the minimum posible value.
	TYA 	; A = max
	SEC		; Calculate the number of possible values
	SBC	min	; that could be returned as max - min + 1
	ADC	#0	; Carry is always set by previous subtraction.
	STA	Adder.lobyte; Fraction to be mulitplied 0 - 255 times.
					; and added to min to form the answer.
	
	LDA	#0
	STA	Adder+hibyte; Adder  =  00:max-min+1
	STA Answer+lobyte; Answer = min:00
	
	LDA 53770;atari800 random register (0-255)	

whileMultNotZeroDo	; This loop executes 0 to 8 times.
	BEQ	.Done
	
	LSR				; check if next bit in Mult is set.
	STA	Mult
	BCC .skipAdd		
	
	CLC				; Add Adder to Answer (16-bit addition).
	LDA	Answer+lobyte
	ADC	Adder+lobyte
	STA	Answer+lobyte
	LDA	Answer+hibyte
	ADC	Adder+hibyte
	STA	Answer+hibyte
.skipAdd	

; a BCD number can not be shifted to mulitply by 2. 
; instead the code must add the BCD number it to itself.
; Carry should always be 0 at this point so no CLC is needed here.
	LDA	Adder+lobyte
	ADC	Adder+lobyte
	STA	Adder+lobyte
	LDA	Adder+hibyte
	ADC Adder+hibyte; Multiply the 16-bit adder by 2 every
	STA	Adder+hibyte; time through the loop. x1,x2,x4,...,x128
	
	LDA	Mult
	BCC	whileMultNotZeroDo; branch is always taken.

.Done	
	CLD				; Turn off BCD math mode.

	LDA	Answer+hibyte; A = random # in range min to max.
	RTS				; X = min; Y = max


#10 Heaven/TQA ONLINE  

Heaven/TQA

    Quadrunner

  • 8,105 posts
  • Location:Baden-Württemberg, Germany

Posted Thu Jul 19, 2007 11:44 PM

bcd could be interesting... another approach could be using RAND(96) instead of RAND(100) which could be a good compromise

rand100: lda 53770;(0-255)
and #$1f;0-31
sta rand100b+1
lda 53770;(0-255)
and #$3f
clc
rand100b: adc #0;add rand(0-31)
rts


?

#11 Robert M OFFLINE  

Robert M

    Stargunner

  • 1,481 posts
  • Rootbeer!
  • Location:Western NY state

Posted Fri Jul 20, 2007 10:42 AM

View PostHeaven/TQA, on Thu Jul 19, 2007 11:44 PM, said:

bcd could be interesting... another approach could be using RAND(96) instead of RAND(100) which could be a good compromise

rand100: lda 53770;(0-255)
and #$1f;0-31
sta rand100b+1
lda 53770;(0-255)
and #$3f
clc
rand100b: adc #0;add rand(0-31)
rts


?

That code would produce a number between 0 and 94. The distribution would be more of a bell curve. It would be less likely to get very high and very low values. Which may be desirable.

#12 The Electric Monk OFFLINE  

The Electric Monk

    Combat Commando

  • 4 posts

Posted Fri Aug 3, 2007 11:09 AM

Is 'LDA 53770' legal in 6502 for the 2600?

All the random number algorithms I've seen before take advantage (I think) of the fact that the 2600 powers up in a random state, so the contents of any memory address can serve as a seed for an LFSR (it's called something like that) algorithm. This seems much easier if it's kosher.

Thanks,
Jason

#13 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 20,458 posts
  • Location:The land of Gorch

Posted Fri Aug 3, 2007 1:20 PM

View PostThe Electric Monk, on Fri Aug 3, 2007 9:09 AM, said:

Is 'LDA 53770' legal in 6502 for the 2600?

All the random number algorithms I've seen before take advantage (I think) of the fact that the 2600 powers up in a random state, so the contents of any memory address can serve as a seed for an LFSR (it's called something like that) algorithm. This seems much easier if it's kosher.

Thanks,
Jason
Legal, yes. It's actually address $D20A - which is a mirror for romspace. If used on the 2600, you would be reading an unchanging value (unless something other than native hardware is involved - i.e. Supercharger, etc). So it would not be applicable to this discussion.

The address is a random number generator in the Atari computer line.

Your second part is valid, so long as the 7800 isn't being used to play the game (this powers up with known values in Ram...making it possible to "autodetect" if that console is being used vs. the 2600 or emulators).

#14 The Electric Monk OFFLINE  

The Electric Monk

    Combat Commando

  • 4 posts

Posted Tue Aug 14, 2007 7:52 PM

View PostNukey Shay, on Fri Aug 3, 2007 3:20 PM, said:

View PostThe Electric Monk, on Fri Aug 3, 2007 9:09 AM, said:

Is 'LDA 53770' legal in 6502 for the 2600?

All the random number algorithms I've seen before take advantage (I think) of the fact that the 2600 powers up in a random state, so the contents of any memory address can serve as a seed for an LFSR (it's called something like that) algorithm. This seems much easier if it's kosher.

Thanks,
Jason
Legal, yes. It's actually address $D20A - which is a mirror for romspace. If used on the 2600, you would be reading an unchanging value (unless something other than native hardware is involved - i.e. Supercharger, etc). So it would not be applicable to this discussion.

The address is a random number generator in the Atari computer line.

Your second part is valid, so long as the 7800 isn't being used to play the game (this powers up with known values in Ram...making it possible to "autodetect" if that console is being used vs. the 2600 or emulators).

Belated thanks, Nukey. That makes sense.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users