[tutoré] loto et nombres pseudo-aléatoires [masm]

Description

Comme l'apprentissage passe par la démonstration, voici un petit exemple très simple : le LOTO.

L'idée du programme est double :
1) prendre une console, générer un tirage et vérifier un algorithme de génération aléatoire
2) expliquer la structure d'un fichier .ASM

Le programme fonctionne avec MASM32 sur un 586. Vous trouverez les versions :
- Pascal de haut niveau (version de "base")
- ASM décommentée
- ASM avec ses nombreux commentaires

L'algorithme RANDOM est tiré de Pascal/Delphi. Mais comme je l'ai retouché pour le faire sortir dans DL, la version Pascal qui sort dans AL se retrouve légèrement plus lente que le programme ASM. Mais le code est déjà très compact et il est très difficile d'accélérer plus.

Bref, tout commentaire est bienvenu... J'espère juste de ne pas avoir dit de bêtises.

Source / Exemple :


; Console Assemble & Link

    .586
    .model flat, stdcall
    option casemap :none
    include \masm32\include\windows.inc
    include \masm32\macros\macros.asm
    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib

.data

    DMaxInt         EQU     49d
    SCrLf           EQU     13,10
    SDoubleLine     DB      SCrLf,SCrLf,0
    SHeader         DB      "-------------------------------------------------------------------------",SCrLf,          \
                            "                     ::  Application Loto MAsm32  ::",SCrLf,                               \
                            "-------------------------------------------------------------------------",SCrLf,SCrLf,0
    SMenuItem       DB      "       1: G?n?rer un tirage du loto",SCrLf,SCrLf,          \
                            "       2: V?rifier l'homor?partition",SCrLf,SCrLf,         \
                            "       3: Quitter",SCrLf,                                  \
                            SCrLf,SCrLf,0
    SSpace          DB      " ",0
    SRandomize      EQU     "M?thode de randomisation :",SCrLf,SCrLf,                   \
                            "   1) TickCount Windows    - D?faut",SCrLf,                \
                            "   2) Processeur           - Pentium (x586)",SCrLf,        \
                            "   3) Horloge syst?me",SCrLf,SCrLf,  \
                            "> ",0
    SSelectItem     EQU     "Votre choix :  ",0
    SIteration      EQU     "Nombre de balles ? tirer : ",0
    SMaskResult     DB      "     %d -> %d",SCrLf,0
    SMaskStats      DB      SCrLf,SCrLf,                                    \
                            "  Valeur minimale : %d",SCrLf,                 \
                            "  Valeur maximale : %d",SCrLf,                 \
                            "  Delta           : %d",SCrLf,                 \
                            "  Temps requis    : %d ms",SCrLf,SCrLf,0

.data?

    RandBase        DD      ?
    BRet            DB      ?
    AAllDrawn       DB      7       dup(?)
    ACountDraws     DD      49      dup(?)
    DTiming         DD      ?
    SOutput         DB      255     dup(?)
    DMinVal         DD      ?
    DMaxVal         DD      ?

