1

How to make a function that generates a random number between 0 and 80? I am trying to make a game with asteroids in assembly 8086.

I tried this code but it generates too small numbers...

 _RAND:
    mov ah,2Ch
    int 21h
    mov ax,dx
    mov ax,0Fh
    mov al,dl
    cmp al,80d
    jg _RAND

It gave me a number between 1 and 8 or something like that. It's random, but too small number for the X position of my asteroids.

  • are you using EMU8086 or are you using DOS? Either way this other question may be of benefit: https://stackoverflow.com/questions/47607104/random-number-in-assembly .It may even be a duplicate. – Michael Petch May 01 '19 at 20:57
  • In that other answer you'd change `mov bx,10` to `mov bx,80`. It should yield a number between 1 and 80 (including 80). If you want a number between 0 and 79 (including 79) then you remove the `inc` instruction as well. – Michael Petch May 01 '19 at 21:00
  • Is 80 included in the range, for a total of 81 numbers, 0 through 80 inclusive, or is it 80 numbers 0 through 79 inclusive? – rcgldr May 02 '19 at 04:44

1 Answers1

0

If you need to generate a lot of random values in a very short period of time you may consider using this:

; Description  : get RND between any bl and bh includs (max 0 -255)
; Input        : 1. Bl = min (from 0) , BH , Max (till 255)
;                2. RndCurrentPos a  word variable,   help to get good rnd number
;                   Declre it at DATASEG :  RndCurrentPos dw ,0
;                3. EndOfCsLbl: is label at the end of the program one line above END start     
; Output:        Al - rnd num from bl to bh  (example 50 - 150)
; More Info:
;   Bl must be less than Bh 
;   in order to get good random value again and agin the Code segment size should be 
;   at least the number of times the procedure called at the same second ... 
;   for example - if you call to this proc 50 times at the same second  - 
;   Make sure the cs size is 50 bytes or more 
;   (if not, make it to be more) 
proc RandomByCs
    push es
    push si
    push di

    mov ax, 40h
    mov es, ax

    sub bh,bl  ; we will make rnd number between 0 to the delta between bl and bh
               ; Now bh holds only the delta
    cmp bh,0
    jz @@ExitP

    mov di, [word RndCurrentPos]
    call MakeMask ; will put in si the right mask according the delta (bh) (example for 28 will put 31)

RandLoop: ;  generate random number 
    mov ax, [es:06ch] ; read timer counter
    mov ah, [byte cs:di] ; read one byte from memory (from semi random byte at cs)
    xor al, ah ; xor memory and counter

    ; Now inc di in order to get a different number next time
    inc di
    cmp di,(EndOfCsLbl - start - 1)
    jb @@Continue
    mov di, offset start
@@Continue:
    mov [word RndCurrentPos], di

    and ax, si ; filter result between 0 and si (the nask)
    cmp al,bh    ;do again if  above the delta
    ja RandLoop

    add al,bl  ; add the lower limit to the rnd num

@@ExitP:    
    pop di
    pop si
    pop es
    ret
endp RandomByCs

Note, if your codeseg isn't long enough try adding this in the codeseg:

    ; put some data in Code segment in order to have enough bytes to xor with 
    SomeRNDData     db 227  ,111    ,105    ,1      ,127
                    db 234  ,6      ,116    ,101    ,220
                    db 92   ,60     ,21     ,228    ,22
                    db 222  ,63     ,216    ,208    ,146
                    db 60   ,172    ,60     ,80     ,30
                    db 23   ,85     ,67     ,157    ,131
                    db 120  ,111    ,105    ,49     ,107
                    db 148  ,15     ,141    ,32     ,225
                    db 113  ,163    ,174    ,23     ,19
                    db 143  ,28     ,234    ,56     ,74
                    db 223  ,88     ,214    ,122    ,138
                    db 100  ,214    ,161    ,41     ,230
                    db 8    ,93     ,125    ,132    ,129
                    db 175  ,235    ,228    ,6      ,226
                    db 202  ,223    ,2      ,6      ,143
                    db 8    ,147    ,214    ,39     ,88
                    db 130  ,253    ,106    ,153    ,147
                    db 73   ,140    ,251    ,32     ,59
                    db 92   ,224    ,138    ,118    ,200
                    db 244  ,4      ,45     ,181    ,62

Shachaf Zohar
  • 165
  • 1
  • 13
  • This could perform very badly if you ask for a small range, like `0..2`. It could take a long time before it finds a code byte that happens to XOR with the current time to make a number in that range. (At least mask with a power of 2 or something before discarding a candidates and retrying). Also this has a large chance of not actually being very random; bytes in x86 machine code are far from uniformly distributed. And current time only increments 1 at a time. – Peter Cordes May 03 '19 at 01:17
  • This might be barely random enough and smallish code-size for some use-cases, but if you need to pad your code section with extra random bytes then it would make more sense to implement something much better like xorshift+, maybe with small shift counts to reduce cost of shifting across word boundaries. (https://en.wikipedia.org/wiki/Xorshift). https://en.wikipedia.org/wiki/Linear-feedback_shift_register shows a `uint16_t` example that could be implemented efficiently (e.g. with a rotate right + AND to emulate `var<<15` which is slow on real 8086.) – Peter Cordes May 03 '19 at 01:33