Improving doGetRandomNumber

TakuikaNinja

Active member
Either way, an important part of using RNG is to seed it properly. Getting an unpredictable non-zero (most LSFRs cycle when encountering a zero) value is a must.
A good example: using the number of frames before the player pressed start at the title screen
 
Last edited:

TakuikaNinja

Active member
Here is an alternate version which uses the unused randomSeed variable (identical to vBlankTimer) and an extra table.
This is based on the indexing suggestion in the same article. One benefit of this version is that the RNG sequence changes every frame (modulo 16).
Code:
doGetRandomNumber:
        tya ; backup Y
        pha
        lda randomSeed ; unused zp variable, incremented once every NMI
        and #$0F ; mask to lower 4-bits
        tay
        lda randomSeed1 ; actual seed
        beq +doEor
        asl
        beq +noEor
        bcc +noEor
+doEor: eor eorTable,y
+noEor: sta randomSeed1
        pla ; restore Y
        tay
        lda randomSeed1 ; reload result into A
        rts
eorTable:
        .db #$1D, #$2B, #$2D, #$4D, #$5F, #$63, #$65, #$69
        .db #$71, #$87, #$8D, #$A9, #$C3, #$CF, #$E7, #$F5
 
Last edited:

TheNew8bitHeroes

New member
All of these are cool, relevant ways to do it. The original just clobbers the hell out of it in all sorts of ways on purpose. Different modules have utilized these seeds differently depending on the use of random since the 3.x beta to now, so there are likely some holdovers in RAM for a few things that don't get used, or that are placeholders in case someone wants to make use of them (as in this case). In older builds, every input to the gamepad warped the seed in some way. With this, the current state of gamepad and a few registers that will be wildly different at any given time and the current frame counter are all factored in mutating the seed. Might be overkill, but...*shrugs*.

Thanks for lending sleeker ways to do this for those that want something cleaner. :)
 

TakuikaNinja

Active member
Uh, here's an update, I guess. There was a discussion about RNG routines in the NESdev community a while ago, and foobles came up with an improvement to the first routine I shared here. This version avoids a "multiply by 2" pattern seen with values below 128 and is also smaller/faster:

Code:
doGetRandomNumber:
    LDA randomSeed1
    ASL
    BCS +
    EOR #$9e
+
    ADC #$81
    STA randomSeed1
    RTS
 
Top Bottom