Home > Net >  How to use while loop user input established variable out of scope (if possible)
How to use while loop user input established variable out of scope (if possible)

Time:10-27

I need to ask the user for a number of dice to roll, (at least 1) and then loop if necessary to return a positive integer. Simple question, but I'm new to Java and don't understand how to do this using a while loop and bringing my variable back into scope.

Here's what I have so far, as anyone can see my variable 'numOfDice' is never pulled back into scope, as I need it later in my program to establish a variable array length.

while (true) {
    System.out.println("Hello! How many dice would you like to roll");
    int numOfDice = scan.nextInt();
    if (numOfDice<=0) {
        System.out.println("Please enter a positive integer and try again");
    }else {
        break;
    }

}

So as you can see my variable is never pulled back into scope, and I've tried initializing it before the while loop, with no luck. I've also tried


System.out.println("Hello! How many dice would you like to roll");
int numOfDice = scan.nextInt();
while (true) {
    if (numOfDice<=0) {
        System.out.println("Please enter a positive integer and try again");
    }else {
        break;
    }

}

But this results in an infinite loop if a negative number is an input, as my if will repeat forever. Anyways, I'm very new to Java (my 6th week learning) and any veteran help would be much appreciated. I'm willing to learn new ways to create these loops or tricks to pull variables back into scope (if possible).

Solved. Thanks to tgdavies telling me to split the declaration and assignment I was able to finish this problem. Here's the solution for anyone who stumbles upon this.

  System.out.println("Hello! How many dice would you like to roll");
        int numOfDice;
        numOfDice = scan.nextInt();

        while (true) {
            if (numOfDice <= 0) {
                System.out.println("Please enter a positive integer and try again");
                numOfDice = scan.nextInt();
            } else {
                break;
            }
        }

CodePudding user response:

This is very simple. First you have to declare your variable outside the loop.

int numOfDice = -1; 

Then you need to think of a way to update the state of your variable numOfDice inside the loop. Hence,

numOfDice = sc.nextInt();

Should be inside your loop. Now, the state of your variable numOfDice is updated. After that we can check if the value is a negative or not, and reiterate the loop accordingly.

Hence, the overall code will look like this.

        int numOfDice = -1;     //Declaration - value is negative because the while loop has to be executed at least once.
    Scanner sc = new Scanner(System.in);
    while(numOfDice<=0){    // checks if the variable is negative or positive, loop continues if the value is negative
        System.out.println("Hello! How many dice would you like to roll");
        numOfDice = sc.nextInt();   //updates the state of the variable
        if (numOfDice<=0) {     
            // this line will be printed only if the value is negative.
            System.out.println("Please enter a positive integer and try again");
        }
    }

Hope this answer is helpful. Refer this article to understand more about while loops in java.

CodePudding user response:

Let me start by showing my solution first...

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    System.out.println("Let's start rolling some dice");
    while (true) {
        System.out.println("Hello! How many dice would you like to roll");
        int numOfDice = scan.nextInt();
        if (numOfDice < 0) {
            System.err.println("Please enter a positive integer and try again");
        } else if (numOfDice == 0) {
            System.out.println("Goodbye!");
            break;
        }
    }
    scan.close();
}

As you can see, it is not much of a variation, but it has clear boundaries. For example, you can't have a negative number of dice rolled. So checking for the number of dice to be less than zero (negative) is an error and an appropriate message is shown when that condition is reached.

The second thing you see is a clear case for ending the "forever" loop. And that is when zero is passed through the Scanner object. Not much of an explanation required. Pass zero and simply break out of the loop.

The rest, if a positive integer is passed, keep rolling the dice!


Output sample

Let's start rolling some dice
Hello! How many dice would you like to roll
2
Hello! How many dice would you like to roll
3
Hello! How many dice would you like to roll
9
Hello! How many dice would you like to roll
-3
Please enter a positive integer and try again
Hello! How many dice would you like to roll
-2
Please enter a positive integer and try again
Hello! How many dice would you like to roll
1
Hello! How many dice would you like to roll
3
Hello! How many dice would you like to roll
0
Goodbye!

...to return a positive integer

Sorry for the dramatic heading, but I miss this from the OPs question the first time I read it. The code above keeps rolling until the user enters zero. Let's modify this so that it returns a positive integer.

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    System.out.println("Let's start rolling some dice");
    while (true) {
        System.out.println("Hello! How many dice would you like to roll");
        int numOfDice = scan.nextInt();
        if (numOfDice < 0) {
            System.err.println("Please enter a positive integer and try again");
        } else if (numOfDice == 0) {
            System.out.println("Goodbye!");
            break;
        } else {
            // Add some code here (i.e. a Random generation of dice values 1-6)
            System.out.println("You rolled a "   diceRollValue);
            break;
        }
    }
    scan.close();
}

Variable Scope

Since the OP seems to struggle with issues related to scope, I will expand on this answer to focus on scope. Good coding practices call for minimizing the scope of variables. This means (in theory):

  1. No global variables, period!
  2. Local variables should be declared at the lowest possible block.
  3. Variables shall be declared as close to the point of usage as possible.

Of course, in practice, global variables are often necessary. But what no developer should do is declare global variables by default. Instead, all variables shall be declared at the lowest levels of the code, and then "bubbled up" as needed and stop "bubbling" them up when the desired accessibility is reached. Let's look at an example from this code.

The variable numOfDice is declared inside the while loop. This is the lowest level where this variable can be declared. Since the variable is used at the top of the loop, it is OK to declare it and assign a value in the same line. The question is, should this variable be declared outside the loop? The answer is yes, for a very specific reason.

Creating a "forever" loop while(true){...} may not be a good idea. IN FACT, it can be argued that putting the break condition there might be a better coding practice than to include the break condition inside the loop. So, for this reason (and improving readability of the code as well), we might be better off setting the the variable outside the loop to a value, and then prompt the user to enter the number of rolls inside the loop like this:

System.out.println("Let's start rolling some dice");
int numOfDice = -1;
while (numOfDice != 0) {
    System.out.println("Hello! How many dice would you like to roll");
    int numOfDice = scan.nextInt();
    ...
}

Setting the value to -1 allows the instruction pointer to enter the loop because the evaluation of numOfDice returns true. Once inside the loop, it will continue to iterate until the evaluation returns false; and this is when the user enters 0. In the original code, negative values prompt an error message. Negative and positive values continue the "game". This is perfectly fine. As to the improved readability, when you see while (numOfDice != 0) the intent is clear; much better than to "hide" the break condition inside the loop. If the loop contain a lot of lines of code, the break condition is harder to find. So, in the end, this is a better solution.

An alternative is to use a do...while loop. This is the preferred structure when the intent is for the loop to run at least once. This is possible because the break condition is evaluated at the end of the loop rather than at the beginning in a conventional while loop. The equivalent do...while loop is as follows:

System.out.println("Let's start rolling some dice");
int numOfDice = 0; // initialize to the break condition value (just in case)
do {
    System.out.println("Hello! How many dice would you like to roll");
    int numOfDice = scan.nextInt();
    ...
} while (numOfDice != 0);

The last thing with regards to scope. I mentioned before that variables should be declared as close to the point of usage as possible. This means that instead of this

public void myMethod() {
    int myVariable = 0
    .
    .
    .
    .
    .
    myVariable = someCodeThatSetsValue();
    .
    .
}

You should do this instead to follow best practices

public void myMethod() {
    .
    .
    .
    .
    .
    .
    int myVariable = someCodeThatSetsValue();
    .
    .
}
  • Related