assembly x86汇编-- Powerball模拟器--需要帮助正确调用宏,利用数组和简化不必要的长代码

kdfy810k  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(211)

我已经创建了一个强力球抽奖模拟,它应该检查用户选择的号码与一组随机生成的号码,并告诉用户他们是否赢得了任何东西(如下所示)。x1c 0d1x
用户是否知道强力球的号码并不重要;该程序应该对照随机生成的输入来检查用户的输入。
我试图使用宏(我必须使用),但我不断收到以下错误:

由于这是我第一次使用宏,我并不完全理解如何使用它们,所以欢迎解释如何正确地将数组作为输入(但不是必需的)。然而,如果有人能想到一种方法来大大简化我的代码,我将欣喜若狂。我的代码如下所示。

TITLE Powerball Drawing Simulation, Version 1   (PowerballDraw.asm)
; at end try to change Powerball numbers to their proper colors

; This program takes four numbers and
; checks them against a simulated Powerball
; draw.

INCLUDE Irvine32.inc
INCLUDE Macros.inc

.data
; Powerball numbers drawn
whiteBalls  DWORD 5 dup(0)  ; declare an array of 5 elements
redBall     DWORD ?         ; create a red number ball

; user numbers entered
uWtBalls DWORD 5 dup(0)     ; declare an array of 5 elements
uRedBall DWORD ?            ; create a red number ball

.code
;-------------------------------------------------------
mCheckNumbers MACRO wballs:REQ, rball:REQ
;
; Macro for checking user-selected numbers
;   against the system-generated Powerball
;   draw
; Receives: wballs, the array of user-selected
;   numbers; rballs, the red Powerball selected.
; Returns: String stating how much the user won.
;-------------------------------------------------------
.data
countWMatches   DWORD 0     ;; number of user-selected white numbers that 
                            ;;      match Powerball draw 
redMatch        DWORD ?     ;; value changes if user entry matches red ball

;; output strings (amount won)
pI      BYTE    "You have matched all 5 of the white balls and the red ball! You've won the Grand Prize!",0
pII     BYTE    "You have matched all 5 of the white balls but not the red ball. Your ticket wins $1 Million!",0
pIII    BYTE    "You have matched 4 of the white balls and the red ball. Your ticket wins $50,000!",0 
pIV     BYTE    "You have matched 4 of the white balls but not the red ball. Your ticket wins $100!",0
pV      BYTE    "You have matched 3 of the white balls and the red ball. Your ticket wins $100!",0
pVI     BYTE    "You have matched 3 of the white balls but not the red ball. Your ticket wins $7.",0
pVII    BYTE    "You have matched 2 of the white balls and the red ball. Your ticket wins $7.",0
pVIII   BYTE    "You have matched 1 of the white balls and the red ball. Your ticket wins $4.",0
pIX     BYTE    "You have matched the red ball. Your ticket wins $4.",0

;; output strings (user lost)
loseI   BYTE    "You have matched 2 of the white balls but not the red ball. You lose!",0
loseII  BYTE    "You have matched 1 of the white balls but not the red ball. You lose!",0
loseIII BYTE    "You matched absolutely nothing! You lost!",0

