News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Using the CMP Operator

Started by cbjunior, October 16, 2011, 07:01:11 PM

Previous topic - Next topic

cbjunior

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?
Ash nazg durbatuluk
Ash nazg gimpatul
Ash nazg thrakatuluk
Agh burzum ishi krimpatul

dedndave

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

dedndave

by the way, i thought the numer would be '42'
my guess was too high   :lol

cbjunior

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.
Ash nazg durbatuluk
Ash nazg gimpatul
Ash nazg thrakatuluk
Agh burzum ishi krimpatul

Gunner

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
~Rob (Gunner)
- IE Zone Editor
- Gunners File Type Editor
http://www.gunnerinc.com

cbjunior

That did the trick! Thank you very much.   :bg
Ash nazg durbatuluk
Ash nazg gimpatul
Ash nazg thrakatuluk
Agh burzum ishi krimpatul

dedndave

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

cbjunior

Hmmmm...interesting. I'll definitely look at this, as it will help me understand the language better. Thanks for the help.   :bg
Ash nazg durbatuluk
Ash nazg gimpatul
Ash nazg thrakatuluk
Agh burzum ishi krimpatul