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/... массивы, это позволяет избежать этого полностью, поэтому имеет небольшую образовательную ценность. Вероятно, вам следует отдельно попытаться написать этот тест массива, чтобы получить больше навыков... после того, как вы научитесь сначала использовать отладчик, чтобы вы могли на самом деле проверить, что на самом деле делает код.

Другие вопросы по тегам