Irvine's RandomRange
returns a number of a range of numbers. Therefore, it needs the range as argument in EAX. Consider, that EAX must not be zero, otherwise you'll get a "division by zero" exception. Also, the program lacks of an exit
.
RandomRange
calls Irvine's Random32
which algorithm is almost the same as that of the rand()
function in Microsoft's C runtime library (MSVCRT.DLL). It produces a number based on another number (called "seed") which will become the new seed. If you don't initialize the first seed, you will always get the same sequence of numbers. Initialize it once with Irvine's Randomize
.
RandomRange
uses a simple modulo function to separate a number of the range: N = rand() % EAX
. If the range of Random32
(0..0xFFFFFFFF) cannot evenly splitted into parts of the wished range (0..EAX-1), you get some numbers more frequently than others. A formula for a better distribution of the numbers:
(rand() / (RAND_MAX+1) * EAX
=> (rand() * EAX) / (RAND_MAX+1) ; RAND_MAX is 0xFFFFFFFF (according to Irvine)
This can be easily programmed in assembly:
myRandomRange PROC USES EBX EDX
mov ebx,eax ; maximum value
call Random32 ; eax = random number
mul ebx ; rand() * EAX => EDX:EAX
mov eax, edx ; SHL EDX:EAX,32 = Divide EDX:EAX by 0x100000000 (RAND_MAX+1)
ret
myRandomRange ENDP
The whole bunch:
TITLE Program Template (template.asm)
INCLUDE Irvine32.inc
.DATA
onezero BYTE 36 DUP(0)
row BYTE 0
col BYTE 0
.CODE
myRandomRange PROC USES EBX EDX
mov ebx,eax ; maximum value
call Random32 ; eax = random number
mul ebx ; rand() * EAX => EDX:EAX
mov eax, edx ; SHL EDX:EAX,32 = Divide EDX:EAX by 0x100000000 (RAND_MAX+1)
ret
myRandomRange ENDP
main PROC
call Randomize
_again:
mov eax, 6
call myRandomRange
; mov bx, 6
; div bx
; mov row, dl
mov row, al
mov eax, 6
call myRandomRange
; div bx
mov col, al
movzx eax, row
mov ebx, 6
mul ebx
movzx ecx, col
add eax, ecx
mov edi, eax
mov al, 1
cmp al, onezero[edi]
je _again
movzx eax, row
call writeint
movzx eax, col
call writeint
exit
main ENDP
END main