2

I am making a very basic battleships game. Unlike the real thing, the program generates three random integers from 0 to 6. The player then has to guess where the ships are by inputting a integer.

So, the program as it is now:

public class digitBattleShips {

static int choice;
int playerScore;

int shipLoc1;
int shipLoc2;
int shipLoc3;

Random rand = new Random();
static Scanner input = new Scanner(System.in);

public void digitBattleShipsGame() {

    shipLoc1 = rand.nextInt(7);

    shipLoc2 = rand.nextInt(7);

    shipLoc3 = rand.nextInt(7);

    System.out.println(
            "Welcome to digit BattleShips! In this game, you will choose a 
          number from 0 to 6. There are 3 ships to destroy, if you get them 
      all, you win");

    while (playerScore != 3) {

        System.out.println("Choose a number from 0 to 6");

        playerChoice();
        
        if (choice == shipLoc1 || choice == shipLoc2 || choice == shipLoc3) {
            System.out.println("KABOOOOOOM!");

            playerScore++;
        } else {
            System.out.println("Sploooosh...");
        }

        

    }

    System.out.println("HURRRAAAAAAY you win");

}

public static void playerChoice() {
    
    try {
    choice = (int) input.nextInt();
    
    while (choice<0 || choice>6) {
        System.out.println("Error. You have to choose a number from 0 to 6");
        playerChoice();
    } }
    
    catch (InputMismatchException ex) {
        
        System.out.println("Invalid input! You have to enter a number");
        
        playerChoice();
    }

}

public static void main(String[] args) {

    digitBattleShips digit = new digitBattleShips();

    digit.digitBattleShipsGame();
}

}

At the moment, this is what happens:

1 ) If the player chooses an integer from 0 to 6 the while loop works as intended and will continue until the player hits the three ships represented by shipLoc1, shipLoc2 and shipLoc3

2 ) If the player chooses a number above or below 0 and 6, an error is shown, and the player gets prompted again for another input. Works as intended here.

3 ) If the player chooses a char, string, float number etc. then the exception is thrown BUT it does not allow the player to have another chance of changing their input.

I thought creating a method specifically designed (named playerChoice() as in the code) to allow input would sort this out and hence, after the exception is thrown, this method activates again so the player can choose another number. However, from my limited understanding, it does look like that the invalid choice is stored and hence, when this method is called, the exception is automatically thrown again as the invalid choice stays throughout. This then creates an infinite loop of the exception being thrown.

The idea is to allow another input if the one before it is invalid i.e. not an integer so that 3) operates in the same manner as 2)

I think the confusion I am facing here may be due to how I placed the while and try / catch techniques. Please provide some direction and how to prevent 3) from happening

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Zero201
  • 43
  • 1
  • 6

2 Answers2

4

This is what I would do:

public static void playerChoice()
{
    try
    {
        String inStr = input.nextLine();
        int inInt = Integer.parseInt(inStr); // throws exception.
        if (inInt < 0 || inInt > 6) // If number out of range, try again.
        {
            System.out.println("Error. You have to choose a number from 0 to 6");
            playerChoice();
        }
        else
        {
            choice = inInt;
        }
    }
    catch (NumberFormatException ex) // If exception, try again.
    {
        System.out.println("Invalid input! You have to enter a number");
        playerChoice();
    }
}

Instead of relying on Scanner.nextInt(), I would read the input as String first (since no parsing is involved at this step), then use Integer.parseInt() to parse manually. It is usually a good practice to seperate reading/fetching from casting/parsing.

cyqsimon
  • 2,752
  • 2
  • 17
  • 38
1

After a little bit of googling it looks like input isn't cleared after the exception is thrown (see How does input.nextInt() work exactly?).

As a result, because you aren't calling "input.next();", it keeps reading the same input, realizing it isn't an integer and throwing the exception.

Solution:

 try {
choice = (int) input.nextInt();

while (choice<0 || choice>6) {
    System.out.println("Error. You have to choose a number from 0 to 6");
    playerChoice();
} }

catch (InputMismatchException ex) {

    System.out.println("Invalid input! You have to enter a number");
    input.next();
    playerChoice();
}
bnunamak
  • 644
  • 8
  • 17
  • Yes, simple tweak that makes sense since it ''clears'' a previous input! Thanks so much for how quick you replied and the elegant explanation. I'm new here so it's much obliged! – Zero201 Jul 08 '18 at 10:54
  • 1
    I also used input.next() instead and that works fine. I think it is immaterial which one you would use in this specific program but does it matter if things were more sophisticated? – Zero201 Jul 08 '18 at 10:55
  • input.next() is actually more correct, as nextLine searches for a newline character and reads the input until one is found. I'll update my answer (see https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#next()) – bnunamak Jul 08 '18 at 10:58
  • @Zero201 if this answer solved your problem, then you might consider accepting it. – Lajos Arpad Jul 08 '18 at 12:13
  • Yes, there is another answer too which is also insightful, so thank you to both other users. Is there somewhere where you can accept answers? Or do you just say it? If the latter then I accept the answer of course – Zero201 Jul 08 '18 at 19:35