-1

I was expecting the do-while loop to end every time I typed in 'n', but it only happens every other time. I have not noticed any patterns within this. I also try to have the loop finish either if the number of points is 0 or less, but this does not seem to work either.

I have been trying this many times, but cannot see where the fault is. Just require some assistance please and thanks.

Here is the problem:

enter image description here

Here is my code:

package highlow;

import java.util.Scanner;

public class Highlow {

    public static void Rules() {
        System.out.println("RULES:");
        System.out.println("Numbers 1-6 are low ");
        System.out.println("Numbers 8-13");
        System.out.println("Number 7 is neither high or low\n\n");
    }

    public static void main(String[] args) {
        int number;
        int gambleAmount;
        int prediction;
        int correctRange;
        int winnings;
        int points;
        int numberOfGuesses = 0;
        String repeat;
        Scanner input = new Scanner(System.in);
        points = 1000;
        System.out.print("High Low Game\n\n");
        Rules();
        do {
            number = (int) (13 * Math.random() + 1);
            if (number > 7) {
                correctRange = 1;
            }
            else if (number < 7) {
                correctRange = 0;
            }
            else {
                correctRange = -1;
            }
            numberOfGuesses += 1;
            System.out.println("You have " + points + " points");
            do {
                System.out.println("Please insert a valid number of points");
                System.out.print("How many points would you like to gamble: ");
                gambleAmount = input.nextInt();
            } while (gambleAmount > points);
            System.out.print("Predict [1=high, 0=low]: ");
            prediction = input.nextInt();
            if (prediction == correctRange) {
                winnings = gambleAmount * 2;
                points = points + winnings;
                System.out.println("The number was " + number);
                System.out.print("You win!\n\n");
            }
            else {
                points = points - gambleAmount;
                System.out.println("The number was " + number);
                System.out.print("You lose\n\n");
            }
            System.out.print("Would you like to play again ('n' for no and 'y' for yes): ");
            repeat = input.next();
        } while (repeat.equals("n") || points != 0);
        System.out.print("You had " + numberOfGuesses + " guesses");
    }
}
Abra
  • 19,142
  • 7
  • 29
  • 41
  • 3
    Beware that things like `nextInt` and `next` will leave a dangling new line character in the buffer, meaning that the next time it attempts to do a `nextXxx`, you're going to get that character instead. Make use of `nextLine` and manually parse the result or use it to clear the new line character – MadProgrammer Apr 05 '23 at 00:08
  • `'n' for no` `repeat.equals("NO")` - I think this will cause a problem. – Scary Wombat Apr 05 '23 at 00:23
  • 3
    So, you have a logic puzzle, which will basically boil down to `false || true` (`!repeat.equals("n") || points > 0`), in this case it will equate to `true`, so you're `do-while` loop will continue. If instead, you changed it to `false && true` it will equate to `false` and the loop will exit ... and yes, my head is still spinning just trying to describe it – MadProgrammer Apr 05 '23 at 00:23
  • @MadProgrammer Only `nextLine` has an issue with dangling token delimiters. Every other method skips delimiters until it finds a valid token. – Tom Apr 05 '23 at 01:10
  • @Tom `nextLine` will read the entire line of text up to the new line token, removing it in the process - in my experience `nextXxx` seems to cause issues with leaving this and causing following `next` statements to be skipped ... but I tend to avoid working with `Scanner` in this way and instead lean towards reading the line from the input then using a seperate parsing workflow which simple ignores all these related issues - but that's me – MadProgrammer Apr 05 '23 at 01:15
  • 1
    @MadProgrammer Neither "next", "nextInt" or "nextFloat" (or any other non-`nextLine` method) will be skipped. You're correct, that those don't read the delimiter after the token, but they don't need to, since they skip such delimiters anyway. Their behaviour is pretty constant and reliable. The issue is `nextLine`. It doesn't follow the usual behaviour of the Scanner class, which is skipping delimiters until it finds a valid token. It only reads up to the next line break, even if the read content is just an empty String. But yes, reading line by line and converting it "manually" is also fine. – Tom Apr 05 '23 at 01:39
  • @Tom *"It only reads up to the next line break, even if the read content is just an empty String"* - sure, but if you do two `nextLine` calls, the second won't be skipped, where as we get SO many "why does is my next input get skipped" questions - which can be solved by simply placing a `nextLine` after the `next` to remove the dangling new line character – MadProgrammer Apr 05 '23 at 01:48
  • @MadProgrammer Yes, this is correct. I just wanted to point out that your first comment is partly correct (it is not every `nextxxx` which has issues, just `nextLine`) and that "causing following `next` statements to be skipped" is incorrect as well. This issue can be confusing to some, so misleading/incorrect information will make it worse. – Tom Apr 05 '23 at 01:58
  • @Tom Yes, observationally, `nextInt` followed by `nextLine` causes `nextLine` to return an empty `String`, which leads to the conclusion that `nextInt` is leaving a dangling new line - so I'm always aware of just clearing the buffer . I don't think `Scanner` is taught well enough for new devs (or old ones like me who grew up without it) – MadProgrammer Apr 05 '23 at 02:07