.code
    ;; check to see if any user selection for white match Powerball draw
    mov  edi,wballs                 ;; move wballs pointer into EDI
    mov  ecx,LENGTHOF wballs        ;; get length of wballs array
    checkWhite:
        push ecx                        ;; save outer loop count
        mov  eax,[edi]                  ;; store [EDI] in EAX for comparisons
        mov  esi,OFFSET whiteBalls      ;; move whiteBalls pointer into ESI
        mov  ecx,LENGTHOF whiteBalls    ;; get length of whiteBalls
        findMatch:
            cmp  [esi],eax              ;; compare EAX and current array value [ESI]
            jne  next                   ;; if [ESI] not equal to EAX, jump to next
            jmp  bigNext                ;; else jump to bigNext
        next:
            add  esi,4                  ;; increment, move to next memory location (whiteBalls)
            loop findMatch              ;; inner loop
    bigNext:
        pop  ecx                    ;; retrieve outer loop count
        add  countWMatches,1        ;; add 1 to countWMatches
        add  edi,4                  ;; increment, move to next memory location (wballs)
        cmp  ecx,0                  ;; compare ECX to 0
        je   quit                   ;; if ECX == 0, jump to quit
        jmp  checkWhite             ;; else jump back to checkWhite
    ;; check to see if user selection for red matches red Powerball from draw
    checkRed:
        cmp  rball,redBall          ;; compare rball and redBall
        je   markRed                ;; if rball == redBall, jump to markRed
        jmp  notEqual               ;; else jump to not equal
    markRed:
        mov  redMatch,1             ;; move 1 into redMatch
        jmp  getResults             ;; jump to getResults
    notEqual:
        mov  redMatch,0             ;; move 0 into redMatch
        jmp  getResults             ;; jump to getResults
    ;; find results for comparisons/Powerball draw
    getResults:
        cmp  countWMatches,5        ;; compare countWMatches to 5
        je   match5                 ;; if equal, jump to match5
        cmp  countWMatches,4        ;; else, compare countWMatches to 4
        je   match4                 ;; if equal, jump to match4
        cmp  countWMatches,3        ;; else, compare countWMatches to 3
        je   match3                 ;; if equal, jump to match3
        cmp  countWMatches,2        ;; else, compare countWMatches to 2
        je   match2                 ;; if equal, jump to match2
        cmp  countWMatches,1        ;; else, compare countWMatches to 1
        je   match1                 ;; if equal, jump to match1
        jmp  match0                 ;; else jump to match0
    match5:
        cmp  redMatch,1             ;; compare redMatch to 1
        je   prizeI                 ;; if equal, jump to Grand Prize (prizeI)
        jmp  prizeII                ;; else jump to $1 Million prize (prizeII)
    match4:
        cmp  redMatch,1             ;; compare redMatch to 1
        je   prizeIII               ;; if equal, jump to $50,000 prize (prizeIII)
        jmp  prizeIV                ;; else jump to first $100 prize (prizeIV)
    match3:
        cmp  redMatch,1             ;; compare redMatch to 1
        je   prizeV                 ;; if equal, jump to second $100 prize (prizeV)
        jmp  prizeVI                ;; else jump to first $7 prize (prizeVI)
    match2:
        cmp  redMatch,1             ;; compare redMatch to 1
        je   prizeVII               ;; if equal, jump to second $7 prize (prizeVII)
        jmp  LOSE1                  ;; else jump to LOSE1
    match1:
        cmp  redMatch,1             ;; compare redMatch to 1
        je   prizeVIII              ;; if equal, jump to first $4 prize (prizeVIII)
        jmp  LOSE2                  ;; else jump to LOSE2
    match0:
        cmp  redMatch,1             ;; compare redMatch to 1
        je   prizeIX                ;; if equal, jump to second $4 prize (prizeIX)
        jmp  LOSE3                  ;; else jump to LOSE3
    ;; display results for Powerball draw (winner)
    prizeI:
        ;; Grand Prize
        mov  edx,OFFSET pI          ;; move pI string into EDX
        call WriteString            ;; display pI string
        jmp  quit                   ;; jump to quit
    prizeII:    
        ;; $1 Million
        mov  edx,OFFSET pII         ;; move pII string into EDX
        call WriteString            ;; display pII string
        jmp  quit                   ;; jump to quit
    prizeIII:
        ;; $50,000
        mov  edx,OFFSET pIII        ;; move pIII string into EDX
        call WriteString            ;; display pIII string
        jmp  quit                   ;; jump to quit
    prizeIV:
        ;; $100
        mov  edx,OFFSET pIV         ;; move pIV string into EDX
        call WriteString            ;; display pIV string
        jmp quit                    ;; jump to quit
    prizeV:
        ;; $100
        mov  edx,OFFSET pV          ;; move pV string into EDX
        call WriteString            ;; display pV string
        jmp  quit                   ;; jump to quit
    prizeVI:
        ;; $7
        mov  edx,OFFSET pVI         ;; move pVI string into EDX
        call WriteString            ;; display pVI string
        jmp  quit                   ;; jump to quit
    prizeVII:
        ;; $7
        mov  edx,OFFSET pVII        ;; move pVII string into EDX
        call WriteString            ;; display pVII string
        jmp  quit                   ;; jump to quit
    prizeVIII:
        ;; $4
        mov  edx,OFFSET pVIII       ;; move pVIII string into EDX
        call WriteString            ;; display pVIII string
        jmp  quit                   ;; jump to quit
    prizeIX:
        ;; $4
        mov  edx,OFFSET pIX         ;; move pIX string into EDX
        call WriteString            ;; display pIX string
        jmp  quit                   ;; jump to quit
    ;; display results for Powerball draw (loser!)
    LOSE1:
        mov  edx,OFFSET loseI       ;; move loseI string into EDX
        call WriteString            ;; display loseI string
        jmp  quit                   ;; jump to quit
    LOSE2:
        mov  edx,OFFSET loseII      ;; move loseII string into EDX
        call WriteString            ;; display loseII string
        jmp  quit                   ;; jump to quit
    LOSE3:
        mov  edx,OFFSET loseIII     ;; move loseIII string into EDX
        call WriteString            ;; display loseIII string
        jmp  quit                   ;; jump to quit
    quit:
        call Crlf                   ;; jump to next line
        ret
