I am in an intro to java class and have we have to create a Mine Sweeper game. I have the game complete for the most part. But I have having 1 issue where my program goes into a crazy infinite loop.
When the user Guesses wrong and hits a "bomb", the game correctly ends. But when they guess correctly and do not hit a bomb, the program enters a infinite loop for some reason and I have to terminate it.
I use 2 2dArrays, one that displays to the player as all '?', and the other that has actual bombs placed on it, that I compare guesses to and update the player board. I feel like the problem is in my GetGuess method. Not sure why this infinite loop only happens the the user makes a correct guess.
The first guess prompt works fine, and if it hits a bomb, the game ends. If the guess is good, the program should ask for another guess, but instead
The infinte loop prints:
Enter row number:
null
over and over again until I terminate. Can anyone help me figure out where this is coming from?
Here is my main and Game class.
public class MineSweeper {
public static void main(String[] args) {
Game test = new Game();
test.loadBombs(test.bombBoard);
test.loadArray(test.board);
test.loadNumber(test.bombBoard);
test.displayBoard(test.board);
test.displayBoard(test.bombBoard);
while(test.gameOver==false)//Continue to get user guess until win or lose
{
test.getGuess(test.board, test.bombBoard);
test.displayBoard(test.board);
}
}
public class Game {
int arrayDimension = 9;
char[][] board = new char[arrayDimension][arrayDimension];
char[][] bombBoard = new char[arrayDimension][arrayDimension];
static boolean gameOver;
public static void getGuess(char[][] boardArray,char[][]bombBoard)
{
int rowGuess = 0, colGuess=0;
Scanner reader = new Scanner(System.in);
//Prompt user guess
boolean valid = false;//Check if guess is valid
while(valid == false)
{
try{
System.out.println("Enter row number: ");
rowGuess= reader.nextInt();
System.out.println("Enter column number: ");
colGuess = reader.nextInt();
if((rowGuess<0||rowGuess>8) && (colGuess<0||colGuess>8))//Check if guess is valid
{
throw new IndexOutOfBoundsException("This row and column is out of bounds!");
}
else if(rowGuess<0 || rowGuess >8)
{
throw new InputMismatchException("Invalid Row Choice!");
}
else if(colGuess<0 || colGuess >8)
{
throw new InputMismatchException("Invalid Column Choice!");
}
else{}
}
catch(Exception e)
{ System.out.println(e.getMessage());
}
if(rowGuess >= 0 && rowGuess<=8) //Guess was valid, place * at location
{
if(colGuess >=0 && colGuess<=8)
{
boardArray[rowGuess][colGuess]= '*';
reader.close();
valid = true;
}
}
}
char answer = bombBoard[rowGuess][colGuess];//check bomb board with user guess
if(answer == '#')//Bomb, you lose
{
boardArray[rowGuess][colGuess]= answer;
System.out.println("You hit a bomb, game over!");
gameOver = true;
}
else//correct guess, Place number of bombs around guess, continue guessing.
{
boardArray[rowGuess][colGuess]= answer;
gameOver = false;
}
}
Additional to the other answers, I'd like to warn you about this code:
if(colGuess >=0 && colGuess<=8) {
boardArray[rowGuess][colGuess]= '*';
reader.close(); // this line is dangerous
valid = true;
}
Here you're closing the current InputStream of System.in. The problem with this is, that it cannot be re-opend by simply calling Scanner reader = new Scanner(System.in); on the next getGuess method call. That means you're unable to retrieve more user input and furthermore a method call on reader can cause a NoSuchElementException.
To fix this, move the Scanner reader variable to the class fields:
public class Game {
// ... other fields
Scanner reader = new Scanner(System.in);
and create a new method that will close this resource if the game is over:
public void finishGame() {
// do other stuff to close the game
reader.close();
}
You can call this method like this:
while(test.gameOver==false)//Continue to get user guess until win or lose
{
test.getGuess(test.board, test.bombBoard);
test.displayBoard(test.board);
}
test.finishGame(); // Game is over, close all resources
In this part of your code
else//correct guess, Place number of bombs around guess, continue guessing.
{
boardArray[rowGuess][colGuess]= answer;
gameOver = false;
}
You want something that will set gameOver to be true when the user has found all of the empty spaces. You should use a variable to keep track of the number of correct guesses the player has made, and if this number plus the number of bombs equals the number of tiles on the board then you want game over to be true. This will exit the outer loop in your test runner class.
Infinite loops mostly happen if you try to read a closed scanner. I would also suggest you keep a refence of it
as an object variable or at least in your main function:
Scanner reader = new Scanner(System.in);
Game test = new Game();
test.loadBombs(test.bombBoard);
test.loadArray(test.board);
test.loadNumber(test.bombBoard);
test.displayBoard(test.board);
test.displayBoard(test.bombBoard);
Hope it helps.
Related
I am just busy with learning Java and my task is making a safecracker game. I need to do this game with classes and methods. But I came to until a point and I can't go further. Below I share my code and my questions. If you could have a look I will be so appreciate.
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
entrance();
playGame();
quitGame();
}
private static void entrance() {
System.out.println("Welcome to the SafeCracker!\nI need your help to open the safe box." +
"\nThe code is with 3 digits and we need to find it out as quick as possible.\nLet's write your guess!");
}
private static int playGame() {
int[] safeCode = {takeRandomSafeCode(), takeRandomSafeCode(), takeRandomSafeCode()};
int guess = takeGuess();
//Below I need to use a for each loop but I don't get the logic of it. I stuck here. I need to check every numbers one by one but how?
for (int safeDigit : safeCode) {
if (safeDigit == guess) {
System.out.println("Your number is correct");
}
}
return playGame(); // with this return type I also have a problem.
If I return this method, it keeps going to play again and again.
But I don't know also which return type I need to give.
}
private static int takeGuess() {
Scanner keyboard = new Scanner(System.in);
int userGuess = keyboard.nextInt();
return userGuess;
}
private static int takeRandomSafeCode() {
Random random = new Random();
int result = random.nextInt(10);
return result;
}
private static int quitGame() {
System.out.println("Do you want to play again?\nPress 1 for play again\nPress 2 for quit the game!");
Scanner key = new Scanner(System.in);
int userWannaPlay = key.nextInt();
if(userWannaPlay == 1) {
System.out.println(playGame());
} else if (userWannaPlay == 2) {
System.out.println(quitGame());
} else {
System.out.println("You entered an invalid number. If you want to play again or quit, you need to click 1 or 2!");
}
return userWannaPlay; //And also quitGame method. I want to ask the users that if they want to play or not and according to answer I would like to run "playGame" method again or quit game.
}
}
Try to use a loop for your game.
You can set quitGame variable from playGame method or you can create a new method for user decision.
public static void main(String [] args){
entrance();
do{
playGame();
}while(!quitGame)
}
public void playGame(){
//Your code is here
}
If I return this method, it keeps going to play again and again. But I
don't know also which return type I need to give.
Your playGame*( method calls itself recursively in its last line return playGame(). I guess you did that to return anything at all. If you think about your problem you may come to the conclusion that you don't want to return anything at all (as you do not know what to do with it). In this case you may return nothing aka void as you did in your main method.
And also quitGame method. I want to ask the users that if they want
to play or not and according to answer I would like to run "playGame"
method again or quit game
You have to think about what you want. You want to call a method again and again depending on a condition. For that you can either use a loop or recursion. For exmaple you could change you main method slightly and add a do-while-loop.
public static void main(String[] args) {
entrance();
int condition;
do {
playGame();
condition = quitGame();
} while (condition == 1);
Don't forget to change you quitGame method because there you are trying to solve your problem recursively (remove the if clause). If you want to do it recursively though ignore the above and look at this snippet:
private static int quitGame() {
System.out.println("Do you want to play again?\nPress 1 for play again\nPress 2 for quit the game!");
Scanner key = new Scanner(System.in);
int userWannaPlay = key.nextInt();
if(userWannaPlay == 1) {
playGame(); // you dont need a println here
} else if (userWannaPlay == 2) {
// you dont need to anything here
System.out.println("Quitting...");
} else {
System.out.println("You entered an invalid number. If you want to play again or quit, you need to click 1 or 2!");
// call quitGame again to ask for the choice again
quitGame();
}
return userWannaPlay; // if you do it like this, this return is also unnecessary and you could use a void method without returning anything
}
This is the basic setup for a little console-based quiz game. The answers are numbered. I want the player to give the answer number. If the input is not a number, then my program should give a warning, and wait for proper input.
Instead, what I get (after inserting something that is not a number) is an infinite loop of asking the question and presenting the answers again.
public static void main(String[] args) {
boolean quizActive = true;
while(quizActive) {
presentQuestion();
presentAnswers();
Scanner s = new Scanner(System.in);
if (s.hasNext()) {
String choice = s.next();
if (!NumberUtils.isNumber(choice)) {
presentText("Please insert the answer number.");
} else {
System.out.println("You made a choice!");
checkAnswer(choice);
quizActive = false;
}
s.close();
}
}
}
What am I doing wrong here?
If you do not want to question and answers be presented each time move presentQuestion() and presentAnswers() outside the loop.
But main problem is that you closing Scanner.
Remove s.close(); and move Scanner s = new Scanner(System.in); outside of the loop.
I really don't get the point in using scanner for acquiring user input.
The scanner class is perfect to process structured input from a flat file with known structure like an CSV.
But user input need to deal with all the human imperfection. After all the only advantage you get is not needing to call Integer.parseInt() your yourself at the cost to deal with the not cleared input when scanne.nextInt() fails...
So why not using InputStreamReader aside with a loop suggested by others?
Here an Example :
public class Application {
public static void main(String [] args) {
System.out.println("Please insert the answer number. ");
while (true) {
try {
Scanner in = new Scanner(System.in);
int choice = in.nextInt();
System.out.println("You made a choice!");
checkAnswer(choice);
break;
} catch (Exception e) {
System.out.println("Invalid Number, Please insert the answer number ");
}
}
}
}
You started your Quiz in a loop which is regulated by your quizActive boolean. That means that your methods presentQuestion() and presentAnswers() get called every time the loop starts again.
If you don't input a number but a character for example, your program will run the presentText("Please insert the answer number.") and start the loop again. As it starts the loop again, it will call the methods presentQuestion() and presentAnswers().
To stop that, you can do another loop around the input-sequence. Also your Scanner s = new Scanner(System.in) should be outside the loop. And you shouldn't close your Scanner right after the first input and then open it again!
if you want a code example, please tell me :)
I am working on a java program. Right now everything is totally working, and all my functionality is there. However, the part I am stuck on is how to exit out of the program in a do-while loop. I must be getting the syntax wrong.
Basically, I set a switch done which reacts to a user's input. Right now, it's working and loops through the program, but it does not exit if I say "no" to continuing.
Here is the part of the code this is happening:
public void main() {
String userInput;
boolean done = true;
Scanner keyboard = new Scanner(System.in);
do {
System.out.println("Welcome to Hangman!");
System.out.println("Do you want to play?");
userInput = keyboard.next();
if (userInput.equals("Yes") || userInput.equals("yes") || userInput.equals("y") || userInput.equals("Y")) {
done = false;
} else if (userInput.equals("n") || userInput.equals("no") || userInput.equals("NO") || userInput.equals("No")) {
done = true;
}
while (!done) {
System.out.println(getDisguisedWord());
System.out.println("Guess a letter: ");
String guess = keyboard.next();
makeGuess(guess);
if (gameOver()) {
String ui;
System.out.println("Do you want to play again?");
ui = keyboard.next();
if (ui.equals("Yes") || ui.equals("yes") || ui.equals("y") || ui.equals("Y")) {
done = false;
} else {
done = true;
}
}
}
} while(done);
}
any tips on how I could handle this better?
Your problem isn't what you think it is. To compare Strings, you need to use their built-in equals() method: ui.equals("Y"). Using == to compare them will always return false. For more information, see How do I compare strings in Java?.
Also, you need to flip your done = true and done = false statements (if the user says yes to playing again, they aren't done yet).
Finally, I would recommend changing your keyboard.next() calls to keyboard.nextLine() calls, or else you may run into weird issues, especially if the user enters input that includes whitespace.
EDIT: I noticed some more issues. You're while loop should be while(!done) instead of while(done). Also, I would get rid of your do-while loop, because the while loop is already allowing the user to play as many times as they want, so it is unnecessary.
boolean flag = true;
Scanner sc = new Scanner(System.in);
do{
System.out.println("***********************************************************");
System.out.println("Welcome to the School Admissions App !!! Press X for exit");
System.out.println("***********************************************************");
System.out.println("Enter the Student Name: ");
String student_name=sc.next();
System.out.println("press y to use this application again. press x to exit from this application ");
String input_user=sc.next();
if(input_user.equalsIgnoreCase("y")){
flag=true;
}else{
flag=false;
System.out.println("Thanks for using it.");
}
}while(flag);
U should use equals method for comparing string value in if statment. ui.equals("yes").
public void talk() {
String[] prompts = {"Describe to me in a sentence why this is a cool program.",
"Describe to me in a sentence how your day was.",
"Describe to me in a sentence what programming means to you.",
"Describe to me in a sentence why food is neccessary for humans."};
iramInLoop = true;
while(iramInLoop)
{
int i = new Random().nextInt(prompts.length);
System.out.println(prompts[i]);
String input = Raybot.getInput();
if(!checkPunc(input) && !checkCaps(input)){
System.out.println("Check your capitalization and your punctuation!");
}
else{
System.out.println("Great grammar keep it up! Do you want to try again?");
if(input.equals("yes")) continue;
else
{
iramInLoop = false;
Raybot.talkForever();//this exits the loop
}
}
}
}
I am having extreme trouble trying to restart my loop. So at the end of my code when the loop is done running I put a string which asks if the user wants to try again and if the user says yes I want it to go back to the beginning of the loop and do what the loop does again. However, every time I run it it goes to the end of the loop and doesn't even ask for an input.
I think you should be breaking out of the loop if the person guessed right, but then decided not to continue. In this case, your logic should be something like this:
while (true) {
int i = new Random().nextInt(prompts.length);
System.out.println(prompts[i]);
String input = Raybot.getInput();
if (!checkPunc(input) && !checkCaps(input)) {
System.out.println("Check your capitalization and your punctuation!");
}
else {
System.out.println("Great grammar keep it up! Do you want to try again?");
input = Raybot.getInput();
if (input.equals("no")) {
break;
}
}
}
// whatever this does, you intended for it happen after the loop terminates, so do it here
Raybot.talkForever();
You are missing to actually accept any input
maybe
System.out.println("Great grammar keep it up! Do you want to try again?");
input = Raybot.getInput();
change if(input.equals("yes")) continue;
to if(Raybot.getInput().equals("yes")) continue;
Scanner choice = new Scanner(System.in);
while(!choice.hasNextInt()) {
System.out.println("Invalid input");
choice.next();
}
// Carry out appropriate method relating to user choice
boolean done = false; // Loop is not finished
while (!done) {
int i = choice.nextInt(); // Save the user's choice as int i
/*
* A switch statement here would probably be more elegant but this works too
* Problem: If the user inputs a non-integer number e.g. 2.3 the program explodes :(
*/
if (i == 1) {
newGame(); // Call newGame method
} else if (i == 2) {
playGame(); // Call playGame method
} else if (i == 3) {
viewResults(); // Call viewResults method
} else if (i == 4) {
done = true; // If user quits, the loop is done
quitGame(); // Call quitGame method
} else {
System.out.println("Invalid input");
}
}
The only valid input for this needs to be the numbers 1, 2, 3 and 4. If I enter a string it doesn't accept it. If i enter a number larger than 4 it doesn't accept it. However if I was to enter 2.3 or something the program crashes. I can't see what it causing this as 2.3 is not an integer and I don't know how it gets past the hasNextInt() method in Scanner. Anyone shed some light?
For input 2., first int is 2, so playGame() is executed but done is still false so because of the while(!done) loop choice.nextInt() is called again on . which is not an int.
Hence the exception.
You only check that choice.hasNextInt() for the first input. The second time round it is not checked. Move the check into the while loop so that it looks like this:
boolean done = false;
while (!done) {
while(!choice.hasNextInt()) {
System.out.println("Invalid input");
choice.nextLine(); // drop entire line, not just next token
}
int i = choice.nextInt();
// ...
}