java codebreaker - loop won't end - java

im trying to make a "codebreaker". User tries to guess random password (4 digit int)
program says if typed password is too low/high/equal. But im stuck, i cant figure out why my loop won't end.
public static void main(String[] args) {
int password = 1234;
startGame(checkNumber(loadNumber(),password));
}
public static void startGame(boolean isAWinner) {
int lives = 5;
do {
loadNumber();
lives--;
} while (lives > 0 || !isAWinner); //has lives or is not a winner
}
public static int loadNumber() {
System.out.println("Type the number");
Scanner scan = new Scanner(System.in);
int givenNumber = scan.nextInt();
return givenNumber;
}
//check if greater,lower or equal
public static boolean checkNumber(int number, int password) {
boolean isAWinner = false;
if (number == password) {
System.out.println("congratulations");
isAWinner = true;
}
if (number > password) {
System.out.println("too much");
}
if (number < password) {
System.out.println("too little");
}
return isAWinner;
}

You need to check your number that is loaded from user input while the game is running and assign the result to isAWinner.
Right now the while loop continues because isAWinner is never assigned a new value after an initial false value.
public static void startGame(boolean isAWinner) {
int lives = 5;
do {
//TODO: run checkNumber on result of loadNumber and assign its result to isAWinner
loadNumber();
lives--;
} while (lives > 0 || !isAWinner); //TODO: has lives AND is not a winner
}
In addition, you will want your loop to continue while lives is greater than zero AND the result is not a winner.

You need to do
do {
isAWinner = checkNumber(loadNumber(), password);
lives--;
} while (lives > 0 && !isAWinner);
Or else !isAWinner will always evaluate to true if it's not correct on the first guess. I also changed the OR to AND so that the loop will break once lives == 0 or isAWinner == True.
Also I would set your password variable outside the main method (as a field of your class), so you can access it inside your startGame method.

Your code forces the user to be correct on the first try. Go through it step by step (you can do this with a debugger and breakpoints, or just mentally with a problem this size).
You call startGame(checkNumber(loadNumber(), password));
The innermost function is called first, which in this case is loadNumber()
Let's assume the user enters an incorrect number (4321 for example)
The next innermost function is called next checkNumber(4321, 1234) which will print "too much" then return false
Now, your outer function is called like this startGame(false) since the checkNumber() function returned a false to it.
It gives you 5 lives, then calls loadNumber()
A new number is loaded, but a function call to check the number is never made!!
This happens until lives hits 0, which is when you expect it to terminate, but your while condition says this: Continue to play the game if the user has lives OR if the user has not won.
Since it isn't possible to win after the first iteration, the second part of the condition will never change after the first initial incorrect guess. You can solve the original question you asked by changing your code to while (lives > 0 && !isAWinner); but you will still have the issue of not having checked any of the answers after the first one.

Related

Java Method Example clarification