ENDM

; main procedure
main PROC
    ; begin by filling Powerball draw with random numbers
    call drawNewPowerball   ; draw new set of Powerball numbers and populate 
                            ;   whiteBalls Powerball array + get value for red
                            ;   Powerball
    call Crlf               ; jump to next line
    call newUserEntry       ; have user enter their choice of Powerball values
    call Crlf               ; jump to next line
    call Crlf               ; jump to next line
    mCheckNumbers OFFSET uWtBalls,uRedBall  
                            ; check user-selected numbers against 
                            ;   Powerball draw
    exit                    ; exit program
main ENDP
;-------------------------------------------------------
drawNewPowerball PROC
;
; Procedure for resetting and redrawing
;   Powerball numbers.
; Receives: nothing
; Returns: nothing
;-------------------------------------------------------
.data
drawingResultsWt    BYTE    "Powerball drawing results: White balls ",0
adsp                BYTE    " ",0
drawingResultRed    BYTE    ", Red ball ",0

.code
    ; redraw red Powerball value
    mov  eax,26                     ; range of 0 to 25 for RandomRange
    call RandomRange                ; get random number between 0 and 25
    add  eax,1                      ; add 1 to result
    mov  redBall,eax                ; move EAX into redBall
    ; prepare to replace values in whiteBalls array
    mov  edi,OFFSET whiteBalls      ; move whiteBalls pointer into EDI
    mov  ecx,5                      ; length of whiteBalls array
    ; redraw all white Powerball values
    redraw:
        mov  eax,69                     ; range of 0 to 68 for RandomRange
        call RandomRange                ; get random number between 0 and 68
        add  eax,1                      ; add 1 to result
        mov  [edi],eax                  ; move EAX into whiteBalls array
        add  edi,4                      ; increment, move to next memory location   
    ; check to see if there are any duplicate values
    mov  edi,OFFSET whiteBalls+4    ; move second array location into EDI
    mov  ecx,4                      ; length of whiteBalls array-1
    check:
        mov  ebx,[edi-4]                ; move [EDI-4] into EBX
        cmp  ebx,[edi]                  ; check to see if EBX and [EDI] 
                                        ;   are equal
        je   rd2                        ; EBX is equal to [EDI], replace
                                        ;   selected value
        jmp  next                       ; else go to next position
    rd2:
        add  ecx,1                      ; add 1 to ECX
        mov  eax,69                     ; range of 0 to 68 for RandomRange
        call RandomRange                ; get random number between 0 and 68
        add  eax,1                      ; add 1 to result
        mov  [edi],eax                  ; replace value stored at current
                                        ;   pointer location with EAX
        jmp  check                      ; return to check
    next:
        add  edi,4                      ; add 4 to EDI to move to next location
                                        ;   in the array
        jmp  check                      ; return to check
    quit:
        ; show Powerball drawing results
        mov  edx,OFFSET drawingResultsWt
        call WriteString            ; display drawingResultsWt string
        mov  edi,OFFSET whiteBalls  ; move whiteBalls pointer back into EDI
        mov  ecx,4
        wB:
            mov  eax,[edi]              ; move current value into EAX
            call WriteInt               ; display value
            mov  edx,OFFSET adsp
            call WriteString            ; display space after number
            add  edi,4                  ; increment, move to next memory location
        mov  edi,OFFSET whiteBalls  ; move whiteBalls pointer back into EDI
        mov  eax,[edi+16]           ; get value at end of whiteBalls
        call WriteInt               ; display value
        mov  edx,OFFSET drawingResultRed
        call WriteString            ; display drawingResultRed string
        mov  eax,redBall
        call WriteInt               ; display redBall value
        call Crlf                   ; jump to next line
        ret
