So my TicTacToe game feels practically perfect besides the fact that I'm at a loss on how to prevent non-integer (character or string) input. I want to make it so "That is not a number please try again." whenever a letter or symbol is inputted through the scanner. Instead whenever I try that I just get
Exception in thread "main" java.util.InputMismatchException
at java.base/java.util.Scanner.throwFor(Scanner.java:939)
at java.base/java.util.Scanner.next(Scanner.java:1594)
at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
at TicTactoe3.main(TicTactoe3.java:23)
It also seems that java.util.InputMismatchException; is never used so the block can't be accessed somehow. I have it in a try catch statement in a while loop that seems practically inaccessible, and I'm aware that it's because of playerPos() being different from playerPos but I'm still at a loss for a solution. Placing the try catch into the main method doesn't work either, returns can't be used in void statements and without it it just doesn't do anything.
This is all of my code for reference. I really have no idea how to fix this issue and any answers/advice would be appreciated though I'd prefer not having to rewrite all of my code.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.List;
// import java.util.Random;
import java.util.Scanner;
public class TicTactoe3 {
static Scanner move = new Scanner(System.in);
static ArrayList<Integer> playerPositions = new ArrayList<Integer>();
static ArrayList<Integer> playerPositions2 = new ArrayList<Integer>();
public static void main(String[] args) {
char[][] gameBoard = {{' ', '|', ' ', '|', ' '},
{'-', '+', '-', '+', '-'},
{' ', '|', ' ', '|', ' '},
{'-', '+', '-', '+', '-'},
{' ', '|', ' ', '|', ' '}};
printGameBoard(gameBoard);
int playerPos = move.nextInt();
while(true) {
System.out.println("Enter your move (1-9) player one ");
while(playerPositions.contains(playerPos) || playerPositions2.contains(playerPos)) {
System.out.println("Position taken");
playerPos = move.nextInt();
}
while(playerPos >= 10 || playerPos <= 0) {
System.out.println("Incorrect Input");
playerPos = move.nextInt();
}
placePiece(gameBoard, playerPos, "player 1");
printGameBoard(gameBoard);
String result = checkWinner();
if(result.length() > 0) {
System.out.println(result);
break;
}
if (Character.isLetter(playerPos)) {
System.out.println("Invalid Input. Numbers 1-9 only!");
}
System.out.println("Enter your move (1-9) player two ");
int playerPos2 = move.nextInt();
while(playerPositions.contains(playerPos2) || playerPositions2.contains(playerPos2)) {
System.out.println("Position taken");
playerPos2 = move.nextInt();
}
while(playerPos2 >= 10 || playerPos2 <= 0) {
System.out.println("Incorrect Input");
playerPos2 = move.nextInt();
}
placePiece(gameBoard, playerPos2, "player 2");
printGameBoard(gameBoard);
result = checkWinner();
if(result.length() > 0) {
System.out.println(result);
break;
}
}
}
public static int playerPos() { // This is where I try to prevent non-integer input but it doesn't do anything
// That and it seems to regard playerPos() as different from playerPos but
// simply using playerPos leads to other issues
while (true) {
try {
return move.nextInt();
}
catch (InputMismatchException a) {
move.next();
System.out.println("That is not a number please try again.");
}
}
}
public static void printGameBoard(char[][] gameBoard) {
for(char[] row : gameBoard) {
for(char c : row) {
System.out.print(c);
}
System.out.println();
}
}
public static void placePiece(char[][] gameBoard, int pos, String user) {
char symbol = ' ';
if(user.equals("player 1")) {
symbol = 'X';
playerPositions.add(pos);
} else if(user.equals("player 2")) {
symbol = 'O';
playerPositions2.add(pos);
}
switch(pos) {
case 1:
gameBoard[0][0] = symbol;
break;
case 2:
gameBoard[0][2] = symbol;
break;
case 3:
gameBoard[0][4] = symbol;
break;
case 4:
gameBoard[2][0] = symbol;
break;
case 5:
gameBoard[2][2] = symbol;
break;
case 6:
gameBoard[2][4] = symbol;
break;
case 7:
gameBoard[4][0] = symbol;
break;
case 8:
gameBoard[4][2] = symbol;
break;
case 9:
gameBoard[4][4] = symbol;
break;
default:
break;
}
}
public static String checkWinner() {
List topRow = Arrays.asList(1, 2, 3);
List midRow = Arrays.asList(4, 5, 6);
List botRow = Arrays.asList(7, 8, 9);
List leftCol = Arrays.asList(1, 4, 7);
List midCol = Arrays.asList(2, 5, 8);
List rightCol = Arrays.asList(3, 6, 9);
List cross1 = Arrays.asList(1, 5, 9);
List cross2 = Arrays.asList(7, 5, 3);
List<List> winning = new ArrayList<List>();
winning.add(topRow);
winning.add(midRow);
winning.add(botRow);
winning.add(leftCol);
winning.add(midCol);
winning.add(rightCol);
winning.add(cross1);
winning.add(cross2);
for (List l : winning) {
if(playerPositions.containsAll(l)) {
return "Congrats, player 1 wins!";
}
else if(playerPositions2.containsAll(l)) {
return "Congrats, player 2 wins";
}
}
for (List l : winning) {
if(playerPositions.size() + playerPositions2.size() == 9) {
return "NOBODY WINS";
}
}
return "";
}
}
Edit: I came up with a partial solution. First I made it so playerPos and playerPos2 start at zero before any player input.
int playerPos = 0;
int playerPos2 = 0;
Then I wrote a simple try and catch statement but I'm unable to make it loop so it has to break. Continue just types the error ad nauseum.
try {
playerPos = move.nextInt();
} catch (InputMismatchException e) {
System.out.println("1-9 only, please try again.");
break;
}
In place of break I tried playerPos = move.nextInt(); like my other while loops but that just leads to the "Exception in thread main" error which halts the program. There's probably a pretty simple solution to this that I'm just not realizing somehow.