Removing a method call from the stack - java

suppose I have a game with a text interface. Now, when starting the game the player needs to tell the game their age.
public void getAge() {
System.out.println("Please enter your age");
int age;
try {
Scanner sc = new Scanner(System.in);
age = sc.nextInt();
} catch (InputMismatchException e) {
System.out.println("You made a mistake. Let's start this over!");
getAge();
}
gameLoop(age);
}
Suppose the user makes 100 errors, and the method is called over and over again. Do the 100 calls stay on the call stack? Is there any way to remove them, perhaps by returning a value instead?
Is this a memory leak (although small)?
Anyway, I would like to hear your thoughts, on how this could be improved.

Try a loop (Just pseudocode)
bool done = false;
while (!done)
{
try {
// Get the age
if (valid) { done = true; }
}
catch { // ...
// Handle the exception make sure done is still false
}
} // End while

Related

Trying to validate a passed value to a method

I have a program that is trying to validate a passed value. I want a user to input anything and the method that I pass it to will validate whether the input would work.
This is my code:
public static void main(String[]args) {
Scanner input = new Scanner(System.in);
ChequingAccount a = new ChequingAccount();
double deposit = inputCheck("Enter deposit amount: ", input);
a.setDeposit(deposit);
}
public static double inputCheck(String prompt, Scanner input) {
boolean userValid = false;
do {
System.out.print(prompt);
double user;
try {
user = input.nextDouble();
if (user < 0) {
throw new IllegalArgumentException("Value cannot be lower than 0");
}
userValid = true;
} catch (InputMismatchException e) {
System.out.println("The value entered is not a number");
user = inputCheck(prompt, input);
input.nextLine();
} catch (IllegalArgumentException ex) {
System.out.println(ex.getMessage());
user = inputCheck(prompt, input);
}
return user;
} while (!userValid);
}
The code works except for the fact that when the method catches the InputMismatchException, the code then will loop a bunch of times and breaks the program. I thought adding a doWhile loop would solve the issue but it didn't do anything.
you don't need a loop , you need recursion
public static double inputCheck(String prompt, Scanner input) {
double user;
try {
user = input.nextDouble();
if (user < 0) {
throw new IllegalArgumentException("Value cannot be lower than 0");
}
return user;
} catch (InputMismatchException e) {
System.out.println("The value entered is not a number");
return inputCheck(prompt, input);
} catch (IllegalArgumentException ex) {
System.out.println(ex.getMessage());
return inputCheck(prompt, input);
}
}
You're calling your own method from inside; the inputCheck method's code calls inputCheck. This is a somewhat creative way to write a loop.
You also have... a loop.
So you 2 loops, to do the job that one loop should do. That's why all heck breaks loose here. Pick one: Either use the do/while construct (so do not call yourself), or, don't loop, and call yourself. Either one can be made to work here.
The nextLine stuff is irrelevant and not the problem here (in general don't call that; just set the delimiter properly; call scanner.useDelimiter("\\r?\\n") and to get entire lines, use next(), not nextLine().
There are number of approaches that can work for this – iteration, recursion, exception catching, etc. Your solution is mixing several of them together which makes it harder to understand and also harder to fix.
Here is an example that uses a simple while loop, no recursion, no exception catching. It uses hasNextDouble() and, depending on the result, either proceeds to capture the double (by calling nextDouble()), or prints a message (along with consuming and ignoring whatever non-double token is present by calling next()).
public static double inputCheck(String prompt, Scanner input) {
while (true) {
System.out.print(prompt);
if (input.hasNextDouble()) {
double number = input.nextDouble();
if (number < 0) {
System.out.println("Value cannot be lower than 0. Please try again.");
} else {
return number;
}
} else {
System.out.println("The value entered is not a number. Please try again.");
input.next(); // consume and ignore whatever non-double input is waiting on the scanner
}
}
}

Working with methods for a safecracker game

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
}

java simple UI loop, can't find bug