drawNewPowerball ENDP
;-------------------------------------------------------
newUserEntry PROC
;
; Procedure for user selecting a new set 
;   of Powerball numbers.
; Receives: user input
; Returns: nothing
;-------------------------------------------------------
.data
firstNumber     BYTE    "Please enter your first white number: ",0
secondNumber    BYTE    "Please enter your second white number: ",0
thirdNumber     BYTE    "Please enter your third white number: ",0
fourthNumber    BYTE    "Please enter your fourth white number: ",0
fifthNumber     BYTE    "Please enter your fifth white number: ",0
redNumber       BYTE    "Please enter your red number: ",0

.code
    mov  edi,OFFSET uWtBalls        ; move uWtBalls pointer into EDI
    uno:
        mov  edx,OFFSET firstNumber     ; move firstNumber string into EDX
        call WriteString                ; display firstNumber
        call ReadInt                    ; read in the number the user entered
                                        ;   and store it in EAX
        cmp  eax,0                      ; compare EAX to 0
        je   uno                        ; if EAX is equal to zero, return to 
                                        ;   beginning of loop
        cmp  eax,69                     ; compare EAX to 69
        ja   uno                        ; if EAX is greater than 69, return to
                                        ;   beginning of loop
        mov  [edi],eax                  ; store EAX at pointer location
        add  edi,4                      ; go to the next pointer location
    dos:
        mov  edx,OFFSET secondNumber    ; move secondNumber string into EDX
        call WriteString                ; display secondNumber
        call ReadInt                    ; read in the number the user entered
                                        ;   and store it in EAX
        cmp  eax,0                      ; compare EAX to 0
        je   dos                        ; if EAX is equal to zero, return to 
                                        ;   beginning of loop
        cmp  eax,69                     ; compare EAX to 69
        ja   dos                        ; if EAX is greater than 69, return to
                                        ;   beginning of loop
        mov  [edi],eax                  ; store EAX at pointer location
        mov  ebx,[edi-4]                ; copy previous pointer location into EBX
        cmp  ebx,[edi]                  ; compare EBX and [EDI]
        je   dos                        ; if EBX == [EDI] repeat dos loop
        jmp  tres                       ; else proceed to tres loop
    tres:
        add  edi,4                      ; go to next pointer location
        mov  edx,OFFSET thirdNumber     ; move thirdNumber string into EDX 
        call WriteString                ; display thirdNumber string
        call ReadInt                    ; read in the number the user entered
                                        ;   and store it in EAX
        cmp  eax,0                      ; compare EAX to 0
        je   tres                       ; if EAX is equal to zero, return to 
                                        ;   beginning of loop
        cmp  eax,69                     ; compare EAX to 69
        ja   tres                       ; if EAX is greater than 69, return to
                                        ;   beginning of loop
        mov  [edi],eax                  ; store EAX at pointer location
        mov  ebx,[edi-4]                ; copy previous pointer location into EBX
        cmp  ebx,[edi]                  ; compare EBX and [EDI]
        je   tres                       ; if EBX == [EDI] repeat tres loop
        jmp  cuatro                     ; else proceed to cuatro loop
    cuatro:
        add  edi,4                      ; go to next pointer location
        mov  edx,OFFSET fourthNumber    ; move fourthNumber string into EDX
        call WriteString                ; display fourthNumber string
        call ReadInt                    ; read in the number the user entered
                                        ;   and store it in EAX
        cmp  eax,0                      ; compare EAX to 0
        je   cuatro                     ; if EAX is equal to zero, return to 
                                        ;   beginning of loop
        cmp  eax,69                     ; compare EAX to 69
        ja   cuatro                     ; if EAX is greater than 69, return to
                                        ;   beginning of loop
        mov  [edi],eax                  ; store EAX at pointer location
        mov  ebx,[edi-4]                ; copy previous pointer location into EBX
        cmp  ebx,[edi]                  ; compare EBX and [EDI]
        je   cuatro                     ; if EBX == [EDI] repeat cuatro loop
        jmp  cinco                      ; else proceed to cinco loop
    cinco:
        add  edi,4                      ; go to next pointer location
        mov  edx,OFFSET fifthNumber     ; move fifthNumber string into EDX
        call WriteString                ; display fifthNumber string
        call ReadInt                    ; read in the number the user entered
                                        ;   and store it in EAX
        cmp  eax,0                      ; compare EAX to 0
        je   cinco                      ; if EAX is equal to zero, return to 
                                        ;   beginning of loop
        cmp  eax,69                     ; compare EAX to 69
        ja   cinco                      ; if EAX is greater than 69, return to
                                        ;   beginning of loop
        mov  [edi],eax                  ; store EAX at pointer location
        mov  ebx,[edi-4]                ; copy previous pointer location into EBX
        cmp  ebx,[edi]                  ; compare EBX and [EDI]
        je   cinco                      ; if EBX == [EDI] repeat loop
        jmp  quit                       ; else continue to quit loop
    quit:
        mov  edx,OFFSET redNumber       ; move redNumber string into EDX
        call WriteString                ; display redNumber string
        call ReadInt                    ; read in the number the user entered
                                        ;   and store it in EAX
        cmp  eax,0                      ; compare EAX to 0
        je   quit                       ; if EAX is equal to zero, return to
                                        ;   beginning of loop
        cmp  eax,26                     ; compare EAX to 26
        ja   quit                       ; if EAX is greater than 26, return to 
                                        ;   beginning of loop
        mov  uRedBall,eax               ; else move EAX into uRedBall
        ret
