【问题标题】:x86 Irvine Assembly jmp + cmp and conditional loops - craps gamex86 Irvine Assembly jmp + cmp 和条件循环 - 掷骰子游戏
【发布时间】:2019-04-12 13:31:16
【问题描述】:

Assembly 是一门有趣的学习语言。我还有很大的进步空间。我正在尝试制作一个简单的掷骰子游戏,该游戏应该根据用户输入随机掷骰子 x 次。我的代码如下:

TITLE Program Template          (main.asm)

INCLUDE Irvine32.inc

.data
diceOne                     DWORD ? 
diceTwo                     DWORD ?
win                         DWORD 7, 11
lose                        DWORD 2, 3, 12
mark                        DWORD 4, 5, 6, 8, 9, 10
markCounter                 DWORD ?
userInput                   BYTE 'Enter integer: ', 0
numRolls                    DWORD ?
printWon                    BYTE 'Won: ', 0
wonCounter                  DWORD ?
printWin                    BYTE ' You win!', 0
printLost                   BYTE 'Lost: ', 0
lostCounter                 DWORD ?
printLose                   BYTE ' You lose!', 0
printTotal                  BYTE 'Total: ', 0
space                       DWORD ' ', 0
printPlus                   BYTE ' + ', 0
printMark                   BYTE ' Mark ', 0

.code
main PROC
    call randomize                      ; set random seed
    mov ecx, 6                          ; counter set to 6
    mov edx, offset userInput           ; print string
    call writeString
    call readInt                        ; read input
    mov numRolls, eax                   ; store input in variable
    mov ecx, numRolls                   
    mov eax, 0
    mov edi, offset win

    call gamesRolled

    exit
main ENDP
;number of games rolled based on user input
gamesRolled PROC uses eax ecx

DICEROLLS: 
    call crlf
                                ;diceOne roll
    mov eax, 5                  ;move value into eax to pass as parameter for randomrange
    call randomRange            ;randomrange stored in eax 0-5
    inc eax
    mov diceOne, eax            ;mov the value of randomrange into variable
    call writeDec       
    push edx                    ;push edx off stack to print space 
    mov edx, OFFSET printPlus
    call writeString
    pop edx
                                ;diceTwo roll
    mov eax, 6
    call randomRange
    inc eax
    mov diceTwo, eax
    call writeDec


    add eax, diceOne            ; add diceOne roll to diceTwo roll
    cmp eax, win                ; comp eax value to win
    je wins
    cmp eax, lose
    je losses
    cmp eax, mark
    je marks
    LOOP DICEROLLS

    ret
gamesRolled ENDP

wins PROC uses edi ecx
    mov edi, offset win
    mov ecx, lengthof win
    cmp eax, [edi]
    add edi, type win
    push edx
    mov edx, offset printWin
    call writeString
    pop edx
    jmp gamesRolled
    ret

wins ENDP

losses PROC uses edi ecx
    mov edi, offset lose
    mov ecx, lengthof lose
    cmp eax, [edi]
    add edi, type lose
    push edx
    mov edx, offset printLose
    call writeString
    pop edx
    jmp gamesRolled
    ret
losses ENDP

marks PROC uses edi ecx
    mov edi, offset lose
    mov ecx, lengthof lose
    cmp eax, [edi]
    add edi, type lose

    push edx
    mov edx, offset printMark
    call writeString    
    pop edx
    jmp gamesRolled
    ret
marks ENDP

END main

所以从我看到的例子和解释来看,这似乎很简单。我正在使用cmp/je 在循环掷骰子时像 if 语句一样工作。这个想法是增加胜负或分数并将其全部打印出来。如果没有 cmp/je 部分,它可以正常工作。我可以打印随机骰子,但是,一旦我开始尝试cmp/je,我会遇到一些奇怪的冻结,有时甚至会崩溃。我正在尝试学习如何在汇编中更好地编码。请您帮助我理解为什么这不能按我认为的方式工作。我想如果我比较包含diceOne + diceTwo 的组合总数的eax 寄存器,它应该跳转到其他函数,并且在这些函数中edi 应该像一个计数器,在打印表示获胜的字符串时进行计数,丢失或标记。比如:

Enter integer: 5
2 + 3 Mark
1 + 5 Mark
5 + 6 You win!
5 + 1 Mark
2 + 6 Mark
Wins: 1 Losses: 0 Marks: 4

我还没有进入最后一部分,因为我在处理代码时遇到了问题。感谢您对此的任何帮助。我很茫然。

这是我现在得到的实际结果:

Enter integer: 5

3 + 2
3 + 5
2 + 5 You win!
3 + 6
5 + 5

