Home > Blockchain >  Guessing Game - NASM ASSEMBLY KERNEL
Guessing Game - NASM ASSEMBLY KERNEL

Time:10-16

I'm trying to make a guessing game in NASM assembly using a kernel. The boot loader just points to the kernel file. The kernel file stores everything. All the functions and variables for the game; while Ive gotten as far to print instructions for the game out. The problem arises; when I use an if statement. It prints out the winning message whether it's the correct number or not. I want the kernel to print the correct winning message, when the correct number is chosen. My code for the kernel is below ....

 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

Updated the code

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

; Generating a random number
Generate:
xor ax, ax
mov ax, 57
div ax, 3 
inc ax
jmp GameLoop


GameLoop:
xor al, al
int 16h
mov ah, 0x0E
int  0x10
jmp Generate
cmp al, ax
je GameWon
cmp al, ax
jne GameLost

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

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


EndGame:
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

CodePudding user response:

  cmp ax, 0x5
  jne GameWon

GameWon:

In code that branches on the result of a comparison, if the condition is true then the jump is taken, but if the condition is not true then the execution just continues on the following lines. We call this 'falling through'. In your program you will always arrive at GameWon.

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

GameLoop:

And this is another example of not understanding the priciple of code that falls through. When the test al, al instruction determines that AL is 0, the PrintLoop will not continue and the execution will fall through into your GameLoop. Therefore it is totally redundant that you would check for an empty AL with those two lines that you added (or al, al jz GameLoop).

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

The game loop waits for a key, echoes it to the screen, and then wants to compare the key with the value 0x5.
BIOS gave you the key's ASCII code in the AL register and the key's scancode in the AH register. There are 3 reasons why the cmp ax, 0x5 instruction (comparing the full 16 bits) is not going to work:

  • Scancodes start at 1, never 0
  • You need to compare ASCII codes, for 5 that is 53
  • The echoing via the Teletype destroys AH

Your program outputs several messages. You cannot continu to use the PrintLoop that I wrote in a previous answer. You need to turn this code into a subroutine that you can call multiple times:

_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

Tip: better ask for a single-digit number in the range 0 to 9. The number 10 is not a good choice since it doesn't have a single ASCII code.


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

Your latest edit shows that you also want to implement a random number generator. Get a grasp for it in 8086 random number generator (not just using the system time)?.
The div ax, 3 line is not a valid instruction! And the xor ax, ax needs to become xor dx, dx instead.

Next is a correct dividing operation, although of course (57/3) 1 is not going to be a surprise:

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

CodePudding user response:

There are a couple of things wrong. First is, as @vitsoft stated earlier, that you don't have a GameLoss condition. You are checking if something is 5 and basically ignoring the condition.

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

To fix that the above code can be:

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

Also there is this thing

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

You are moving 0x0E to ah and then expecting ax to have a value of 0x5. This is not possible since as far as I know int 0x10 doesn't modify ah. Therefore the code should be:

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'?

Here is a simple guessing game code, I haven't tried this per se, try it and adapt it to yourself:


[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

  • Related