0

I am stuck on some things for my code so i can finish it up. I'm making a game of tic tac toe for an assignment but i'm stuck. The professor requires us to make input validation and i got most of them down.

The last couple lines in playGame where i have "input not valid", i want it to loop and ask if you want to start the game again, i can put a number that isnt 1 or 0 but if i put a letter instead it keeps looping over and over until it throws an exception.

I have an input validation in playerMove that does the same thing. If i put a letter, it loops over and over. And if i put a number that isnt acceptable, itll say it isnt valid but then itll throw an exception. Compared to when you put a number like 2 when it asks the first question of if you want to play. It'll say its not the right input and ask the question again but i cant seem to replicate that in the other methods.

Also, I can't seem to finish the game in a draw, I don't know why. If anyone could help out, That'd be great, i cant figure it out at all.

import java.util.Scanner; //Used for player's input in game



public class TicTacToe 
{

//instance variables
private char[][] board; //Tic Tac Toe Board, 2d array
private boolean xTurn; // true when X's turn, false if O's turn
private Scanner input; // Scanner for reading input from keyboard

//Constants for creation of gameboard
public final int ROWS = 3; //total rows
public final int COLS = 3; //total columns
public final int WIN = 3; //amount needed to win

public TicTacToe()

{
    //creates the board
    board = new char[ROWS][COLS];

    for(int r = 0; r < ROWS; r++)
    {
        for(int c = 0; c < COLS; c++)
        {   
            board[r][c] = ' ';
        }
    }

    //X's turn when game starts
    xTurn = true; 

    //creates our input object for the turn player
    input = new Scanner(System.in);
}
    //shows game board
    public void displayBoard()

    {   
    int colNum = 0; //number of columns
    int rowNum = 0; //number of rows

    //creates column labels
    System.out.println(" \n");
    System.out.println("     Columns ");
    for (int num = 0; num < COLS; num++)
    {
        System.out.print("   " + colNum);
        colNum++;
    }

    //creates vertical columns and spaces between each spot 
    System.out.println(" \n");
    for (int row = 0; row < ROWS; row++) 
    {
        //numbers rows
        System.out.print(" " + rowNum + "  ");
        rowNum++;

        for (int col = 0; col < COLS; ++col) 
        {

            System.out.print(board[row][col]); // print each of the cells

            if (col != COLS - 1) 
            {
                System.out.print(" | ");   // print vertical partition
            }   
     }

     System.out.println();

     //creates seperation of rows
     if (row != ROWS - 1) 
     {
        System.out.println("   ------------"); // print horizontal partition
     }

    }
    //labels row
    System.out.println("Rows \n");
    }

    //displays turn player
    public void displayTurn()
    {
        if (xTurn)
        {
            System.out.println("X's Turn");

        }
        else
        {
            System.out.println("O's Turn");
        }


    }

    //allows you to make move
    public boolean playerMove()
    {
        boolean invalid = true;
        int row = 0;
        int column = 0;

        while(invalid)
        {
            System.out.println("Which row (first) then column (second) would you like to \n"
                    + "play this turn? Enter 2 numbers between 0-2 as \n"
                    + "displayed on the board, seperated by a space to \n"
                    + "choose your position.");
            if (input.hasNextInt())
            {
            row = input.nextInt();

            if (row >= ROWS|| row < 0 || column >= COLS || column < 0)
                {
                    System.out.println("Invalid position");
                }

            if (row >= 0 && row <= ROWS - 1 && column >= 0 && column <= COLS - 1)
            {
                if (board[row][column] != ' ')
                {
                    System.out.println("Spot is taken \n");
                }

                else
                {
                    invalid = false;
                }

            }



            }
            else
            {
                System.out.println("Invalid position");
            }

            if(input.hasNextInt())
            {
            column = input.nextInt();

             if (row >= ROWS|| row < 0 || column >= COLS || column < 0)
                {
                    System.out.println("Invalid position");
                }

            //checks if spot is filled
            if (row >= 0 && row <= ROWS - 1 && column >= 0 && column <= COLS - 1)
            {
                if (board[row][column] != ' ')
                {
                    System.out.println("Spot is taken \n");
                }
                else
                {
                    invalid = false;
                }

            }



            }
            else
                {
                    System.out.println("Invalid position");
                }
//fills spot if not taken
            if (xTurn)
            {
                board[row][column] = 'X';
            }
            else
            {
                board[row][column] = 'O';
            }
        }
        return displayWinner(row,column);       
    }


