x86 Irvine Assembly jmp + cmp и условные циклы - игра в кости
Сборка - это интересный язык для изучения. У меня еще много возможностей для совершенствования. Я пытаюсь сделать простую игру в кости, которая должна делать случайные броски игральных костей х количество раз на основе пользовательского ввода. У меня есть код следующим образом:
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^C
1 ответ
Что делает ваша текущая версия:
Первый случайный звонок только 0-4.
cmp eax, win
: Вы используете синтаксис MASM, так что это cmp eax,[mem32]
в синтаксисе Intel, будем сравнивать eax
против стоимости 7
от win
"Массив". затем je wins
будет прыгать на результат 7 в коде в wins:
и тот сделает некоторые бесполезные вещи с указателями, сброс ecx
до 2, отобразить сообщение и вернуться к главному циклу вращения.
Аналогично для "массивов" потерь / меток тестируется первый элемент (2 для потерь, 4 для оценки), и при равенстве отображается сообщение "потеря / оценка", с некоторыми бесполезными данными, сбрасываемые ecx
и прыгать прямо обратно в прокат.
Только для других значений (3, 5, 6, 8, 9, 10, 11 (и пропущенных 12 из-за случайной ошибки)) loop
выполняется, считая в ecx
общее количество петель.
Вы должны легко увидеть это поведение в отладчике (и даже обнаружить какое-либо несоответствие моему описанию, если я допустил какую-то ошибку в моей голове, поскольку моя "эмуляция" ЦП немного ограничена и имеет скорость всего лишь ~2 Гц), если вы пошаговое выполнение инструкций и проверка состояния машины после каждого шага. Программирование в сборке без отладчика похоже на попытку собрать робота с завязанными глазами. Вы можете, но это примерно в 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/...
массивы, это позволяет избежать этого полностью, поэтому имеет небольшую образовательную ценность. Вероятно, вам следует отдельно попытаться написать этот тест массива, чтобы получить больше навыков... после того, как вы научитесь сначала использовать отладчик, чтобы вы могли на самом деле проверить, что на самом деле делает код.