newUserEntry ENDP
END main
pu3pd22g

pu3pd22g1#

消息1

通过调用宏mCheckNumbers MACRO wballs:REQ, rball:REQmCheckNumbers OFFSET uWtBalls,uRedBall,对行cmp rball,redball中的 * rball * 进行参数替换将产生以下行:

cmp uRedBall, redBall

这是一条不可编码的指令,因为两个操作数都引用内存。您收到了有关此指令的"invalid instruction operand"(无效指令操作数)错误。

checkRed:
    mov  redMatch, 0
    mov  eax, rball
    cmp  eax, redBall
    jne  getResults       ; notEqual
    mov  redMatch, 1
getResults:

为了消除大量的跳跃,我将 * redMatch * 变量预加载为零。如果数字不匹配,我将直接分支到 * getResults *。

消息2

通过调用宏mCheckNumbers MACRO wballs:REQ, rball:REQmCheckNumbers OFFSET uWtBalls,uRedBall,对行mov ecx,LENGTHOF wballs中的 * wballs * 进行参数替换将产生以下行

mov  ecx,LENGTHOF OFFSET uWtBalls

此操作数没有意义!您收到了"表达式中的语法错误"错误。
将宏调用更改为:

mCheckNumbers uWtBalls, uRedBall

和宏本身中的代码转换为:

mov  edi, OFFSET wballs
mov  ecx, LENGTHOF wballs

checkout 这些逻辑错误

  • 您的 * checkWhite * 嵌套循环将始终递增 * countWMatches * 变量,因为您要么跳转到 * bigNext *(在真正匹配的情况下),要么进入 * bigNext *(在没有匹配的情况下)。
    • checkWhite * 中的外部循环将无限运行,因为您从不递减ECX计数器!

因为这些数组很短,所以在匹配的情况下提前退出并不重要,而且因为不存在重复的数字,所以不存在对 * countWMatches * 变量进行多次递增的风险。
我建议在下一个嵌套循环中使用不同的寄存器作为计数器:

mov  edi, OFFSET wballs
    mov  edx, LENGTHOF wballs
checkWhite:
    mov  esi, OFFSET whiteBalls
    mov  ecx, LENGTHOF whiteBalls
findMatch:
    lodsd
    cmp  eax, [edi]
    jne  next
    add  countWMatches, 1
next:
    dec  ecx
    jnz  findMatch
    add  edi, 4
    dec  edx
    jnz  checkWhite
checkRed:

为什么这部分代码有一个条件跳转到 * quit *?难道你不想显示 * loseIII * 消息"你完全没有匹配!你输了!"
但是,如果有人能想出一种方法来大大简化我的代码,我会欣喜若狂。
一旦你的程序开始运行,你可以在the CodeReview forum上提交它以供审查。我相信它将有可能比我今天写的更简单。

相关问题