Thread: Random guessing game

  1. #1
    Registered User
    Join Date
    Sep 2006
    Posts
    14

    Random guessing game

    I'm trying to program a simple game where the user has to guess a number between 1 and 1000. The game works for the most part, however it always displays the "You are correct! Play again? (y or n)" message twice. I don't understand why. Could someone here take a look at my code and point me in the right direction? I'd greatly appreciate it. The game is supposed to start over again, with a new random number if the user wins and presses 'y' - it's supposed to end if the user wins and presses 'n'.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(){
    
    int i = 1;
    int ran = 0;
    int input = 0;
    char cont = 0;
    
    srand( time( NULL ) );
    ran = 1 + ( rand() % 999);
    
    
    
    printf( "I have a number between 1 and 1000.\nCan you guess my number?\nPlease type your first guess.\n");
    		
    		
    	while( i != 0){
    		scanf( "%d", &input);
    		if( input != ran ){
    			if( input > ran)
    				printf("You're too high. Try again.\n");
    			if( input < ran)
    				printf("You're too low. Try again.\n");
    		}
    		if(input == ran){
    			printf("You're correct! Play again? (y or n)\n");
    			scanf("%c", &cont);
    			if( cont == 'y'){
    				cont = 0;
    				printf( "I have a number between 1 and 1000.\nCan you guess my number?\nPlease type your first guess.\n");
    			}
    			if( cont == 'n'){
    				printf("Ending game.\n");
    				i = 0;
    			}
    		}
    
    
    
    
    	}
    
    	return 0;
    }

  2. #2
    {Jaxom,Imriel,Liam}'s Dad Kennedy's Avatar
    Join Date
    Aug 2006
    Location
    Alabama
    Posts
    1,065
    You need to test for Y as well as y, then loop the question if y, Y, n, N is not pressed. Also, you'll need to get another random number when the user presses Yes. Reset your `input` also.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    It's just another example of using broken scanf() to handle user input.

    It doesn't handle errors gracefully, and you don't even check them at all.
    Use fgets() and sscanf(), see the FAQ.

    Also, there seems to be confusion over whether it is 'cont' or 'i' which is the exit condition. Perhaps better named variables would help.

    Also, you don't calculate another 'ran' if yes is selected.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    14
    Quote Originally Posted by Salem
    It's just another example of using broken scanf() to handle user input.

    It doesn't handle errors gracefully, and you don't even check them at all.
    Use fgets() and sscanf(), see the FAQ.

    Also, there seems to be confusion over whether it is 'cont' or 'i' which is the exit condition. Perhaps better named variables would help.

    Also, you don't calculate another 'ran' if yes is selected.
    cont is the variable that holds the input for one of the scanf functions. I used an if statement to check to see what cont was equal to after the scan - if it was equal to n, it set the continuation variable ( i ) to zero. That way it doesn't loop again.

    Kennedy: That sounds like a switch statement. I'll try using that, but this should be simple enough to work without it, if I wasn't worried about looking for both the lowercase and captial of y and n, right?

    I'd rather do this with the knowledge that I know from my book than with some functions that I don't know about yet. My book assumes I should be able to do it with scanf.

    I'm just worried why my program breaks when I try to start a new game or end the game. It loops the "You are too high!" or the "You are too low!" message.

    Should I try using getchar for y and n?

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Let me guess -- you typed "yes" when asked if you wanted to play a new game.

    Well, the scanf("%c") only reads the 'y' -- "es\n" is still in the input stream. The next scanf() comes looking for a number and finds an 'e'. It gets confused and returns an error code without doing anything. The next scanf() will do the same thing. You have an infinite loop there, as you have described.

    There are two things you could do to rectify this problem. Either type only 'y', or fix it.

    To fix it, first put a loop after the scanf("%c") that will read in the rest of the characters in stdin.
    Code:
    int c;  /* must be int to hold EOF */
    while((c = getchar()) != '\n' && c != EOF);
    You should also check the return value of scanf() to see if an error occured. scanf() returns the number of items successfully read, so if you pass it "%d", it will return 1 on success. Passing it "%i%i%i" could result in 0, 1, 2, or 3 (and possibly others). If it did encounter an error, clear stdin again with the above code.
    Code:
    while(scanf("%d", &integer) != 1) {
        while((c = getchar()) != '\n' && c != EOF);
        printf("Invalid number, try again: ");
    }
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    14
    Quote Originally Posted by dwks
    Let me guess -- you typed "yes" when asked if you wanted to play a new game.
    No, I only typed y or n. The program still breaks, so I don't think making the changes you've suggested would fix the problem. I'll give it a try when I get home, but that's not what broke the program. Thank you very much for your help though.

    Does anyone else see why the program would break when trying to start a new game?

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    14
    I've fixed the program. I'm not completey sure, but I believe my problem was using scanf to read in the input expecting it to be a %c - I thought this stood for character, but apparently I needed to be reading it in as a %s for string. I've since re-written the program to use a switch statement. I realize that this still has no error checking, and it can be broken easily, I'm sure (because scanf seems to be poorly designed) but this completes what the excersize in the book calls for. My assignment is now complete.

    Thank you all for helping me in the right direction. Here's a post of my code incase someone catches something that I did not. I'm new to programming, so if you see a goof I've made, or something that I've made too complicated, give me a heads up and help me learn. I'm sure there's plenty of room for improvement with this simple game. Please note that I actually print the random number for debugging purposes. Since the program seems to be working as intended, this could be removed.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(){
    
    int i = 1;
    int ran = 0;
    int input = 0;
    char cont = 0;
    
    srand( time( NULL ) );
    ran = 1 + ( rand() % 999);
    
    
    printf("The random number is %d. This is for debugging purposes.\n", ran);
    printf( "I have a number between 1 and 1000.\nCan you guess my number?\nPlease type your first guess.\n");
    		
    		
    while( i != 0){
    		input = 0;				/* Reset input. */
    		scanf( "%d", &input);	/* Ask for input, and store it inside the variable input. */
    		
    		
    		/* If the input does not equal the random number, check this. */
    		if( input != ran ){
    			if( input > ran ){
    				printf("Too high. Please try again.\n");
    			}
    
    			if( input < ran ){
    				printf("Too low. Please try again.\n");
    			}
    		}
    
    		
    		/* If the input does equal the random number, make a new random number. Ask if 
    		   the user wants to play another game. If not, end the program. */
    		if( input == ran){		
    			ran = 1 + ( rand() % 999);
    			printf("Correct! Would you like to play again? ( y or n)\n");
    			scanf("%s", &cont);
    			switch(cont) { /* check the input inside of the variable cont */
    				case 'y':
    				case 'Y':
    					ran = 1 + ( rand() % 999);
    					printf("Starting new game.\n");
    					printf("The random number is %d. This is for debugging purposes.\n", ran);
    					printf( "I have a number between 1 and 1000.\nCan you guess my number?\nPlease type your first guess.\n");
    					break;
    	
    				case 'n':
    				case 'N':
    					printf("Ending game.\n");
    					i = 0;
    					break;
    	
    				default:
    					printf("Wrong input.\n");
    					break;
    			}
    		}
    
    
    
    	}
    
    	return 0;
    }

  8. #8
    Registered User
    Join Date
    Oct 2006
    Posts
    3
    First of all, when using scanf() to read in characters, you should not point to the address of the variable... So there should be no "&" symbol before your variable "cont"...

    Here is what I would do:

    Code:
    if( input == ran){		
    			ran = 1 + ( rand() % 999);
    			printf("Correct! Would you like to play again? ( y or n)\n");
    			scanf("%c", cont);
                            if ((cont == 'y') || (cont == 'Y')) {
                                   // blah blah blah
                                  }
                            if ((cont =='n') || (cont == 'N')) {
                                   // blah blah blah
                                  }
                            else {
                                  // blah blah blah
                                  }
    		}
    it gets rid of those nasty switch statements!
    hope that helps!

  9. #9
    {Jaxom,Imriel,Liam}'s Dad Kennedy's Avatar
    Join Date
    Aug 2006
    Location
    Alabama
    Posts
    1,065
    Post #3 and Post #5 both tell you to NOT use scanf. You say you must use scanf. Okay, then in Post #5 you are told why you you aren't getting results you expect. You aren't just entering 'y' or 'n'. There is also a '\n' at least. Also, you still haven't put a while() loop around your switch. Use the switch if you want, but for only 2 vs 2 argument the if statement would be better.

    Please listen to folks when they give you advice.

  10. #10
    Its hard... But im here swgh's Avatar
    Join Date
    Apr 2005
    Location
    England
    Posts
    1,688
    I know it is C++, but using srand() and rand() would make the program much smaller and easier to read

    Code:
    srand((unsigned)time(0));
    
    int num = rand() % 1000 + 1;
    Then use a do-while loop or a for loop to keep looping untill answer is correct

  11. #11
    Registered User
    Join Date
    Sep 2006
    Posts
    14
    Quote Originally Posted by Kennedy
    Post #3 and Post #5 both tell you to NOT use scanf. You say you must use scanf.
    Post three may tell me not to use scanf, but why would I use code when I have no idea what it does? I posted here asking why my code didn't work as expected, not how to completely rewrite it just because scanf is considered to be broken. I'm learning from a book. At the end of each chapter are excersizes that you should be able to complete with the knowledge you have learned from each previous chapter. Right now, the only thing I understand is scanf. Not sscanf, not fgets, nothing. So again, why would I use these functions when I don't understand them, and up until this point have not even heard of? The object of doing these excersizes is to understand the code, not use more efficient functions that are built into C that I know nothing about. If I start throwing in things that I haven't learned about, not only will I not learn anything, but I'll be confused if I come back to this code at a later date for guidance.

    Okay, then in Post #5 you are told why you you aren't getting results you expect.
    Lets take a look at exactly what post five told me.

    Let me guess -- you typed "yes" when asked if you wanted to play a new game.

    Well, the scanf("%c") only reads the 'y' -- "es\n" is still in the input stream. The next scanf() comes looking for a number and finds an 'e'. It gets confused and returns an error code without doing anything. The next scanf() will do the same thing. You have an infinite loop there, as you have described.
    This post, while giving a correct way to fix my problem, did not seem to be correct to me at the time. Realize that I'm new, so I don't readily understand code when I see it. I have to disect it, look up definitions, etc. I did not understand, and still do not understand how to implement (although I do understand how it works) what his code did, However, his assumption that I typed in a full word instead of y or n was wrong. That's all I typed in. You say that the new line character, \n is passed on. That's not something easily realized when you're new to programming, and may explain why I was getting the errors. However, post five made no mention of the \n character, and for all I knew, n or y was all I was passing on.

    Also, you still haven't put a while() loop around your switch. Use the switch if you want, but for only 2 vs 2 argument the if statement would be better.
    I haven't put a loop around my switch statement because I'm still working on understanding how to implement it, and how to understand it. As is, my program works as intended, but does not take into account user error. It doesn't take this into account because my book does not call for it, and I have learned little about implementing it. Perhaps it's covered in another chapter. I'm still early in the book. From what I understand, the loop around the switch statement would check the scanf for errors, and allow more than one character to be passed onto the scanf without breaking the program.

    Yes, using the if statement would be better. I see that now. However, being new to programming, I don't see every viable solution all at once. I saw that the switch statement would work, and knowing how to use it, I implemented it. It worked, and I was happy. Sure, it may not be as efficient as the if statement, but it's not wrong either. Maybe next time a problem like this comes to me, I'll realize that the if statement would work better than the switch statement. I hadn't thought of using an if statement with || to check for one case or the other.

    Please listen to folks when they give you advice.
    I'm here to learn. Programming is not an easy task (atleast for most of us). If my book wants me to continue using scanf, I will until it teaches me about the other functions. That way I learn about them in full, instead of just jimmy rigging them into my program because others feel they are more efficient. I'll be looking up the functions suggested here, but if I dont' understand them, I'm not going to fret much. I'll learn them when I get to them. I'm not here to make a bullet-proof program, just to do a few excersizes to make sure I'm where I should be. I appreciate the help I recieved here, and your posts did help me track down the problem. However, I was looking to fix my program using the functions I had posted, not find more efficient ones. I see no problem with using scanf, and my book more than likely wants me to use it so that I understand at an early stage how to implement basic error checking, rather than have a function do everything for me. Learning too much too quickly is not always a good thing.
    Last edited by Nalif; 10-25-2006 at 02:19 PM.

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    If you persist with scanf, then get used to all sorts of funnies.

    Rule 1 - scanf leaves input.
    So if you type in
    1234ABCD<return>
    and you try and read with %d, then you will have ABCD<return> to deal with at some later stage. Unless you're careful, even minor user typos will mess with your head.

    Rule 2 - scanf skips leading white space, and stops at trailing white space.
    For everything except %c conversions.

    Rule 3 - if the conversion doesn't happen, then the data is still there.
    Type in
    ABCD<return>
    and you try and read with %d, then you will have ABCD<return> to deal with.
    Recovering from user input errors is a PITA, made even worse by the fact that few people even bother to look at what scanf() returns.

    Keeping track of exactly where you are is hard work, even when the user is playing by the rules.

    Oh, and ignore anyone who suggests using fflush(stdin) as a solution to the woes of dealing with input that scanf() doesn't deal with.

    > If my book wants me to continue using scanf
    Skip ahead, and find out how much longer you have to wait before you get to fgets()
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  13. #13
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Quote Originally Posted by Nalif
    Post three may tell me not to use scanf, but why would I use code when I have no idea what it does? I posted here asking why my code didn't work as expected, not how to completely rewrite it just because scanf is considered to be broken. I'm learning from a book. At the end of each chapter are excersizes that you should be able to complete with the knowledge you have learned from each previous [COLOR="Magenta"]chapter. Right now, the only thing I understand is scanf. Not sscanf, not fgets, nothing. So again, why would I use these functions when I don't understand them, and up until this point have not even heard of? The object of doing these excersizes is to understand the code, not use more efficient functions that are built into C that I know nothing about. If I start throwing in things that I haven't learned about, not only will I not learn anything, but I'll be confused if I come back to this code at a later date for guidance.
    It seems to me your problems arise because you don't know how to use scanf. So by your own argument, why are you using it?

    Quote Originally Posted by Nalif
    I haven't put a loop around my switch statement because I'm still working on understanding how to implement it, and how to understand it. As is, my program works as intended, but does not take into account user error. It doesn't take this into account because my book does not call for it, and I have learned little about implementing it. Perhaps it's covered in another chapter. I'm still early in the book. From what I understand, the loop around the switch statement would check the scanf for errors, and allow more than one character to be passed onto the scanf without breaking the program.
    It's really not a user error, it's a programmer error (failure to handle input correctly). Perhaps that's why these issues were brought to your attention.

    Quote Originally Posted by Nalif
    I'm here to learn. Programming is not an easy task (atleast for most of us). If my book wants me to continue using scanf, I will until it teaches me about the other functions. That way I learn about them in full, instead of just jimmy rigging them into my program because others feel they are more efficient. I'll be looking up the functions suggested here, but if I dont' understand them, I'm not going to fret much. I'll learn them when I get to them. I'm not here to make a bullet-proof program, just to do a few excersizes to make sure I'm where I should be. I appreciate the help I recieved here, and your posts did help me track down the problem. However, I was looking to fix my program using the functions I had posted, not find more efficient ones. I see no problem with using scanf, and my book more than likely wants me to use it so that I understand at an early stage how to implement basic error checking, rather than have a function do everything for me. Learning too much too quickly is not always a good thing.
    Perhaps your books happens to suck because it does not tell you how to program correctly. If this is so and you know it, would you still discard sound advice in favor of unsound advice from a book?
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  14. #14
    Registered User
    Join Date
    Sep 2006
    Posts
    14
    Quote Originally Posted by Dave_Sinkula
    It seems to me your problems arise because you don't know how to use scanf. So by your own argument, why are you using it?
    Let me restate. I do not understand scanf. However, I understand it much more than any other comparable function. I can't claim to fully understand any function I've ever used, because I've never taken a look at C's header files to see how they work and exactly what they do. For now, I usually know when I can use them, and I vaguely know what they do.
    It's really not a user error, it's a programmer error (failure to handle input correctly). Perhaps that's why these issues were brought to your attention.
    For now, I'm not so much interested in whos error it is. It's enough for me to realize that the problem is there and that I'll eventually realize how to deal with it.
    Perhaps your books happens to suck because it does not tell you how to program correctly. If this is so and you know it, would you still discard sound advice in favor of unsound advice from a book?
    This may indeed be true. I'm using C How to Program by Dietel, fourth edition. Do you know anything about the quality of this book?

    Don't look at it as discarding sound advice - I said I would look up the functions recommended. I'm just afraid that I'll get ahead of the book and miss out on things I should have learned along the way. Even worst, that I get lost and become discouraged with programming all together.

  15. #15
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Good attitude. (No sarcasm.)

    You can take the long road or frustration and cling to scanf, or you can jettison it in favor of better ways (previously mentioned).
    One of my rants.

    One of these days I may feel I've got a comprehensive hold of scanf, but until then I'll wing it and avoid it because I know many bad things that come from using it.

    And I know nothing of value regarding your book.
    Quote Originally Posted by Nalif
    For now, I'm not so much interested in whos error it is. It's enough for me to realize that the problem is there and that I'll eventually realize how to deal with it.
    The "how to deal with it" was already presented.

    Quote Originally Posted by Nalif
    Even worst, that I get lost and become discouraged with programming all together.
    Even worse, if you don't listen to the presented advice, you may become discouraged with programming altogether.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. random to int?
    By psyadam in forum C# Programming
    Replies: 7
    Last Post: 07-22-2008, 08:09 PM
  2. guessing game
    By Sal79 in forum C Programming
    Replies: 14
    Last Post: 05-09-2007, 02:22 PM
  3. C Programming 2d Array Question
    By jeev2005 in forum C Programming
    Replies: 3
    Last Post: 04-26-2006, 03:18 PM
  4. Genetic Random Number Guessing Agent (GRNGA)
    By Keybone in forum C++ Programming
    Replies: 14
    Last Post: 05-27-2004, 11:14 AM
  5. Random Number problem in number guessing game...
    By -leech- in forum Windows Programming
    Replies: 8
    Last Post: 01-15-2002, 05:00 PM