public class TicTacToe {
private char[][] board;
private char currentPlayerMark;
public TicTacToe() {
board = new char[3][3];
currentPlayerMark = 'x';
initializeBoard();
}
// Set/Reset the board back to all empty values.
public void initializeBoard() {
// Loop through rows
for (int i = 0; i < 3; i++) {
// Loop through columns
for (int j = 0; j < 3; j++) {
board[i][j] = '-';
}
}
}
// Print the current board (may be replaced by GUI implementation later)
public void printBoard() {
System.out.println("-------------");
for (int i = 0; i < 3; i++) {
System.out.print("| ");
for (int j = 0; j < 3; j++) {
System.out.print(board[i][j] + " | ");
}
System.out.println();
System.out.println("-------------");
}
}
// Loop through all cells of the board and if one is found to be empty (contains char '-') then return false.
// Otherwise the board is full.
public boolean isBoardFull() {
boolean isFull = true;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == '-') {
isFull = false;
}
}
}
return isFull;
}
// Returns true if there is a win, false otherwise.
// This calls our other win check functions to check the entire board.
public boolean checkForWin() {
return (checkRowsForWin() || checkColumnsForWin() || checkDiagonalsForWin());
}
// Loop through rows and see if any are winners.
private boolean checkRowsForWin() {
for (int i = 0; i < 3; i++) {
if (checkRowCol(board[i][0], board[i][1], board[i][2]) == true) {
return true;
}
}
return false;
}
// Loop through columns and see if any are winners.
private boolean checkColumnsForWin() {
for (int i = 0; i < 3; i++) {
if (checkRowCol(board[0][i], board[1][i], board[2][i]) == true) {
return true;
}
}
return false;
}
// Check the two diagonals to see if either is a win. Return true if either wins.
private boolean checkDiagonalsForWin() {
return ((checkRowCol(board[0][0], board[1][1], board[2][2]) == true) || (checkRowCol(board[0][2], board[1][1], board[2][0]) == true));
}
// Check to see if all three values are the same (and not empty) indicating a win.
private boolean checkRowCol(char c1, char c2, char c3) {
return ((c1 != '-') && (c1 == c2) && (c2 == c3));
}
// Change player marks back and forth.
public void changePlayer() {
if (currentPlayerMark == 'x') {
currentPlayerMark = 'o';
}
else {
currentPlayerMark = 'x';
}
}
// Places a mark at the cell specified by row and col with the mark of the current player.
public boolean placeMark(int row, int col) {
// Make sure that row and column are in bounds of the board.
if ((row >= 0) && (row < 3)) {
if ((col >= 0) && (col < 3)) {
if (board[row][col] == '-') {
board[row][col] = currentPlayerMark;
return true;
}
}
}
return false;
}
}
optimize:
The key observation is that in order to win Tic-Tac-Toe you must have the entire row or column. Thus, we don't need to keep track of an entire n^2 board. We only need to keep a count for each row and column. If at any time a row or column matches the size of the board then that player has won.
To keep track of which player, I add one for Player1 and -1 for Player2. There are two additional variables to keep track of the count of the diagonals. Each time a player places a piece we just need to check the count of that row, column, diagonal and anti-diagonal.
public class TicTacToe {
private int[] rows;
private int[] cols;
private int diagonal;
private int antiDiagonal;
/** Initialize your data structure here. */
public TicTacToe(int n) {
rows = new int[n];
cols = new int[n];
}
/** Player {player} makes a move at ({row}, {col}).
@param row The row of the board.
@param col The column of the board.
@param player The player, can be either 1 or 2.
@return The current winning condition, can be either:
0: No one wins.
1: Player 1 wins.
2: Player 2 wins. */
public int move(int row, int col, int player) {
int toAdd = player == 1 ? 1 : -1;
rows[row] += toAdd;
cols[col] += toAdd;
if (row == col)
{
diagonal += toAdd;
}
if (col == (cols.length - row - 1))
{
antiDiagonal += toAdd;
}
int size = rows.length;
if (Math.abs(rows[row]) == size ||
Math.abs(cols[col]) == size ||
Math.abs(diagonal) == size ||
Math.abs(antiDiagonal) == size)
{
return player;
}
return 0;
}