汇编是一种有趣的语言学习。我还有很大的提升空间。我试图做一个简单的掷骰子游戏,应该根据用户输入随机掷骰子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
,我会得到一些奇怪的冻结,有时会崩溃。我试图学习如何在装配中更好地编码。你能不能帮助我理解为什么这不是我想象的那样。我想如果我比较eax
寄存器,其中包含diceOne + diceTwo
的总和它应该跳到其他函数,并且在那些函数中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
答案 0 :(得分:0)
您当前的版本:
第一次随机通话仅为0-4。
cmp eax, win
:您使用MASM语法,因此在英特尔语法中为cmp eax,[mem32]
,将eax
与来自7
"的值win
进行比较阵列&#34 ;.然后je wins
将在wins:
处的代码处跳转结果7,并且那将执行一些无用的指针内容,将ecx
重置为2,显示消息并跳回主卷循环。
类似于丢失/标记"数组",第一个元素(2表示丢失,4表示标记)被测试,当相等时,显示丢失/标记消息,带有一些无用的东西,重置ecx
并直接回到滚动。
仅对其他值(3,5,6,8,9,10,11(由于随机错误而丢失12))执行loop
,在ecx
中向下计数总循环。
你应该很容易在调试器中看到这种行为(甚至发现我的描述有任何差异,如果我在脑子里做了一些错误,因为我的"仿真和#34; 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
不幸的是,如果你想对cmp
数组中的值进行win/...
运算,那么这就完全避免了,因此教育价值很小。您可能应该单独尝试编写该数组测试,以获得更多技能......在您学会首先使用调试器之后,您可以实际检查代码的真正用途。