I apologize if this question is uber-simplistic, but I'm still in the early stages of learning Java. I have an example program that calls other methods within the class, and I'm not totally following a few of the elements - hoping someone can clarify. It's a simply random number guessing game and it works fine, but I want to better understand some components. Specifically:
There is a boolean variable (validInput) that is declared but never appears to be used anywhere in the methods
There are 2 methods (askForAnotherRound and getGuess) with a 'while' loop that just has 'true' as the variable(?) - i.e. "while (true)."
This code is directly from the example in the book and, again, it works. I just want to better understand those 2 elements above. (I think the validInput variable is not useful as when I 'comment out' that line the code still executes). I'm curious, though, about the "while (true)" element. There is an option to set, in the askForAnotherRound, to set the return value to false (ending the program). Are boolean methods defaulted to 'true' when they are first executed/called?
Again...understand this is probably a super-simple question for most folks on here, but as a newb I just want to understand this as best I can...
Thanks!!!
// Replicates the number guessing game using 4 separate methods.
import java.util.Scanner;
public class GuessingGameMethod2
{
static Scanner sc = new Scanner(System.in);
public static void main(String[] args)
{
System.out.println("Let's play a guessing game!");
do
{
playARound();
}while (askForAnotherRound());
System.out.println("Thanks for playing!");
}
public static void playARound()
{
boolean validInput;
int number, guess;
String answer;
//Pick a Random Number
number = getRandomNumber();
//Get a guess
System.out.println("\nI'm thinking of a number between 1 and 10.");
System.out.print("What do you think it is? ");
guess = getGuess();
//Check the guess
if (guess == number)
System.out.println("You're right!");
else
System.out.println("You're wrong! The number was " + number + ".");
}
public static int getRandomNumber()
{
return (int)(Math.random() * 10) + 1;
}
public static int getGuess()
{
while (true)
{
int guess = sc.nextInt();
if (guess < 1 || guess > 10)
{
System.out.print("I said, between 1 and 10. Try again");
}
else
return guess;
}
}
public static boolean askForAnotherRound()
{
while (true)
{
String answer;
System.out.print("\nPlay again? Y or N: ");
answer = sc.next();
if (answer.equalsIgnoreCase("Y"))
return true;
else if (answer.equalsIgnoreCase("N"))
return false;
}
}
}
I don't see boolean validInput being used either. But if it were to be used somewhere it would probably be to check that you guess satisfies 1 <= guess <= 10.
When it comes to askForAnotherRound and getGuess here's what you should know:
while(true) is always executed. One way you can get out of the while loop is if you use the break statement or if the loop is in a function you can return something. The method askForAnotherRound() will always return either true or false. Depending on the returned value of askForAnotherRound() you will either play another round or not. Note that when you have
`do{
...
someActions()
...
}while(booleanValue)`
someActions() will be executed at least once before it checks for the value of booleanValue which, if it turns out false you'll exit out of the do/while loop. Boolean methods do not default to anything, you have to give them a value.
Hope this helps! I'm also in the process of learning Java right now, so good luck!
As I see you're absolutely true about validInput - it isn't used. May be it will be used in the following chapters.
As for askForAnotherRound() - no, boolean methods don't evalute to true, by default. Even more, Java compiler throw an error if it find a method which does not return value and finish it execution in some cases.
while(true) - it's infinite loop, so it will be executed untill some instruction which interrupts loop, in general it's return statement.
askForAnotherRound() do the following:
- asks user if he/she want to play again
- returns true if user input "Y"
- returns false if user input "Y"
- asks again in all other cases(so it doesn't finish execution) and etc.
Hope it'll help
The validInput is indeed worthless.
The infinite loops are required to read from the console to get a valid input. e.g
while (true)
//start infinite loop
{
int guess = sc.nextInt();
if (guess < 1 || guess > 10)
{
//continue the loop the input is not between 1-10
System.out.print("I said, between 1 and 10. Try again");
}
else
//break out of infinite loop, valid int
return guess;
}
If we take this method without the infinite loop, and i recommend trying this, it will simply return the value read even if it was not valid.
For example.
return sc.nextInt();
will allow any int returned, if we returned anything outside of the bounds in the current impl it would loop again until you enter a value between 1-10
The same is also true for ask for next round, its looping until a valid input is given.
I would bet the next exercises will use the validInput var as both these methods loop until a valid input is given.
You are right about validInput. It is not used. And probably missed after some code change. Should be removed.
while(true) - true is not variable but a boolean constant. It will basically make program run for ever in this case unless somebody kills program. Another alternative would have been to use break to exit out of loop on some condition.

Stuck in a while loop only sometimes

I am having a heck of a time trying to figure out why I can't leave a loop. What I need to do is leave the loop if my Boolean, forward, is set to true. (The Boolean has been set to false above the while loop.
When I run the code snippet below I and enter a positive number I can only enter an unlimited amount a numbers. When I enter a negative number I get one prompt telling me that's not allowed and to try again. After than I am stuck in the similar situation above. It doesn't matter what I enter next it will just keep letting input over and over again.
{
while (forward == false)
if (n2 == 0)
{
System.out.println("Sorry, the 0 is not a valid entry for the second number, try again!");
n2 = in.nextInt();
}
else
{
forward = true;
}
}
You can get away with using no extra variables
n2 = in.nextInt();
while (input == 0){
System.out.println("Sorry, 0 is not valid input");
n2 = in.nextInt();
}
as the forward is a boolean, you can use it directly instead of compare
forward == false.
If you wanna use this variable (I will not go thru the path of the best way achieve your aim), you can do the follow:
while (!forward) {
if (n2 == 0) {
System.out.println("Sorry, the 0 is not a valid entry for the second number, try again!");
n2 = in.nextInt();
} else {
forward = true;
}
}
Do you have an outer while loop that makes you go back into your while loop? An efficient way to solve loop issues is to debug the code a line at a time.
If you are in Eclipse, set a breakpoint (a place where your program will pause) by clicking on the line number just before entering the while loop. Then run the program, and you will see the current line highlighted. Then move line by line by pressing F6 repeatedly. In the bottom pane you can also find the current values of variables.
Now if you inspect your code line by line you will have a better idea of what's going on.

While Loop Not Terminating With Boolean Value Changing

A working example is to have a while loop that continues to get a number from the user until they guess the number correctly, then it will return true and exit out the while loop.
However, if I create a method that returns whether the variable is true or false, the while loop does not terminate. But, if the IF condition is inside the while loop, it terminates and work as intended.
Code that Works as Intended:
private void print() { // Method name not decided yet
boolean playerGuessedCorrectly = false;
while(!playerGuessedCorrectly) {
[...] // Other code that asks the user to enter a new number
// userGuess is the next int entered by the user
// computerNumber is a random number between 1 and 100
if(userGuess == computerNumber) {
System.out.print("You have guessed my number.");
playerGuessedCorrectly = true;
} // while loop terminates upon true
}
}
This code works and the while loop stops working when it is changed to true. However, when I put the same code in a method, the while loop continues going around and does not terminate:
Not Working Code:
private void print() {
boolean playerGuessedCorrectly = false;
while(!playerGuessedCorrectly) {
checkIfGuessIsMyNumber(playerGuessedCorrectly);
} // value of playerGuessedCorrectly is sent to method checkIfGuessIsMyNumber();
private boolean checkIfGuessIsMyNumber(boolean playerGuessedCorrectly) {
// userGuess is the next int entered by the user
// computerNumber is a random number between 1 and 100
if(userGuess == computerNumber) {
System.out.print("You have guessed my number.");
return playerGuessedCorrectly = true;
} else {
playerGuessedCorrectly = false;
}
}
To clarify, the while loop terminates when IF userGuess == computerNumber is inside the while loop, however, it does not work when it is split up into a different method and returns the value.
Note that when I print out the value given by the method, it has printed true. So I am confused to why it doesn't terminate when the value in the method is true, but it terminates with the if condition inside the while loop.
This line:
playerGuessedCorrectly = false;
and this line:
return playerGuessedCorrectly = true;
don't work because Java passes parameters by value. You're actually assigning false to the copy of playerGuessedCorrectly that is local to the checkIfGuessIsMyNumber function, not to the original version in the print function.
Following the not-working code line by line:
boolean playerGuessedCorrectly = false;
This works as intended.
while(!playerGuessedCorrectly) {
// ...
}
This would work as intended if the value of playerGuessedCorrectly was updated properly.
checkIfGuessIsMyNumber(playerGuessedCorrectly);
This is where you go wrong. This copies the value of the currently existing playerGuessedCorrectly variable into the parameter of the checkIfGuessIsMyNumber function. In that function, the new copy of playerGuessedCorrectly is reassigned different values, and you have a return statement, but note that you never actually use the return value of that function. If you instead did something like this:
playerGuessedCorrectly = checkIfGuessIsMyNumber(playerGuessedCorrectly);
your code would work as intended. You would also probably want to clean up the body of your checkIfGuessIsMyNumber function:
if(userGuess == computerNumber) {
System.out.print("You have guessed my number.");
return true;
} else {
return false;
}
Parameters in Java are passed by value. So when you call playerGuessedCorrectly = false, you just override the local copy of the playerGuessedCorrectly parameter.
A different approach to enclose your logic in a function is to have it return the appropriate value:
private void print() {
boolean playerGuessedCorrectly = false;
while(!playerGuessedCorrectly) {
playerGuessedCorrectly = checkIfGuessIsMyNumber();
}
}
private boolean checkIfGuessIsMyNumber() {
// userGuess is the next int entered by the user
// computerNumber is a random number between 1 and 100
if(userGuess == computerNumber) {
System.out.print("You have guessed my number.");
return true;
} else {
return false;
}
}

WHILE repeats before ELSE is evaluated

I've nested an IF ELSE statement inside a WHILE statement, but am confused as to why the WHILE is interpreted before the ELSE (when the IF fails). A user is asked to enter a number from 1-10 (inclusive). If the number is inside that range, the program ends. If it's outside of that range, I want to display an error and then prompt them to again enter a number.
It works well if I put the "prompt" before the WHILE, but then I have to put it again inside the ELSE statement for it to show up again. I found this question, but it didn't appear to answer the issue I'm running into. I'm admittedly a Java novice, so I apologize if I'm missing some fundamental aspect of Java.
import java.util.Scanner;
public class Rangecheck {
private static int userNumber; //Number input by user
private static boolean numberOK = false; //Final check if number is valid
//String that will be reused in the DO statement
private static String enterNumber = "Please enter a number from 1 to 10: ";
public static void main(String[] args) {
//Print string
while(!numberOK) // Repeat until the number is OK
{ System.out.println(enterNumber);
Scanner input_UserNumber = new Scanner(System.in); //input integer
userNumber = input_UserNumber.nextInt();
if (10>= userNumber && userNumber >= 1) //Check if 10>=input>=1
{
/*
** If number was valid, congratulate the user and mark numberOK true
*/
System.out.println("Good job! The number you entered is "+userNumber+".");
numberOK = true; // Congratulate user / exit loop if successful
}
else ; //if (10 < userNumber && userNumber < 1)
{
System.err.println("The number entered was not between 1 and 10!");
System.err.print(enterNumber); // Error; user retries until successful
}
}
}
}
I'd expect the System.err.println() to be evaluated in the else statement and then the whileto be evaluated, so that this gets returned:
The number entered was not between 1 and 10!
Please enter a number between 1 and 10:
I've sort of worked around this by putting enterNumber just before while, then putting a second
println in the else statement immediately following the error. It returns what I expect, but I believe I'm fundamentally misunderstanding something.
Let's suppose you have the following code:
while (whileCondition) {
//Inside while, before if
if (ifCondition) {
//Inside if
} else {
//Inside else
}
}
This cycle will execute repeatedly, until the whileCondition becomes false. Whenever the ifCondition is true, the operations inside if will be executed, otherwise the operations inside else will be executed.
Back to your problem:
Your line of
System.out.println(enterNumber);
is at the start of the while. So before the code even gets to your if, the content of enterNumber is displayed on the console. Later, your if is evaluated and if you enter, let's say 22, the condition given to the if will be false and the content of the else block will be evaluated.
The else statement is repeated before the while statement. There can however sometimes be a problem with Streams. A Stream does not necessarily print the data immediately. Especially in the case one uses two different streams, the order of printing the output data can be interleaved.
You can use:
System.err.flush();
to ensure the data is written to the console first.
Add this statement in else body:
numberOk=false;

Can I manipulate the way that variables change in Java?

If the die shows a 6, the player doesn't move at all on this turn and also forfeits the next turn.
To accomplish this, I have tried an integer type warning marker variable for the player and an integer type time counter variable.
If the die shows 6, I want to increment the warning marker variable by 1 during the first run(and have the while loop do nothing), then keep the value at 1 during the second run (while loop will not work), then lower it back down to 0 for the third run of the while loop (so the while loop will work). The marker will stay at zero unless the die shows a 6 again, after which the same process will repeat.
I have a while loop like this:
while the warning marker is equal to 0 {
Do Stuff
if the die shows a 6, the warning marker increases by 1.
the time counter also increases by 1.
}
How do I manipulate the variables to get the result that I need? Or is my partially complete method absolutely off in terms of logic?
Thanks.
Can u tell me if this works for you?
flag=true;
while condition{
if flag==true{
if die == 6
{
flag=false;
continue;}
}
else { Do STUFF }
} else
{
flag==true;
}
}
I think you want to reword this problem.
This is what I understood. You have a warning marker.
You have a loop that checks whether the marker is 0, if it is then you do something.
If the die is a six, you will increase the warning marker. If its new value is 3, then you will reset it to 0. Meanwhile, the time counter is always increasing.
If this is correct, I think you want something like:
int warningMarker = 0;
int timeMarker = 0;
while (true) {
if (die == 6) {
++warningMarker;
if (warningMarker == 3) {
warningMarker = 0;
}
}
if (warningMarker == 0) {
doSomething();
}
++timeMarker;
}
Java is Object-Oriented Pragramming language. Use this feature.
See following pseudocode and let me know if you have problem in undestanding it.
Create a class Player as following:
class Player
{
boolean skipChance = false;
... // Other fields
... //
}
Change your while as following:
while(isGameOn())
{
Player p = getCurrentPlayer();
if( ! p.skipChance)
{
int val = p.throwDice();
if(val == 6)
{
p.skipChance = true;
continue; // control moves to while.
}
// Do stuff
}
else
{
p.skipChance = false;
}
}

Categories

Resources