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