.code

        Randomize proc
            LOCAL   RSysTime:SYSTEMTIME
            .IF AL == 2d
                RDTSC
            .ELSEIF AL == 3d
                invoke  GetSystemTime, ADDR RSysTime
                MOVZX   EAX, Word PTR RSysTime.wHour
                IMUL    EAX,60
                ADD     AX, Word PTR RSysTime.wMinute
                IMUL    EAX, 60
                MOVZX   EDX, Word PTR RSysTime.wSecond
                ADD     EAX, EDX
                IMUL    EAX, 1000
                MOV     DX, Word PTR RSysTime.wMilliseconds
                ADD     EAX, EDX
            .ELSE
                CALL    GetTickCount
            .ENDIF
            MOV     RandBase, EAX
            RET
        Randomize endp

        DisplayHeader proc
            cls
            invoke  StdOut, ADDR SHeader
            RET
        DisplayHeader endp

        Menu proc
          @@:
            CALL DisplayHeader
            invoke  StdOut, ADDR SMenuItem
            MOV     EAX, sval(input(SSelectItem))
            .IF EAX == 1d
                CALL    DrawLoto
                JMP     @B
            .ELSEIF EAX == 2d
                CALL    CheckLoto
                JMP     @B
            .ELSEIF EAX != 3d
                JMP     @B
            .ENDIF
            RET
        Menu endp

        IsAlreadyDrawn proc uses ECX EBX
            AND     BRet, 0b
          @SiDebut:
            MOV     AL, Byte PTR [EBX]
            CMP     AL, DL
            JNE     @F
            OR      BRet, 1b
            JMP     @SiFin
          @@:
            CMP     CL, 00h
            JE      @SiFin
            DEC     CL
            DEC     EBX
            JMP     @SiDebut
          @SiFin:
            RET
        IsAlreadyDrawn endp

        DrawLoto proc uses EBX
            LOCAL   DBoucle:DWord
            invoke  StdOut,ADDR SDoubleLine
            LEA     EBX, AAllDrawn
            XOR     ECX, ECX
          @@:
            CALL    Random
            CALL    IsAlreadyDrawn
            CMP     BRet, 1b
            JE      @B
            MOV     Byte PTR [EBX], DL
            INC     EBX
            INC     ECX
            CMP     ECX, 7d
            JNE     @B
            MOV     DBoucle, 1d
            LEA     EBX, AAllDrawn
          @@:
            MOVZX   EAX, Byte PTR [EBX]
            INC     EAX
            invoke  wsprintf, ADDR SOutput, ADDR SMaskResult, DBoucle, EAX
            invoke  StdOut, ADDR SOutput
            INC     EBX
            INC     DBoucle
            CMP     DBoucle, 7d
            JBE     @B
            MOV     EAX, input(0)
            RET
        DrawLoto endp

        Random proc
            MOV     EAX, DMaxInt
            IMUL    EDX, RandBase, 08088405h
            INC     EDX
            MOV     RandBase, EDX
            MUL     EDX
            RET
        Random endp

        CheckLoto proc uses EBX
            LOCAL   Index:DWord
            LOCAL   DNumber:DWord
            invoke  StdOut,ADDR SDoubleLine
            LEA     EBX, ACountDraws
            MOV     ECX, DMaxInt
          @@:
            AND     DWord PTR [EBX+4*ECX-4], 00h
            DEC     ECX
            JNZ     @B
            MOV     ECX, sval(input(SIteration))
            CALL    GetTickCount
            MOV     DTiming, EAX
          @@:
            CALL    Random
            INC     DWord PTR [EBX+4*EDX]
            DEC     ECX
            JNE     @B
            CALL    GetTickCount
            SUB     EAX, DTiming
            MOV     DTiming, EAX
            OR      DMinVal, 0FFFFFFFFh
            AND     DMaxVal, 00h
            invoke  StdOut,ADDR SDoubleLine
            AND     Index, 00h
          @Draw:
            MOV     ECX, Index
            MOV     EAX, DWord PTR [EBX+4*ECX]
            MOV     DNumber, EAX
            CMP     EAX, DMinVal
            JNB     @F
            MOV     DMinVal, EAX
          @@:
            CMP     EAX, DMaxVal
            JNA     @F
            MOV     DMaxVal, EAX
          @@:
            INC     Index
            CMP     Index, 10d
            JNB     @F
            invoke  StdOut, ADDR SSpace
          @@:
            invoke  wsprintf, ADDR SOutput, ADDR SMaskResult, Index, DNumber
            invoke  StdOut, ADDR SOutput
            CMP     Index, DMaxInt
            JNE     @Draw
            MOV     EAX, DMaxVal
            SUB     EAX, DMinVal
            invoke  wsprintf, ADDR SOutput, ADDR SMaskStats, DMinVal, DMaxVal, EAX, DTiming
            invoke  StdOut, ADDR SOutput
            MOV     EAX, input(0)
            RET
        CheckLoto endp

start:

  @@:
    CALL    DisplayHeader
    MOV     EAX, sval(input(SRandomize))
    DEC     EAX
    CMP     EAX, 3d
    JAE     @B
    INC     EAX
    CALL    Randomize
    CALL    Menu

exit
end start

Conclusion :


Vous pouvez toujours aller visiter http://altert.family.free.fr/

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.