【问题讨论】:

  • 我知道有些变量没有使用,请忽略。
  • 我不理解规则 (tldr),但我看到你只与值 7、2 和 4 进行比较,而不是与数组的所有成员进行比较。这是故意的吗?
  • 第一个 call randomRange 将只产生 0-4 范围内的值(mov eax,5 提前)
  • 我看不出您当前的版本会如何冻结或崩溃,它应该在没有任何消息的情况下执行 ecx 多次循环,并显示值 7、2 的消息赢/输/标记, 4(那些带有消息的抛出不计算在内,如果只产生这样的抛出,则可以无限循环)。你能确认你发布的代码到底是什么吗? (我只是在脑海中“运行”它,所以我可能是错的)......哦..确实是......这些消息抛出也会将ecx重置为2、3或6,所以它可能会循环更长的时间......

标签: assembly x86


【解决方案1】:

您当前版本的功能:

第一次随机调用仅限 0-4。

cmp eax, win:您使用 MASM 语法,因此这是 Intel 语法中的 cmp eax,[mem32],会将 eax 与来自 win“数组”的值 7 进行比较。然后je wins 将在wins: 的代码处跳转到结果 7,然后执行一些无用的指针操作,将ecx 重置为 2,显示消息并跳回主滚动循环。

与loose/mark "arrays"类似,测试第一个元素(2代表loose,4代表mark),相等时显示loose/mark消息,有一些无用的东西,重置ecx并跳转直接回到滚动。

仅对于其他值(3、5、6、8、9、10、11(由于随机错误而缺少 12)),loop 被执行,在ecx 总循环中向下计数。

你应该很容易在调试器中看到这种行为(如果我在脑海中犯了一些错误,甚至发现与我的描述有任何差异,因为我对 CPU 的“仿真”有点有限,速度只有大约 2Hz) , 如果您单步执行指令并在每一步后检查机器状态。在没有调试器的情况下进行汇编编程就像试图组装被蒙住眼睛的机器人。可以,但难度要高出 100 倍,因此在继续学习汇编之前,投入大量资金学习如何有效地使用调试器。


关于代码的一些建议:

总的来说你有点复杂,否则我会这样做,我会在数据中定义表格(而不是win/lose/mark数组):

;             2L  3L  4M  5M  6M  7W  8M  9M 10M 11W 12L
outcome BYTE   1,  1,  2,  2,  2,  0,  2,  2,  2,  0,  1
outcomeMsgs:
    DWORD  OFFSET printWin, OFFSET printLose, OFFSET printMark
totalScore DWORD 0, 0, 0    ; wins / losses / marks

然后在第二次投掷后的代码中显示,并且您在eax 中有投掷的总和,您可以选择这样的结果:

    ; decide what is the outcome of throws
    movzx   ebx,byte ptr [outcome + eax - 2]
      ; ebx = 0/1/2 = win/lose/mark
    ; display outcome message
    mov     edx,[outcomeMsgs + ebx*4]
    call    writeString
    ; add to total score
    inc     dword ptr [totalScore + ebx*4]
    ; do ecx-many rolls
    dec     ecx
    jnz     DICEROLLS
    ; ending sequence
    ; for example, display total losses
    mov     edx,OFFSET printLost
    call    writeString
    mov     eax,[totalScore+4]
    call    writeDec
    ret

不幸的是,如果您想针对 win/... 数组中的值使用 cmp,这将完全避免这种情况,因此没有什么教育价值。您可能应该单独尝试编写该数组测试以获取更多技能...在您首先学会使用调试器之后,这样您就可以实际检查代码真正在做什么。

【讨论】:

  • 哇,我得稍微消化一下,非常感谢。不幸的是,我在 cmd 提示符下运行它,并没有得到调试器的好处。我必须学习如何在视觉工作室中使用它,现在把它作为优先事项:)。我在发布后意识到我没有比较整个数组,我需要创建一个循环/计数器来遍历数组,或者我只是尝试 cmp eax, 7 / cmp eax, 11 这似乎有效第一卷,但它会崩溃。我真的需要一个导师,不幸的是我找不到任何真正了解这些东西的人谢谢你
  • 如果您不介意,请解释这是如何打印出 rolls lost mov eax,[totalScore+4] 的值
  • @Alex 检查我对totalScore 的定义。它是3x DWORD 0。所以第一个DWORD 在地址totalScore+0,第二个在totalScore+4,第三个在totalScore+8。现在在我的示例中,我通过执行 inc dword ptr [totalScore + ebx*4] 来增加这些值,其中 ebx = 0/1/2 为赢/输/标记,因此损失计入地址 totalScore+4 的内存中(作为 DWORD,最多 4 个字节到地址 @ 987654344@ 受影响)。 ... Visual Studio 还能够调试控制台可执行文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-24
  • 1970-01-01
  • 2012-02-29
  • 2020-02-15
  • 1970-01-01
相关资源
最近更新 更多