I've written the UI class below and it's basically just a simple loop that calls a couple of methods in the class, console based ui.
The user is supposed to be able to select from 1 of 6 menu choices. Now, the selection input from the user must be of type int. I surrounded the selection code with a try {} catch{} to handle an invalid, non-int, input.
So when I test it everything works fine. Right now if the user inputs a valid selection, an int of 1,2,3,4,5, or 0 then it's stuck in the while loop. This isn't the bug I just haven't implemented the menu choices yet.
The bug appears when the user enters a non-int invalid input. Maybe I have done something funky with the exception handling, not sure, but if you put in an invalid input it just loops endlessly as if an invalid input is being entered over and over even if I input nothing. It seems like it's getting input from somewhere else but I have no idea what could be sending input to the Scanner.
I know I have other Scanner objects but they're not even in the same class and aren't connected to this class at all yet. I was hoping someone else could take a look at it and maybe tell me what I've got wrong.
class UI{
private Scanner userInput;
private String fileName;
private Performance perf;
private Menu menu;
private int selection = -1;
public UI(){
userInput = new Scanner(System.in);
setFileName();
initializePerformance();
initializeMenu();
loopUI();
}
void setFileName() {
System.out.print("\nEnter the performance file name: ");
try{
fileName = userInput.next();
} catch (Exception e){
System.err.println(e.getMessage());
setFileName();
}
}
void initializePerformance(){
perf = new Performance(fileName);
}
void initializeMenu(){
this.menu = new Menu();
menu.addItem("Rows");
menu.addItem("Show Row");
menu.addItem("Seat Status");
menu.addItem("Buy Ticket");
menu.addItem("Return Ticket");
menu.addItem("Exit and Save");
}
void showMenu(){
menu.showMenu();
}
void selection() {
System.out.println("\nSelection[1,2,3,4,5,0]: ");
try{
this.selection = userInput.nextInt();
}catch(Exception e){
System.out.println("Invalid selection, try again.");
}
}
void loopUI(){
while(selection != 0){
System.out.println("\n" + perf.getName());
showMenu();
selection();
}
}
}
You'll have to add userInput.next() within the catch clause to consume the rest of the line after using userInput.nextInt().

Infinite loop when prompting for user input?

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.

How can I exit a Scanner Class to perform the rest of the loop?

I am accessing a Scanner that helps retrieve RFID Tags from an RFID Reader. I tried using a loop around my Scanner.next(); but that wouldn't do anything. I think that once my Scanner accesses the RFID Reader's method, that it just permanently stays in there. Is there any way to exit the method for the RFID and then perform the rest of my loop?
//The beginning of the loop
while (!doneYet) {
//Just a set boolean variable that I try to use later
Inter = false;
//A question class that I created, obtains and displays a random question
Test = Work.randomQuestion();
Test.display();
//This is where my problems seem to start, this is the RFID Readers Method.
rfid.addTagGainListener(new TagGainListener() {
public void tagGained(TagGainEvent oe) {
Temp = oe.getValue();
if (Test.getRFIDTag().equals(Temp)) {
System.out.println("You are Correct");
count++;
System.out.println(count);
Inter = true;
System.out.println("out");
/*
* try { System.in.close(); } catch (IOException e) {
* TODO Auto-generated catch block e.printStackTrace();
* }
*/
} else if (!Test.getRFIDTag().equals(Temp)) {
System.out.println("Sorry, you are wrong");
}
return;
}
});
// Before the RFID Opens though, this code is initiated
rfid.openAny();
rfid.waitForAttachment(1000);
sc = new Scanner(System.in);
//This is where I attempted to control the RFID Reader, but this doesn't work
if(!Inter){
sc.next();
}
//How I attempt to end the initial while loop
if(count>10){
doneYet = true;
}
}
Thanks in advance for all of the help.
Your scanner doesn't actually do anything. sc.next() just skips initial whitespace, and returns the first string of non-whitespace characters; but it just discards that string, never (for example) passing it to rfid. As far as I can see, nothing ever triggers rfid's TagGainListener. (And why do you add a new TagGainListener for each pass through the loop, anyway? Surely you only need one listener?)

Categories

Resources