    public boolean displayWinner(int lastR, int lastC)
    {
        boolean winner = false;
        int letter = board[lastR][lastC];

        //checks row for win
        int spotsFilled = 0;
        for (int c = 0; c < COLS; c++)
        {
            if(board[lastR][c] == letter)
            {
                spotsFilled++;
            }
        }

        if (spotsFilled == WIN)
        {
            winner = true;


        }

        //checks columns for win
        spotsFilled = 0;
        for (int r = 0; r < ROWS; r++)
        {
            if(board[r][lastC] == letter)
            {
                spotsFilled++;
            }
        }

        if (spotsFilled == WIN)
        {
            winner = true;

        }

        //checks diagonals for win
        spotsFilled = 0;
        for (int i = 0; i < WIN; i++)
        {
            if(board[i][i] == letter)
            {
                spotsFilled++;
            }
        }

        if(spotsFilled == WIN)
        {
            winner = true;

        }

        //checks other diagonal
        spotsFilled = 0;
        for(int i = 0; i < COLS; i++)
        {
            if(board[i][(COLS-1)- i] == letter)
            {
                spotsFilled++;
            }
        }
        if(spotsFilled == WIN)
        {
            winner = true;

        }


        return winner;
    }

//checks if board is full
public boolean fullBoard()
{
    int filledSpots = 0;

    for(int r = 0; r < ROWS; r++)
    {
        for (int c = 0; c < COLS; c++)
        {
            if (board[r][c] == 'X' || board[r][c] == 'O')
            {
                filledSpots++;
            }
        }
    }
    return filledSpots == ROWS*COLS;
}

//plays game
public void playGame()
{
    boolean finish = true;
    System.out.println("Are your ready to start?");
    System.out.println("1 for Yes or 0 for No? : ");

    if (input.hasNextInt())
    {
        int choice = input.nextInt();

        if(choice > 1 || choice < 0)
    {
        System.out.println("Invalid choice");
        playGame();
    }

    else if (choice == 1)
    {
    while (finish)
    {
        displayBoard();
        displayTurn();

        if (playerMove())
        {
            displayBoard();
            if (xTurn)
            {
                System.out.println("X won");
                displayBoard();
            }
            else
            {
                System.out.println("O won");
                displayBoard();
            }

        }
        else if (fullBoard())
        {
            displayBoard(); 
            System.out.println("Draw");


        }
        else
        {
            xTurn=!xTurn;
        }

        }

    }
}
    else 
    {
        System.out.println("Input not valid");
        playGame();
    }
}

}

and the tester

public class TicTacToeTester {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {

    TicTacToe tictactoe = new TicTacToe();

    tictactoe.playGame();
}

}

3 Answers3

0

To get a numeric input validation that doesn't throw an exception you need to do something like this

int num;
    while(true){
        try{
            Scanner input = new Scanner(System.in);
            num = Integer.parseInt(input.nextLine());
            break;
        }catch(NumberFormatException e){}
    }

This will keep looping until you will input a string that can be converted to an int, therefore a number.

T4l0n
  • 595
  • 1
  • 8
  • 25
  • the professor said we couldn't catch exceptions or throw them. I was able to pull it off without throwing the exception but they just keep looping the question over and over – Rafael Leal-Mccormack Feb 18 '16 at 05:12
0

You can simply get the next character and compare that to '0' or '1'.

Try this:

String userInput = input.nextLine();
if(userInput.charAt(0) == '0' || userInput.charAt(0) == '1'){
    //do what you have to do if it is a 0 or 1
}
else {
   //do what you have to do if it is an invalid input
}
Dave
  • 321
  • 1
  • 8
0

So there was a lot going on with your program. In regards to your main problem with the loop in playerMove() and playGame() method, I was able to fix it with the help of this post. Now the playGame() method will:

1)Check if input can be interpreted as int

2)Check if input is within valid row range

3)Check if input is within valid column range

4)Check if input does not attempt to overwrite an occupied cell

The playGame() method will now give the user another chance to enter a new value if his input was invalid.

There was a lot of redundancy in your code such as:

if (row >= ROWS|| row < 0 || column >= COLS || column < 0) where you were testing the value of column before it was even input. And directly after that while checking if spot was occupied if (row >= 0 && row <= ROWS - 1 && column >= 0 && column <= COLS - 1). Here, you are basically carrying out the same if statement, but with a different syntax, where in fact you don't need to be re-checking at all. Another problem with this was that you were also checking if a spot was occupied before the user even input the column. This would be redundant in the early game stages and wouldn't make sense as the board filled up, since it may have given warnings that a spot [row][0] was full (0 being, of course, the default value which you initialized the column variable with before user input and row being the value input for row). Of course you repeat the same in the following section where you check the row value again when it had already been proven valid by the previous if statement but I won't go into that since it's pretty much the same. So without further ado here's the new playerMove() method:

