Jump to content
IGNORED

Random in ranges


Heaven/TQA

Recommended Posts

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
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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).

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

 

 

?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 2 weeks later...

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

Link to comment
Share on other sites

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).

Link to comment
Share on other sites

  • 2 weeks later...
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.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...