Infinite do/while loop in Java. Please advise - java

I'm new here, and to code in general. What I'm trying to accomplish is to create a simple guessing game that prompts a user for a number, and checks that number against a computer generated number between 1 and 100. I've tried to make it so the player can continue guessing until they get the correct answer, as well as display a counter to let the player know how many guessing attempts they have made. The problem is, the program won't terminate after the correct answer has been given, and I can't figure out what I'm doing wrong. I'll paste the entire code at the bottom for reference, but I feel like the problem lies within the following statement in the "determineAnswer" method:
} else if (userAnswer == computerNumber) {
message = "Correct"
+ "\nNumber of Guesses: " + count;
success++;
I'm trying to use the value of the integer "success" as the condition to terminate the do/while loop, but even though I try to increment the value, the loop continues as if the value is being continuously reset. If that's the case, I can't see where I've gone wrong. Again, I'm quite new at this but I would appreciate any input.
import javax.swing.JOptionPane;
public class GuessingGame {
public static void main(String[] args) {
// generate a random number from 1 to 100
int computerNumber = (int) (Math.random() * 100 + 1);
// declare other variables
int success = 0;
int count = 0;
// display the correct guess for testing purposes
System.out.println("The correct guess would be " + computerNumber);
// prompt user for a guess
do {
count++;
String response = JOptionPane.showInputDialog(null,
"Enter a guess between 1 and 100");
int userAnswer = Integer.parseInt(response);
// display result
JOptionPane.showMessageDialog(null, determineGuess(userAnswer, computerNumber, success, count));
} while (success == 0);
}
public static String determineGuess(int userAnswer, int computerNumber,int success, int count) {
String message = null;
if (userAnswer <= 0 || userAnswer > 100) {
message = "Invalid guess"
+ "\nNumber of Guesses: " + count;
} else if (userAnswer == computerNumber) {
message = "Correct"
+ "\nNumber of Guesses: " + count;
success++;
} else if (userAnswer > computerNumber) {
message = "Incorrect, Too High"
+ "\nNumber of Guesses: " + count;
} else if (userAnswer < computerNumber) {
message = "Incorrect, Too Low"
+ "\nNumber of Guesses: " + count;
}
return message;
}
}

You do not update the value of success and every time the loop runs, it will be getting success value as 0 and thus it is causing infinite loop.
int success = 0;
int count = 0;
// display the correct guess for testing purposes
System.out.println("The correct guess would be " + computerNumber);
// prompt user for a guess
do {
count++;
String response = JOptionPane.showInputDialog(null,
"Enter a guess between 1 and 100");
int userAnswer = Integer.parseInt(response);
// display result
JOptionPane.showMessageDialog(null, determineGuess(userAnswer, computerNumber, success, count));
success=1;
} while (success == 0);

In Java everything is pass by value.
In this case have passed primitive (int) to method and then changing its value and expecting same to reflect in calling method. Java doesn't work like that
public class SuccessTest {
public static void main(String[] args) {
int success = 0;
updateSuccess(success);
System.out.println(success); //will print 0
}
private static void updateSuccess(int success) {
//changing value of success here will not reflect in main method
success=2;
System.out.println(success);//will print 2
}
}
In order to make this work declare success as class level variable
private static int success = 0;
then no need to pass this success to determineGuess method, now if you update value of success in determineGuess method it will be available in main method

The reason that the success variable is not being updated in the main method is that it does not have access to any changes to the determineGuess method's success variable. They are two separate variables in separate scopes.
determineGuess receives success as an int method parameter. In Java, types such as int, char and float are pass-by-value: this means that the value is essentially copied when it is given to a method or set as a variable, so that if you modify the copied value, the original one is not modified. (actually, all types are pass-by-value, but the contents of an object is by reference).
There are a few ways of updating the success variable for the main method, two of which are:
Make success a field in the class, that way it is accessible by all methods in the class. Because you are doing all of this in main, for now you will need success to be static: private static int success = 0;. A better way can be to make everything non-static, and have main instantiate a GuessingGame object and then call a run method on it.
Return a value from determineGuess that will let you know what category the answer fits into: success, incorrect, too high or too low. You would then have a second method that uses this output to select the message to display. If main sees that the output is success, it updates its success variable. This might be better, but is more involved.
For this simple example, I suggest option 1. In fact, because you only check for one success, the success variable can just be a boolean value. This would make your code the following (with modifications):
import javax.swing.JOptionPane;
public class GuessingGame {
// Determines whether the user has successfully guessed the number
private static boolean success = false;
public static void main(String[] args) {
// Generate a random integer between 1 and 100 inclusive
int computerNumber = (int) (Math.random() * 100 + 1);
// Count the number of guesses that the user makes, to report it to them
int count = 0;
// FIXME: only for testing purposes, remove this
System.out.println("The correct guess would be " + computerNumber);
do {
count++;
String response = JOptionPane.showInputDialog(null, "Enter a guess between 1 and 100");
int userAnswer = Integer.parseInt(response);
JOptionPane.showMessageDialog(null, determineGuess(userAnswer, computerNumber, count));
} while (!success);
}
public static String determineGuess(int userAnswer, int computerNumber, int count) {
if (userAnswer <= 0 || userAnswer > 100) {
return "Invalid guess\nNumber of Guesses: " + count;
} else if (userAnswer == computerNumber) {
success = true;
return "Correct\nNumber of Guesses: " + count;
} else if (userAnswer > computerNumber) {
return "Incorrect, Too High\nNumber of Guesses: " + count;
} else if (userAnswer < computerNumber) {
return "Incorrect, Too Low\nNumber of Guesses: " + count;
}
return null;
}
}
If you were to go with option 2, then you might have an enum GuessOutcome { INCORRECT, SUCCESS, TOO_LOW, TOO_HIGH } that you return from determineGuess. You would then have a getOutcomeMessage(GuessOutcome outcome) method with a switch (outcome) { ... } to select which message to display. If outcome == GuessOutcome.SUCCESS, then success = true. In this version, success can be a local variable to main.

Related

Simple method for taking in an int, checking if it falls in a min/max, and returning that value.. not able to break out of method

I'm fairly new to java and I'm trying to make a simple method in a class that returns a user integer as long as it falls within certain boundaries. It seems to check the input correctly, but after that, it doesn't exit the method. Here is the method:
public int readInt(String prompt, int min, int max) {
int userInt;
boolean works = true;
System.out.println(prompt);
userInt = inputReader.nextInt();
inputReader.nextLine();
while(works = true) {
if (userInt >= min && userInt <= max) {
works = false;
} else {
System.out.println("Please enter value between " + min + " and " + max);
userInt = inputReader.nextInt();
inputReader.nextLine();
}
}
return userInt;
}
And here is the main method. Running the method and just trying to print the int back out after. Never gets to the sout line.
public static void main(String[] args) {
UserIO userIO = new UserIOImpl();
int userInt;
userInt = userIO.readInt("Please enter a number between 1 and 10", 1, 10);
System.out.println(userInt);
}
Any help in the right direction is greatly appreciated.
Edit: I'm currently using NetBeans 12.0
Instead of "while(works = true)" make "while(works)"

-Roll 2 Dices until gets SnakeEyes- What's wrong with my logic and how to print the last result of a method without caling it again

This is a homework in which I have to code 2 dices that roll constantly and only stop when both gets SnakeEyes. I'm having 2 issues:
Sometimes the CastDie1 and CastDie2 returns 1 but the IF statement doesn't validate the condition.
I want to print out every result, including the Snake Eyes, but whenever I try to print the SnakeEyes result, the method gets called again and the numbers change.
public class SnakeEyesCount {
/**
* #param args the command line arguments
* #return
*/
public static int CastDie1() {
int die1 = (int)(Math.random()*6)+1;
return die1;
}
public static int CastDie2() {
int die2 = (int)(Math.random()*6)+1;
return die2;
}
public static void main(String[] args) {
// TODO code application logic here
int countSnakeEyes = 0;
boolean snakeEyes = false;
while (snakeEyes == false) {
TextIO.putln("Die1: " + CastDie1());
TextIO.putln("Die2: " + CastDie2());
countSnakeEyes++;
if (CastDie1() == 1 && CastDie2() == 1) {
TextIO.putln("Die1: " + CastDie1() + " SNAKE EYES!");
TextIO.putln("Die2: " + CastDie2() + " SNAKE EYES!");
TextIO.putln("Snake Eyes after " + countSnakeEyes + " rolls of the dice");
snakeEyes= true;
}
}
}
}
You call CastDie1 and CastDie2 twice. Since the result is random you're not guaranteed to get the same value in consecutive executions.
Call the method once, and store the result in a variable to be printed off and used otherwise.
while(!snakeEyes) {
int die1 = CastDie1();
int die2 = CastDie2();
TextIO.putln("Die1: " + die1);
// and so forth
if(die1 == 1 && die2 == 1) {
// the rest of your logic
}
}
While I respect that having two distinct methods to invoke for die is what you want, they do the same thing so I would encourage you to collapse this down to a single method: castDie. I leave this as an exercise for the reader.
Store the result of your method call in a variable. Print the value of the variables, then check if it's snake eyes.
Also, there is no need to have two separate CastDie methods; they do the same thing.

Error: Cannot find symbol when passing and returning variables

Rookie mistake?
Hello, I'm a first-year computer science student and I keep getting cannot find symbol errors. I declared the variable in the main method, passed it to another method, modified it, and then returned it. For some reason, the compiler cannot find the symbols result, input, and points. I'm sure it's the same reason for all of them. Any help would be appreciated.
public class Fishing
{
public static void main(String[] args)
{
do
{
String input; //Holds user input
int points; // Holds player's points
int score = 0; // Sets player's score to 0
final int DIE_SIDES = 6; // # of sides for the die
//Create an instance of the Die class
Die die = new Die(DIE_SIDES);
//Roll the die once and store value in result
die.roll();
int result = die.getValue();
getScore(points, result);
String input = getInput();
//Keeps running total of player's score
score = score + points;
} while (input == "yes");
System.out.print(0);
}
/**
The getScore method will calculate the player's score
depending on what the player rolled. It will also show
a message and return the score.
#return A reference to an integer object containing
the player's score for one roll.
*/
public static int getScore(int points, int result)
{
if (result == 1)
{
JOptionPane.showMessageDialog(null, "Waaaaahhhhh, you have caught " +
"a shark. Sharks are dangerous. You " +
"have been awarded zero points.");
points = 0;
return points;
}
else if (result == 2)
{
JOptionPane.showMessageDialog(null, "You have caught a jellyfish. " +
"This beautiful creature has awarded you " +
"50 points!!");
points = 50;
return points;
}
else if (result == 3)
{
JOptionPane.showMessageDialog(null, "You have caught an old boot. " +
"Maybe you can sell this old boot after it " +
"dries out. You have been awarded 1 point.");
points = 1;
return points;
}
else if (result == 4)
{
JOptionPane.showMessageDialog(null, "You have caught an Alaskan salmon. " +
"This delicious and popular fish has awarded you " +
"75 points!!!");
points = 75;
return points;
}
else if (result == 5)
{
JOptionPane.showMessageDialog(null, "You have caught a small fish. You " +
"have been awarded 20 points!");
points = 20;
return points;
}
else
{
JOptionPane.showMessageDialog(null, "You have caught a treasure chest!! " +
"It is filled with shining pieces of gold, and " +
"you have been awarded 100 points!!!!");
points = 100;
return points;
}
}
/**
The getInput method will receive the user's input
and return it to the main method.
#return A reference to a String input value containing
the user's response.
*/
public static String getInput()
{
//Prompt user to enter response
response = JOptionPane.showInputDialog("Would you like to play another " +
"round of fishing? Enter yes or no.");
return response;
}
}
We need to make the following changes:
Result is declared in main() method and hence, it is local to main() only. getScore has no knowledge of it. If we want to access result, input and points in getScore() method then we need to pass all of them to getScore().
getInput() returns an input. So, we don't need to pass any argument to it. We can change getInput(String response) to getInput() and modify main() so that value returned by getInput() is assigned to input variable (input = getInput();)
Here are some basics of parameter passing in java. I would recommend going through it.

Having trouble with validation: infinite loop occurs even though the logic seems fine

I am working on this 'restaurant' program, that takes two inputs: the bill amount and a satisfactionlevel from 1 to 3. I have tried to validate each output using the hasNextDouble(), but for some reason when i run the program the else statement in the first if statement runs infinitly. Can someone please take a look at this?
package tips;
import java.util.Scanner;
public class Tips {
public static void main(String[] args) {
/* Ask for the diners’ satisfaction level using these ratings:
1 = Totally satisfied, 2 = Satisfied, 3 = Dissatisfied.
If the diner is totally satisfied, calculate a 20 percent tip.
If the diner is satisfied, calculate a 15 percent tip.
If the diner is dissatisfied, calculate a 10 percent tip.
Report the satisfaction level and tip in dollars and cents.*/
Scanner in = new Scanner(System.in);
boolean isDouble = false;
boolean isInt = false;
TipsCalculator tips = new TipsCalculator();
while (!isDouble && !isInt) {
System.out.print("Please enter the bill amount: ");
//Checks if the input is a double.
if(in.hasNextDouble()) {
tips.setBill(in.nextDouble());
isDouble = true;
} else {
System.out.println("The value entered is not a valid amount.");
continue;
}
System.out.println("Please enter your satisfaction level: \n1 = Totally Satisfied.\n2 = Satisfied.\n3 = Dissatisfied.");
//Checks if the input is an integer.
if(in.hasNextInt()) {
tips.setSatisfactionLevel(in.nextInt());
isInt = true;
//Prints different outputs depending on the satisfaction level.
if (tips.getSatisfactionLevel() == 1) {
System.out.println("You are totally satisfied! :-)" +
". \n" +
"Your tip amount is: " +
tips.calculateTips());
} else if (tips.getSatisfactionLevel() == 2){
System.out.println("You are satisfied! :-)" +
". \n" +
"Your tip amount is: " +
tips.calculateTips());
} else if (tips.getSatisfactionLevel() == 3) {
System.out.println("You are dissatisfied! :-(" +
". \n" +
"Your tip amount is: " +
tips.calculateTips());
} else {
//Error if the level is not from 1 to 3.
System.out.println("The value entered is not between 1 and 3");
}
} else {
System.out.println("The value entered is not between 1 and 3");
continue;
}
} in.close();
}
}
isDoubl & isInt both are false so !isDouble && !isInt will be always true. This is the root cause behind infinite loop
Don't read input as double and int. read it as Strings and then parse it to Double or Integer in your code. Use method valueOf(String) in classes Integer and Double. to parse your Strings
Reason for infinite loop is:
hasNextDouble method in Scanner class calls hasNext method internally.
It has written like this
public boolean hasNext(Pattern pattern) {
ensureOpen();
if (pattern == null)
throw new NullPointerException();
hasNextPattern = null;
saveState();
while (true) {
if (getCompleteTokenInBuffer(pattern) != null) {
matchValid = true;
cacheResult();
return revertState(true);
}
if (needInput)
readInput();
else
return revertState(false);
}
}
In the above method, getCompleteTokenInBuffer method call is the real culprit. This getCompleteTokenInBuffer can return following 3 possibilities
/*
* 1. valid string means it was found
* 2. null with needInput=false means we won't ever find it
* 3. null with needInput=true means try again after readInput
*/
In hasNext mthod, whenever we first enter non double value, we will be able to read data and getCompleteTokenInBuffer returns null and will also set needInput=false for the first time. But, for the second time, hasNext method will return with value false as needInput=false condition will be true.
This needInput = false condition will remain true for the subsequent hasNextDouble method call. Because of this we were not able to read any data and this was causing infinite loop.

Return value executing a method?

import java.util.*;
public class Guess {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
Random r = new Random();
intro();
int numGames = 0;
int numGuesses = game(console, r);
int max = max(numGuesses);
String again = "y";
do {
game(console, r);
System.out.println("Do you want to play again?");
again = console.next();
System.out.println();
numGames++;
} while (again.startsWith("y") || again.startsWith("Y"));
stats(numGames, numGuesses, max);
}
public static void intro() {...}
public static int game(Scanner console, Random r) {
System.out.println("I'm thinking of a number between 1 and 100...");
int answer = r.nextInt(100) + 1;
System.out.println("answer = " + answer);
int guess = -1;
int numGuesses = 0;
while (answer != guess) {
System.out.print("Your guess? ");
guess = console.nextInt();
numGuesses++;
if (guess > answer) {
System.out.println("It's lower.");
} else if (guess < answer) {
System.out.println("It's higher.");
} else {
System.out.println("You got it right in " + numGuesses + " guesses");
}
max(numGuesses);
}
return numGuesses;
}
public static int max(int numGuesses) {
int max = numGuesses;
if (max > numGuesses) {
max = numGuesses;
}
return max;
}
public static void stats(int numGames, int numGuesses, int max) {
System.out.println("Overall results:");
System.out.println(" total games = " + numGames);
System.out.println(" total guesses = " + numGuesses);
System.out.println(" guesses/game = " + numGuesses / numGames / 1.0);
System.out.println(" best game = " + max);
}
}
So this is a small part of my program and the problem I'm having is that my initial int for numGuesses (int numGuesses = game(console, r);) is executing the game method shown below.
All I want from the game method is the return value of numGuesses so that I can forward the value into a different method called stats(numGames, numGuesses, max); . How do I make it so that the initial value isn't executing the method and only the do/while loop is?
Is the way I produce a return statement wrong? Also, my return values aren't saving in my stats method so when I run it, I get the wrong answers.
Then you should put the code that's responsible of generating numGuesses in another method that you will use on both main and game, for example:
public static int game(Scanner console, Random r) {
int numGuesses = getNumberOfGuesses(..);
//continue implementation here
}
public static void main(String[] args) {
int numGuesses = getNumberOfGuesses(..);
//use value
}
You should get familiar with class variables. At the top of your class, you can declare a variable and also give it a value. That is what you should do with numGuesses if you want to access it from different methods in your class. Here is the Foobar example:
class Foo {
private int bar = 0;
private void foobar(int arg) {...}
}
You just need to watch out that you don't do int numGuesses somewehere in a method as that would create a second local variable. The class variable can be accessed via just the name.
Next, you want to keep track of the total games played and the total guesses. You can guess now (hahaha), that you need to use class variables as well. If you need to keep track of the total guesses even when the program is restarted you will need to store these values in a file, but that will be for another time.
Finally, two more little things.
1.) The method max. I do not know what max should do, but at the moment it is just returning the value passed to it. Also the if statement will never execute (x can't be higher than x).
2.) You should maybe consider not making everything static. It obviously works that way, but that is not, what is called object-oriented programming.

Categories

Resources