1
\$\begingroup\$

I had a Tic Tac Toe assignment for class and the program seems to work fine but I feel like the exception/input handling could be done in a much better way. Is this a good way to approach the structure of the app? Is it okay to use try/catch a lot like in here or is it better to try and avoid it? Really newbie question but I'd love your feedback, thanks!

public class TicTacToeApp {

    static Scanner in = new Scanner(System.in);

    public static void main(String[] args) {
        char[] gameBoard = new char[9];
        Arrays.fill(gameBoard, ' ');
        char playerOne = ' ';
        char playerTwo = ' ';

        System.out.println("Welcome to Tic-Tac-Toe!");


        try {
            playerOne = getPlayerOne(playerOne);
            playerTwo = getPlayerTwo(playerOne);
            System.out.println("Player one plays with: " + playerOne);
            System.out.println("Player two plays with: " + playerTwo);
            displayBoard(gameBoard);

            do {
                System.out.println(playerOne + "'s turn: choose a position from 1-9");
                getPosition(gameBoard, playerOne);
                displayBoard(gameBoard);
                if (gameOver(gameBoard, playerOne, playerTwo)) break;

                System.out.println(playerTwo + "'s turn: choose a position from 1-9");
                getPosition(gameBoard, playerTwo);
                displayBoard(gameBoard);
            } while (!gameOver(gameBoard, playerOne, playerTwo));

        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }

    }

    /** Displays the board in the console
     *
     * @param gameBoard The char[] used for the game
     */
    public static void displayBoard(char[] gameBoard) {
        System.out.println(gameBoard[0] + " | " + gameBoard[1] + " | " + gameBoard[2]);
        System.out.println("---------");
        System.out.println(gameBoard[3] + " | " + gameBoard[4] + " | " + gameBoard[5]);
        System.out.println("---------");
        System.out.println(gameBoard[6] + " | " + gameBoard[7] + " | " + gameBoard[8]);
    }

    /** Gets the mark choice for player one, 'X' or 'O'
     *
     * @param playerOne the player to be assigned with a mark
     * @return          the mark that playerOne will play with
     */
    public static char getPlayerOne(char playerOne) {
        System.out.println("Player one please pick 'X' or 'O' ");
        while (playerOne != 'X' && playerOne != 'O') {
            playerOne = in.nextLine().toUpperCase().charAt(0);
            if (playerOne != 'X' && playerOne != 'O') {
                System.out.println("Please pick either X or O");
            }
        }
        return playerOne;
    }

    /** Assigns the remaining mark to player two
     *
     * @param playerOne the mark player one has chosen
     * @return the mark that remains for player two
     */
    public static char getPlayerTwo(char playerOne) {
        if (playerOne == 'X') return 'O';
        else return 'X';
    }

    /** Checks for victory conditions for either player
     *
     * @param gameBoard the char[] used for the game
     * @param player    the player to check for
     * @return          true if the player has won, false otherwise
     */
    public static boolean isVictory(char[] gameBoard, char player) {
        return ((gameBoard[0] == player) && (gameBoard[1] == player) && (gameBoard[2] == player)) ||
                ((gameBoard[3] == player) && (gameBoard[4] == player) && (gameBoard[5] == player)) ||
                ((gameBoard[6] == player) && (gameBoard[7] == player) && (gameBoard[8] == player)) ||
                ((gameBoard[0] == player) && (gameBoard[3] == player) && (gameBoard[6] == player)) ||
                ((gameBoard[1] == player) && (gameBoard[4] == player) && (gameBoard[7] == player)) ||
                ((gameBoard[2] == player) && (gameBoard[5] == player) && (gameBoard[8] == player)) ||
                ((gameBoard[0] == player) && (gameBoard[4] == player) && (gameBoard[8] == player)) ||
                ((gameBoard[2] == player) && (gameBoard[4] == player) && (gameBoard[6] == player));
    }

    /** Assigns a mark to a position on the board
     *
     * @param gameBoard the char[] used for the game
     * @param player    the player whose turn it is to place a mark
     */
    public static void getPosition(char[] gameBoard, char player) {
        int position = 1;
        do {

            try {
                position = Integer.parseInt(in.nextLine());
                if (position < 1 || position > 9) {
                    System.out.println("Please enter a number from 1-9");
                    position = Integer.parseInt(in.nextLine());
                }
                if (gameBoard[position - 1] != ' ') {
                    throw new IllegalArgumentException("Position is occupied. Please choose another position");
                } else {
                    gameBoard[position - 1] = player;
                    break;
                }
            } catch (IllegalArgumentException e) {
                System.out.println(e.getMessage());
            }

        } while (gameBoard[position - 1] != ' ');
    }

    /** Checks if the board is full
     *
     * @param gameBoard the char[] used for the game
     * @return          true if the board is full, false otherwise
     */
    public static boolean fullBoard(char[] gameBoard) {
        for (char c : gameBoard) {
            if (c == ' ') {
                return false;
            }
        }
        return true;
    }

    /** Checks for end of game conditions (victory or draw)
     *
     * @param gameBoard the char[] used for the game
     * @param playerOne First player
     * @param playerTwo second player
     * @return  True and a message if the game has ended, False otherwise
     */
    public static boolean gameOver(char[] gameBoard, char playerOne, char playerTwo) {
        boolean gameOver = false;

        if (isVictory(gameBoard, playerOne)) {
            System.out.println(playerOne + "'s win!");
            gameOver = true;
        } else if (isVictory(gameBoard, playerTwo)) {
            System.out.println(playerTwo + "'s win!");
            gameOver = true;
        } else if (fullBoard(gameBoard)) {
            System.out.println("Game ended in a draw");
            gameOver = true;
        }
        return gameOver;
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ For future reference, your post title should explain what your code does. \$\endgroup\$ Jun 4 at 18:50

1 Answer 1

1
\$\begingroup\$

Overall, the structure of the app is reasonable. Methods are named clearly and do what the name suggests. It misses some of the benefits of object-oriented programming because all the pieces that make up the state of the game (like the game board) are declared in main and must be passed to each other method.* Additionally, methods should generally have the most restrictive viable access modifier; in this case, all the methods except main can be private instead of public.

Regarding exceptions, in my experience, there are usually better ways to handle errors in self-contained code like this app. In this case, the try/catch in getPosition makes sense as it catches both the NumberFormatException from Integer.parseInt and the IllegalArgumentException your code throws. However, the try/catch in main is unnecessary since getPosition already catches the exceptions that may be thrown.


*Full object-oriented programming generally requires more than 1 class in Java due to the static modifier of the main method.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.