I'm having trouble with this guessing game code I wrote:
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP :NONE
INCLUDE \MASM32\INCLUDE\WINDOWS.INC
INCLUDE \MASM32\INCLUDE\KERNEL32.INC
INCLUDE \MASM32\INCLUDE\MASM32.INC
INCLUDELIB \MASM32\LIB\KERNEL32.LIB
INCLUDELIB \MASM32\LIB\MASM32.LIB
.DATA
GreetString BYTE "Welcome to the Guessing Game!", 0Ah, 0
GuessString BYTE "Input a number between 1 and 100: ", 0
HighString BYTE "Your guess was too high.", 0Ah, 0
LowString BYTE "Your guess was too low.", 0Ah, 0
RightString BYTE "You guessed the number!", 0
.DATA?
Guess BYTE ?
ToGuess BYTE ? ;;not yet utilized
.CODE
START:
INVOKE StdOut, ADDR GreetString
_startGuess:
INVOKE StdOut, ADDR GuessString
INVOKE StdIn, ADDR Guess, 100
CMP Guess, 23
JA _highGuess
JB _lowGuess
JE _end
_highGuess:
INVOKE StdOut, ADDR HighString
JMP _startGuess
_lowGuess:
INVOKE StdOut, ADDR LowString
JMP _startGuess
_end:
INVOKE StdOut, ADDR RightString
INVOKE StdIn, ADDR Guess, 100 ;;only for pausing the program before exiting
INVOKE ExitProcess, 0
END START
Whenever the program runs the lines CMP Guess, 23
JA _highGuess
JB _lowGuess
JE _end
it always jumps to the _highGuess label, regardless of what value I input for Guess. I checked the value of Guess, and it is successfully being assigned the value I type during the StdIn command. What am I doing wrong?
that is because the value in the "Guess" buffer is an ASCII string
you are comparing it to a binary byte value
normally, i'd say you want to convert the Guess value to binary
but, in this particular case, you could compare it against ASCII decimal values
especially easy if you only let them go to 99 :bg
you have an unnecessary branch, here
the flag result after CMP is going to meet one of the 3 conditions (JA, JB, JE) - always
so, you only need 2 branches, letting the 3rd result "fall through"
this should work for everything except '100'
CMP word ptr Guess, '32' ;ASCII strings are backwards, here
JB _lowGuess
JE _end
_highGuess:
INVOKE StdOut, ADDR HighString
JMP _startGuess
_lowGuess:
INVOKE StdOut, ADDR LowString
JMP _startGuess
_end:
INVOKE StdOut, ADDR RightString
INVOKE StdIn, ADDR Guess, 100 ;;only for pausing the program before exiting
INVOKE ExitProcess, 0
you could make '100' work by ensuring the 4th byte is binary 0 before the compare, then using a dword
by the way, i thought the numer would be '42'
my guess was too high :lol
I tried what you suggested, and it works...sort of. The problem is that the value I input appears to be reversed within Guess, which is why I need to use '32' instead of '23', I assume. This becomes problematic because, when I enter a value like 50, which the program should say is higher than 23, it says that it is lower, because it ends up being put into Guess as 05. How would I fix this? Such as converting Guess into a binary, or reversing the characters within it after receiving input.
You could try:
_startGuess:
INVOKE StdOut, ADDR GuessString
INVOKE StdIn, ADDR Guess, 100
invoke trim, offset Guess
invoke atodw, offset Guess
CMP eax, 23
JB _lowGuess
JE _end
That did the trick! Thank you very much. :bg
oops - my mistake :P
the string is stored high-order byte first
because the input string can be 1, 2, 3 digits long - or 0 (user presses enter), or more digits, it may be best to convert the string to binary, first
ASCII decimal characters are pretty easy to work with
'0' = 30h
'1' = 31h
...
'9' = 39h
so, write a little loop to convert the string...
;
;
;
mov edx,offset Guess
xor ecx,ecx
Cnvrt0: movzx ax,word ptr [edx] ;get 2 bytes
or al,al ;is it a null ?
jz NoMoreDigits
xor al,30h ;toggle ASCII bits
cmp al,9 ;is it a digit ?
ja NoMoreDigits
or ah,ah ;is the next byte a null ?
jz LastDigit
xor ah,30h
cmp ah,9 ;is the next byte a digit ?
mov ah,0
ja LastDigit
add eax,ecx
mov ecx,10
push edx
mul ecx
or edx,edx
pop edx
jnz OverFlow
xchg eax,ecx
inc edx
jmp Cnvrt0
OverFlow:
;here, you want to display a message saying the value is too large,
;then go back and let them enter another value
jmp _startGuess
LastDigit:
add ecx,eax
NoMoreDigits:
CMP ecx,23
JB _lowGuess
JE _end
_highGuess:
INVOKE StdOut, ADDR HighString
JMP _startGuess
_lowGuess:
INVOKE StdOut, ADDR LowString
JMP _startGuess
_end:
INVOKE StdOut, ADDR RightString
INVOKE StdIn, ADDR Guess, 100 ;;only for pausing the program before exiting
INVOKE ExitProcess, 0
Rob's idea about using atodw is easier :P
Hmmmm...interesting. I'll definitely look at this, as it will help me understand the language better. Thanks for the help. :bg