2 Answers2

0

A do-while loop repeats if the while statement is true.

Consider your loop:

do {
   ...
} while(repeat.equals("n") || points!=0)

Do you really want keep playing when repeat is n or points not equal to zero?

mdsimmo
  • 559
  • 5
  • 16
0

As stated in the comments (and the other answer), your problem is the condition of the [outer] do-while loop in method main of class Highlow. That condition needs to be changed. Firstly, you should check whether the points are greater than zero since the user can't risk points if [s]he doesn't have any. If the user has points, then check whether the answer is "y", i.e. the user wants to play again. Advisable to also ignore the case of the entered answer, i.e. play again if the user entered "Y" or "y". In other words, you repeat the loop if the user has more than zero points and they answered "y". If the user has zero points or if they did not answer "y", exit the loop. Note that this means that you should initialize repeat to "y".

The below code is the code from your question with corrections described above plus other changes that are detailed after the code.

package highlow;

import java.util.InputMismatchException;
import java.util.Random;
import java.util.Scanner;

public class Highlow {
    private static final int FACTOR = 2;
    private static final int HI = 1;
    private static final int INIT = 2;
    private static final int LO = 0;
    private static final int LOSER = 7;
    private static final int LOWER = 1;
    private static final int UPPER = 13;

    public static void rules() {
        System.out.println("RULES:");
        System.out.println("Numbers 1-6 are low ");
        System.out.println("Numbers 8-13");
        System.out.println("Number 7 is neither high or low\n\n");
    }

    public static void main(String[] args) {
        int number;
        int gambleAmount;
        int prediction = INIT;
        int correctRange;
        int winnings;
        int points = 1000;;
        int numberOfGuesses = 0;
        String repeat = "y";
        Scanner input = new Scanner(System.in);
        System.out.print("High Low Game\n\n");
        rules();
        Random rand = new Random();
        do {
            number = rand.nextInt(LOWER, UPPER + 1); // (int) (13 * Math.random() + 1);
            if (number > LOSER) {
                correctRange = 1;
            }
            else if (number < LOSER) {
                correctRange = 0;
            }
            else {
                correctRange = -1;
            }
            System.out.println("You have " + points + " points");
            System.out.printf("Enter points to risk [1 - %d]: ", points);
            try {
                gambleAmount = input.nextInt();
                if (gambleAmount <= 0  ||  gambleAmount > points) {
                    System.out.println("Invalid value. Please re-enter.");
                    continue;
                }
            }
            catch (InputMismatchException x) {
                System.out.println("You did not enter a number. Please re-enter.");
                input.nextLine();
                continue;
            }
            do {
                System.out.print("Predict [1=high, 0=low]: ");
                try {
                    prediction = input.nextInt();
                    if (prediction < LO  ||  prediction > HI) {
                        System.out.println("Invalid prediction. Please re-enter.");
                        continue;
                    }
                }
                catch (InputMismatchException x) {
                    System.out.println("You did not enter a number. Please re-enter.");
                    input.nextLine();
                    continue;
                }
            } while (prediction < LO  ||  prediction > HI);
            numberOfGuesses += 1;
            if (prediction == correctRange) {
                winnings = gambleAmount * FACTOR;
                points += winnings;
                System.out.println("The number was " + number);
                System.out.print("You win!\n\n");
            }
            else {
                points -= gambleAmount;
                System.out.println("The number was " + number);
                System.out.print("You lose.\n\n");
            }
            if (points > 0) {
                System.out.print("Would you like to play again ('n' for no and 'y' for yes): ");
                repeat = input.next();
            }
        } while (points > 0 && "y".equalsIgnoreCase(repeat));
        String plural = numberOfGuesses == 1 ? "" : "es";
        System.out.printf("You had %d guess%s.%n", numberOfGuesses, plural);
    }
}

Although not stated in the problem, the above code checks the validity of values entered by the user. Calling method nextInt will throw InputMismatchException if it reads a value which is not a valid integer. Note that the catch block also calls nextLine. The reason is mentioned in the question comments. Also refer to Scanner is skipping nextLine() after using next() or nextFoo()?

No need for an inner do-while loop to keep asking the user to enter a valid amount of points to risk. Simply repeat the outer loop as that reminds the user how many points they can risk.

However, no need to repeat the entire loop if the user enters an invalid "prediction". Hence the inner do-while loop for getting the user's prediction.

Note that this is just the way I believe the program logic should be. It is not more correct or less correct to do it this way.

numberOfGuesses should be incremented after the user has entered a valid number of points to risk and a valid prediction. It should not be incremented immediately upon entering the [outer] do-while loop.

If the user just lost all their points, then you should quit the [outer] do-while loop, i.e. no point in asking the user if they want to play again when they have no points to risk.

Although this line of code does not cause problems:

repeat = input.next();

consider calling method nextLine instead.
See what happens when the user simply presses ENTER, i.e. does not enter a value. (Same is true for method nextInt, by the way.)

According to Java naming conventions, method names should start with a lower-case letter, hence I changed method Rules to method rules.

Abra
  • 19,142
  • 7
  • 29
  • 41