Chris L.
Chris L.

Reputation: 55

Java .nextLine() repeats line

Everything of my guessing game is alright, but when it gets to the part of asking the user if he/she wants to play again, it repeats the question twice. However I found out that if I change the input method from nextLine() to next(), it doesn't repeat the question. Why is that?

Here is the input and output:

I'm guessing a number between 1-10
What is your guess? 5
You were wrong. It was 3
Do you want to play again? (Y/N) Do you want to play again? (Y/N) n

Here is the code:(It is in Java) The last do while loop block is the part where it asks the user if he/she wants to play again.

import java.util.Scanner;

public class GuessingGame 
{   
    public static void main(String[] args)
    {
        Scanner input = new Scanner(System.in);
        boolean keepPlaying = true;

        System.out.println("Welcome to the Guessing Game!");

        while (keepPlaying) {
            boolean validInput = true;
            int guess, number;
            String answer;

            number = (int) (Math.random() * 10) + 1;
            System.out.println("I'm guessing a number between 1-10");
            System.out.print("What is your guess? ");
            do {
                validInput = true;
                guess = input.nextInt();
                if (guess < 1 || guess > 10) {
                    validInput = false;
                    System.out.print("That is not a valid input, " +
                            "guess again: ");
                }
            } while(!validInput);
            if (guess == number)
                System.out.println("You guessed correct!");
            if (guess != number)
                System.out.println("You were wrong. It was " + number);
            do {
                validInput = true;
                System.out.print("Do you want to play again? (Y/N) ");
                answer = input.nextLine();
                if (answer.equalsIgnoreCase("y"))
                    keepPlaying = true;
                else if (answer.equalsIgnoreCase("n"))
                    keepPlaying = false;
                else
                    validInput = false;
            } while (!validInput);
        }
    }
}

Upvotes: 5

Views: 2841

Answers (5)

Mario Rossi
Mario Rossi

Reputation: 7799

The problem really lies in a completely different segment of code. When in the previous loop guess = input.nextInt(); is executed, it leaves a newline in the input. Then, when answer = input.nextLine(); is executed in the second loop, there already is a newline waiting to be read and it returns an empty String, which activates the final else and validInput = false; is executed, to repeat the loop (and the question).

One solution is to add an input.nextLine(); before the second loop. Another is to read guess with nextLine() and then parse it into an int. But this complicates things as the input could not be a correct int. On a second thought, the code already presents this issue. Try entering a non-numeric response. So, define a function

public static int safeParseInt(String str) {
    int result;
    try {  
        result= Integer.parseInt(str) ;
    } catch(NumberFormatException ex) {  
      result= -1 ;  
    }  
    return result ;  
}

And then replace your first loop with:

do {
    validInput= true ;
    int guess= safeParseInt( input.nextLine() ) ;
    if( guess < 1 || guess > 10 ) {
        validInput= false ;
        System.out.print("That is not a valid input,  guess again: ");
    }
} while( !validInput );

PS: I don't see any problem with do-while loops. They are part of the language, and the syntax clearly indicates that the condition is evaluated after the body is executed at least one time. We don't need to remove useful parts of the language (at least from practice) just because others could not know them. On the contrary: if we do use them, they will get better known!

Upvotes: 5

Andrew Martin
Andrew Martin

Reputation: 5731

In your do while loop, you don't want the nextLine(), you just want next().

So change this:

answer = input.nextLine();

to this:

answer = input.next();

Note, as others have suggested, you could convert this to a while loop. The reason for this is that do while loops are used when you need to execute a loop at least once, but you don't know how often you need to execute it. Whilst it's certainly doable in this case, something like this would suffice:

System.out.println("Do you want to play again? (Y/N) ");
answer = input.next();
while (!answer.equalsIgnoreCase("y") && !answer.equalsIgnoreCase("n")) {
    System.out.println("That is not valid input. Please enter again");
    answer = input.next();
}

if (answer.equalsIgnoreCase("n"))
    keepPlaying = false;

The while loop keeps looping as long as "y" or "n" (ignoring case) isn't entered. As soon as it is, the loop ends. The if conditional changes the keepPlaying value if necessary, otherwise nothing happens and your outer while loop executes again (thus restarting the program).

Edit: This explains WHY your original code didn't work

I should add, the reason your original statement didn't work was because of your first do while loop. In it, you use:

guess = input.nextInt();

This reads the number off the line, but not the return of the line, meaning when you use:

answer = input.nextLine();

It immediately detects the leftover carriage from the nextInt() statement. If you don't want to use my solution of reading just next() you could swallow that leftover by doing this:

guess = input.nextInt();
input.nextLine();
rest of code as normal...

Upvotes: 7

mihi
mihi

Reputation: 6735

Your problem is that nextInt will stop as soon as the int ends, but leaves the newline in the input buffer. To make your code correctly read the answer, you'd have to enter it on the same line as your guess, like 5SpaceYReturn.

To make it behave more than one would expect, ignore the first nextLine result if it contains only whitespace, and just call nextLine again in that case without printing a message.

Upvotes: 2

Saj
Saj

Reputation: 18702

    validInput = false;

    do {

        System.out.print("Do you want to play again? (Y/N) ");
        answer = input.next();

        if(answer.equalsIgnoreCase("y")){

            keepPlaying = true;
            validInput = true;

        } else if(answer.equalsIgnoreCase("n")) {

            keepPlaying = false;
            validInput = true;

        }        

    } while(!validInput);

I changed the coding style as I find this way more readable.

Upvotes: 4

andersschuller
andersschuller

Reputation: 13907

I believe the output of input.nextLine() will include the newline character at the end of the line, whereas input.next() will not (but the Scanner will stay on the same line). This means the output is never equal to "y" or "n". Try trimming the result:

answer = input.nextLine().trim();

Upvotes: 1

Related Questions