assembly 猜谜游戏- NASM装配核心

mlnl4t2r  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(188)

我正在尝试用一个内核在NASM汇编中做一个猜谜游戏。 Boot 加载程序只是指向内核文件。内核文件存储了所有的东西。游戏的所有函数和变量;而我已经打印出了游戏的说明。当我使用if语句时,它会打印出获胜消息,不管它的数字是否正确。我希望内核在选择正确的数字时打印出正确的获胜消息。我的内核代码如下...

org   0
 bits  16

_start:
 push cs
 pop  ds
 mov  si, msg
 jmp  BeginLoop

PrintLoop:
 mov  ah, 0x0E
 int  0x10

BeginLoop:
  mov  al, [si]
  inc  si
  or al, al
  jz GameLoop
  test al, al
  jnz  PrintLoop

GameLoop:
  xor ax, ax
  int 16h
  mov ah, 0x0E
  int  0x10
  cmp ax, 0x5
  jne GameWon

GameWon:
 mov si, won
 mov  al, [si]
 inc  si
 or al, al
 jz GameLoop
 test al, al
 jnz  PrintLoop

 cli
 hlt
 jmp  $-2


 msg db   'Welcome To My Guessing Game: ', 10, 13, 'Pick A Number Between            1 - 10 ', 10, 13, 0
 won db   'You Guessed The Correct Number!', 10, 13, 0
 loss db  'You Guessed The Incorrect Number!' 10, 13

 TIMES 512 - ($ - $$) db 0

更新了可正常工作的代码

org 0
bits 16

_.start:
push cs
pop  ds
mov  si, msg
jmp Print

GameLoop:
mov ah, 00h
int 1ah
mov  ax, dx
xor  dx, dx
mov  cx, 10
div  cx
add  dl, '0'
mov  ah, 0x00
int  16h
mov  ah, 0x0E
int  0x10

GameCondition:
mov  si, won
cmp  al, dl
je   GameWon
jmp  GameLost

GameLost:
mov  si, loss
jmp Print

GameWon:
jmp Print

Print:
jmp  BeginLoop

PrintLoop:
mov  ah, 0x0E
int  0x10

BeginLoop:
mov  al, [si]
inc  si
or al, al
jz GameLoop
test al, al
jnz  PrintLoop
ret

; -------------------
msg db   'Welcome To My Guessing Game: ', 10, 13, 'Pick A Number Between 0 - 9 ', 10, 13, 0
won db   'You Guessed The Correct Number!', 10, 13, 0
loss db  'You Guessed The Incorrect Number!', 10, 13,  0

times 512 - ($-$$) db 0
pes8fvy9

pes8fvy91#

cmp ax, 0x5
  jne GameWon

GameWon:

在根据比较结果进行分支的代码中,如果条件为真,则执行跳转,但如果条件不为真,则继续执行下面的代码行。我们称之为“falling through”。在您的程序中,您总是会到达 GameWon

or al, al
  jz GameLoop
  test al, al
  jnz  PrintLoop

GameLoop:

这是另一个不了解代码福尔斯原理的例子。当test al, al指令确定AL为0时,PrintLoop 将不会继续,执行将进入 GameLoop。因此,使用添加的两行(or al, aljz GameLoop)检查空AL是完全多余的。

GameLoop:
  xor ax, ax
  int 16h
  mov ah, 0x0E
  int  0x10
  cmp ax, 0x5
  jne GameWon

游戏循环等待一个密钥,将其回显到屏幕,然后将该密钥与值0x5进行比较。
BIOS在AL寄存器中提供了密钥的ASCII码**,在AH寄存器中提供了密钥的扫描码**。cmp ax, 0x5指令(比较完整的16位)不起作用的原因有3个:

  • 扫描码从1开始,从不从0开始
  • 你需要比较ASCII码,对于5就是53
  • 通过电传打字机的回声破坏了AH

你的程序输出了几条消息。你不能继续使用我在前面的答案中写的 PrintLoop。你需要把这段代码变成一个子例程,你可以call多次:

_start:
  push cs
  pop  ds
GameLoop:
  mov  si, msg
  call Print
  mov  ah, 0x00
  int  16h         ; -> AX
  mov  ah, 0x0E
  int  0x10
  mov  si, won
  cmp  al, 0x35    ; eg. "5"
  je   GameWon
  mov  si, loss
 GameWon:
  call Print
  jmp  GameLoop    ; Truly a loop

; --------------------
; IN (si) OUT (si) MOD (ax)
Print:
  jmp  BeginLoop
 PrintLoop:
  mov  ah, 0x0E
  int  0x10
 BeginLoop:
  mov  al, [si]
  inc  si
  test al, al
  jnz  PrintLoop
  ret
; -------------------
 msg db   'Welcome To My Guessing Game: ', 10, 13, 'Pick A Number Between 
0 - 9 ', 10, 13, 0
 won db   'You Guessed The Correct Number!', 10, 13, 0
 loss db  'You Guessed The Incorrect Number!' 10, 13, 0

提示:最好是0到9之间的一位数。数字10不是一个好的选择,因为它没有一个ASCII码。

Generate:
xor ax, ax
mov ax, 57
div ax, 3 
inc ax

你最新的编辑表明你也想实现一个随机数生成器。在8086随机数生成器中掌握它(不仅仅是使用系统时间)?。
div ax, 3行不是有效指令!并且xor ax, ax需要改为xor dx, dx
接下来是一个正确的除法运算,当然(57/3)+1并不令人惊讶:

Generate:
xor dx, dx
mov ax, 57
mov cx, 3
div cx 
inc ax
2hh7jdfx

2hh7jdfx2#

有几件事是错误的。首先,正如@vitsoft之前所说的,你没有GameLoss条件。你正在检查某个值是否为5,基本上忽略了这个条件。

GameLoop:
  xor ax, ax
  int 16h
  mov ah, 0x0E
  int  0x10
  cmp ax, 0x5
  jne GameWon

GameWon:
 mov si, won
 mov  al, [si]
 inc  si
 or al, al
 jz GameLoop
 test al, al
 jnz  PrintLoop

要修复上述代码,可以:

GameLoop:
  xor ax, ax
  int 16h
  mov ah, 0x0E
  int  0x10
  cmp ax, 0x5 ; I am assuming that the player wins if the input is 0x5
  je GameWon

GameLost:
  ; print some error message or a message stating they lost
  ; and etc
  jmp endGame

GameWon:
 mov si, won
 mov  al, [si]
 inc  si
 or al, al
 jz GameLoop
 test al, al
 jnz  PrintLoop

endGame:
 cli
 hlt
 jmp  $-2

还有这个东西

mov ah, 0x0E
int  0x10
cmp ax, 0x5 ; I am assuming that the player wins if the input is 0x5

您要将0x 0 E移动到ah,然后期望ax的值为0x 5。这是不可能的,因为据我所知,int 0x10不会修改ah。因此代码应为:

mov ah, 0x0E
int  0x10
cmp al, 0x5 ; I am assuming that you want to check for the ASCII character
            ; Also are you sure that you should compare it with 0x5 and not '5'?

这里是一个简单的猜谜游戏的代码,我还没有尝试过这个本身,尝试它,并适应自己:

[BITS 16]

global _start

_start:
    mov si, welcomeMsg ; print welcome message
    call printstr

    xor ax, ax ; get input
    int 0x16
    mov ah, 0x0e ; print the character
    int 0x10
    
    sub al, '0' ; convert letter to number
    cmp al, 5 ; compare the inputted value to some number
    je GameWon ; if the inputted value is equal to the number that we are looking for
               ; go to game won
    
GameLost:
    mov si, lossMsg
    call printstr
    jmp EndGame

GameWon:
    mov si, wonMsg
    call printstr

EndGame: 

    jmp $

;
; Input: si: pointer to string to print
;

printstr:
    push ax
    push si
    mov ah, 0x0e

printstrloop:
    mov al, byte [si]
    cmp al, 0
    je endprintstr
    int 0x10
    inc si
    jmp printstrloop

endprintstr:
    pop si
    pop ax
    ret

welcomeMsg: db "Welcome To My Guessing Game: ", 10, 13, "Pick A Number Between 1 - 10 ", 10, 13, 0
wonMsg: db "You Guessed The Correct Number!", 10, 13, 0
lossMsg: db "You Guessed The Incorrect Number!" 10, 13

times 512 - ($-$$) db 0x00

编辑:
这段代码是错误的:

add  dl, '0'

cmp al,dl
je GameWon
GameWon:
mov si, WonMsg
jmp PrintLoop
jmp EndGame

cmp al,dl
jne GameLost
GameLost:
mov si, lossMsg
jmp PrintLoop
jmp EndGame

这甚至没有意义:

cmp al,dl
je GameWon
GameWon:

你正在比较两个值,如果它们相等,就执行GameWon。如果它们不相等,你什么也不做,你的代码继续执行,无论如何都到达GameWon。我在这篇文章中多次提到这个问题,它实际上是文章的第二句话。要修复代码,它应该是:

add  dl, '0'

cmp al,dl
jne GameLost

GameWon:
mov si, WonMsg
jmp PrintLoop
jmp EndGame

GameLost:
mov si, lossMsg
jmp PrintLoop
jmp EndGame

现在你要检查aldl是否相同,如果不相同,你就跳到GameLost,如果相等,你就自动执行GameWon
这与@SepRoland的注解相结合,使您的最终代码如下:

org   0
 bits  16

_start:
push cs
pop  ds
mov si, WelcomeMsg
jmp  BeginLoop

PrintLoop:
mov  ah, 0x0E
int  0x10

BeginLoop:
mov  al, [si]
inc  si
or al, al
jz GamePlay
test al, al
jnz  PrintLoop

GamePlay:
xor ax, ax
int 16h
push ax
mov ah, 0x0E
int  0x10
mov ah, 00h
int 1ah
mov  ax, dx
xor  dx, dx
mov  cx, 10
div  cx
add  dl, '0'
pop ax
cmp al,dl
jne GameLost

GameWon:
mov si, WonMsg
jmp PrintLoop
jmp EndGame

cmp al,dl
jne GameLost

GameLost:
mov si, lossMsg
jmp PrintLoop
jmp EndGame

EndGame:
cli
hlt
jmp  $-2

WelcomeMsg db   'Welcome To My Guessing Game: ', 10, 13, 'Pick A Number Between 1 - 10 ', 10, 13, 0
 WonMsg db   'You Guessed The Correct Number!', 10, 13, 0
 lossMsg db  'You Guessed The Incorrect Number!', 10, 13, 0

 TIMES 512 - ($ - $$) db 0x00

相关问题