
; Win32 386+ Random-Number-In-Range Generator.
;
; Most Win32 random number generators I've come across so far were
; actually rather predictable, so here goes my attempt to code a
; truely random one. It's small, simple and reasonably fast.
;

                .386
                .MODEL  FLAT

EXTRN           GetTickCount:PROC
EXTRN           ExitProcess:PROC

                .DATA

Random_Seed     DD      0

                .CODE
START:
                CALL    GetTickCount            ; Initialize random seed.
                MOV     Random_Seed, EAX        ; This can be anything.

                MOV     EAX, 10                 ; Returns a random value
                CALL    Random_EAX              ; between 0 and 9.

                PUSH    0
                CALL    ExitProcess

;  Entry: EAX == Max_Val.
; Return: EAX == Random number between 0..Max_Val-1.
Random_EAX:
                PUSH    ECX                     ; Save registers that get
                PUSH    EDX                     ; changed.

                PUSH    EAX                     ; Save Max_Val.

                CALL    GetTickCount            ; Get random value.

                MOV     ECX, Random_Seed        ; Get random seed.

                ADD     EAX, ECX                ; Adjust random value with
                                                ; random seed.

                ROL     ECX, 1                  ; Adjust random seed.
                ADD     ECX, 666h

                MOV     Random_Seed, ECX

                ; Perform CRC-32 on semi-random number
                ; to obtain a truely random number.

                PUSH    32
                POP     ECX

CRC_Bit:        SHR     EAX, 1                  ; Bit is set?
                JNC     Loop_CRC_Bit

                XOR     EAX, 0EDB88320h

Loop_CRC_Bit:   LOOP    CRC_Bit                 ; Do all 32 bits.

                POP     ECX                     ; ECX = Max_Val.

                XOR     EDX, EDX                ; Divide truely random value
                DIV     ECX                     ; by Max_Val.

                XCHG    EDX, EAX                ; Remainder is the
                                                ; random-in-range number.

                OR      EAX, EAX                ; Test for zero.

                POP     EDX
                POP     ECX

                RETN

                END     START
