/* An instance of this class can be used in support of a program that ** "plays" the game of Tic-Tac-Toe. ** It keeps track of the state of the 3x3 Tic-Tac-Toe board and allows ** for marks to be placed onto the board. It has methods that answer ** queries about the state of the board/game (e.g., Is a particular ** square marked?; If so, by X or by O?; Is the game over?; If so, ** was it a draw?; If not, who won?). */ public class TicTacToe { // class constants // --------------- public static final char X = 'X'; public static final char O = 'O'; public static final char NONE = ' '; // a non-mark // instance variables // ------------------ private char[][] board; // class invariant: Every element of board[][] // has value either X, O, or NONE private int numMarkedSquares; // # of squares marked by either X or O. // constructor // ----------- /* Establishes the state of the board to be that all squares are ummarked. */ public TicTacToe() { board = new char[3][3]; numMarkedSquares = 0; for (int row = 0; row != 3; row++) { for (int col = 0; col != 3; col++) { board[row][col] = NONE; } } } // observers // ---------- /* Given one of the marks (X or O), returns the opponent's mark. ** pre: mark == X || mark == O */ public char opponentOf(char mark) { if (mark == X) { return O; } else { return X; } } /* Reports whether or not the specified square has a mark in it. */ public boolean isMarked(int row, int col) { return markedBy(row, col) != NONE; } /* Identifies the contents of the specified square by returning ** one among X, O, or NONE). */ public char markedBy(int row, int col) { return board[row][col]; } /* Reports whether or not this game is over. */ public boolean isGameOver() { return wonBy(X) || wonBy(O) || numMarkedSquares == 9; } public boolean isDraw() { return numMarkedSquares == 9 && !wonBy(X) && !wonBy(O); } /* Returns either X, O, or NONE according, respectively, ** to whether the game was won by X, by O, or was a draw. ** pre: isGameOver() */ public char winnerOf() { if (wonBy(X)) { return X; } else if (wonBy(O)) { return O; } else { return NONE; } } // mutators // --------- /* Places the specified mark into the specified square of the board. ** Throws an exception if the specified square was already marked. */ public void placeMark(char mark, int row, int col) { if (isMarked(row, col)) { throw new IllegalArgumentException("Cannot mark an already-marked square"); } else { board[row][col] = mark; numMarkedSquares++; } } // private // ------- /* Reports whether or not the specified player has won. ** pre: mark == X || mark == O */ private boolean wonBy(char mark) { return ownsSlashDiagonal(mark) || ownsBackSlashDiagonal(mark) || ownsSomeRow(mark) || ownsSomeColumn(mark); } /* Reports whether or not some row of the board is "owned by" the ** specified mark (meaning that all its squares are occupied by ** that mark. ** pre: mark == X || mark == O */ private boolean ownsSomeRow(char mark) { return false; // STUB!! } /* Reports whether or not some column of the board is "owned by" ** the specified mark (meaning that all its squares are occupied ** by that mark. ** pre: mark == X || mark == O */ private boolean ownsSomeColumn(char mark) { return false; // STUB!! } /* Reports whether or not the "slash" diagonal of the board is ** "owned by" the specified mark (meaning that all its squares ** are occupied by that mark). ** pre: mark == X || mark == O */ private boolean ownsSlashDiagonal(char mark) { return markedBy(0,2) == mark && markedBy(1,1) == mark && markedBy(2,0) == mark; } /* Reports whether or not the "backslash" diagonal of the board ** is "owned by" the specified mark (meaning that all its squares ** are occupied by that mark). ** pre: mark == X || mark == O */ private boolean ownsBackSlashDiagonal(char mark) { return markedBy(0,0) == mark && markedBy(1,1) == mark && markedBy(2,2) == mark; } }