public boolean playerMove()
    {
        int row = 0;
        int column = 0;

        System.out.println("Which row (first) then column (second) would you like to \n"
                + "play this turn? Enter 2 numbers between 0-2 as \n"
                + "displayed on the board, seperated by a space to \n"
                + "choose your position.");
        while(true){
            System.out.println("Enter row number:");
            while (true)
            {
                if(!input.hasNextInt()){ //Checking row number validity
                    System.out.println("Input not valid, try again!");
                    input.next();
                    continue;
                }   
                row=input.nextInt();
                if(row >= ROWS|| row < 0 ){ //Checking row range
                    System.out.println("Invalid position, rows out of range! Try again:");
                    //input.next();
                    continue;
                }
                break;
            }

            System.out.println("Enter column number:");
            while(true){
                if(!input.hasNextInt()){    //Checking column number validity
                    System.out.println("Input not valid, try again:");
                    input.next();
                    continue;
                }   
                column = input.nextInt();
                if (column >= COLS || column < 0)   //Checking column range
                {
                    System.out.println("Invalid position, columns out of range! Try again:");
                    input.next();
                    continue;
                }
                break;
            }
            //checks if spot is filled
            if (board[row][column] != ' ')
            {
                System.out.println("Spot is taken, pick a new position:");
                continue;
            }
            break;
        }

        //fills spot if not taken
        if (xTurn)
            board[row][column] = 'X';
        else
            board[row][column] = 'O';
        return displayWinner(row,column);
    }

As to your other problem with the game not acknowledging draws (Actually it wasn't only draws that weren't acknowledged but also the wins were ignored), the solution was really quite simple. In your playGame() method you simply needed to add a break statement in the section where playerMove() returns true and in the section where the board becomes full without there being a winner. This will end the game and exit the endless while loop(terminating the program in the process). Here's the new playGame() acknowledging game ends(wins/draws) and error loop free:

public void playGame()
    {
        //boolean finish = true;
        System.out.println("Are your ready to start?");
        System.out.println("1 for Yes or 0 for No? : ");
        //int choice=input.nextInt();
        while(!input.hasNextInt()){
            System.out.println("Input not valid, try again!");
            input.next();
            //int choice=input.next();
        }
        int choice=input.nextInt();
        System.out.print("choice is "+choice);
        if(choice > 1 || choice < 0)
        {
            System.out.println("Invalid choice");
            playGame();
        }

        else if (choice == 1)
        {
            while (true)
            {
                displayBoard();
                displayTurn();

                if (playerMove())
                {
                    displayBoard();
                    if (xTurn)
                    {
                        System.out.println("X won");
                        displayBoard();
                        break;
                    }
                    else
                    {
                        System.out.println("O won");
                        displayBoard();
                        break;
                    }

                }
                else if (fullBoard())
                {
                    displayBoard(); 
                    System.out.println("Draw");
                    break;
                }
                else
                {
                    xTurn=!xTurn;
                }
            }
        }
    }

Another thing I felt like adding was to your displayWinner(..) method. I added

if (spotsFilled == WIN)
        {
            return winner = true;

        }

sections, so that the method returns a value right when there are 3 of the same kind in a row. Again, we see the redundancy here where you continued checking where there was no need to do so, since you already had the answer you needed(in this case winner being true). So here are the changes:

public boolean displayWinner(int lastR, int lastC)
    {
        boolean winner = false;
        int letter = board[lastR][lastC];

        //checks row for win
        int spotsFilled = 0;
        for (int c = 0; c < COLS; c++)
        {
            if(board[lastR][c] == letter)
            {
                spotsFilled++;
            }
        }

        if (spotsFilled == WIN)
        {
            return winner = true;

        }

        //checks columns for win
        spotsFilled = 0;
        for (int r = 0; r < ROWS; r++)
        {
            if(board[r][lastC] == letter)
            {
                spotsFilled++;
            }
        }

        if (spotsFilled == WIN)
        {
            return winner = true;

        }

        //checks diagonals for win
        spotsFilled = 0;
        for (int i = 0; i < WIN; i++)
        {
            if(board[i][i] == letter)
            {
                spotsFilled++;
            }
        }

        if(spotsFilled == WIN)
        {
            return winner = true;

        }

        //checks other diagonal
        spotsFilled = 0;
        for(int i = 0; i < COLS; i++)
        {
            if(board[i][(COLS-1)- i] == letter)
            {
                spotsFilled++;
            }
        }
        if(spotsFilled == WIN)
        {
            return winner = true;

        }
        return winner;
    }
Community
  • 1
  • 1
Omar Sharaki
  • 360
  • 9
  • 34