class Solution:
def validTicTacToe(self, board):
def win(player):
# Check rows, columns, and diagonals
for i in range(3):
if all(board[i][j] == player for j in range(3)):
return True
if all(board[j][i] == player for j in range(3)):
return True
if all(board[i][i] == player for i in range(3)):
return True
if all(board[i][2-i] == player for i in range(3)):
return True
return False
x_count = sum(row.count('X') for row in board)
o_count = sum(row.count('O') for row in board)
if o_count > x_count or x_count - o_count > 1:
return False
x_win = win('X')
o_win = win('O')
if x_win and o_win:
return False
if x_win and x_count != o_count + 1:
return False
if o_win and x_count != o_count:
return False
return True
class Solution {
public:
bool win(vector<string>& board, char player) {
for (int i = 0; i < 3; ++i) {
if (board[i][0] == player && board[i][1] == player && board[i][2] == player)
return true;
if (board[0][i] == player && board[1][i] == player && board[2][i] == player)
return true;
}
if (board[0][0] == player && board[1][1] == player && board[2][2] == player)
return true;
if (board[0][2] == player && board[1][1] == player && board[2][0] == player)
return true;
return false;
}
bool validTicTacToe(vector<string>& board) {
int x_count = 0, o_count = 0;
for (auto& row : board) {
for (char c : row) {
if (c == 'X') x_count++;
else if (c == 'O') o_count++;
}
}
if (o_count > x_count || x_count - o_count > 1)
return false;
bool x_win = win(board, 'X');
bool o_win = win(board, 'O');
if (x_win && o_win) return false;
if (x_win && x_count != o_count + 1) return false;
if (o_win && x_count != o_count) return false;
return true;
}
};
class Solution {
private boolean win(String[] board, char player) {
for (int i = 0; i < 3; i++) {
if (board[i].charAt(0) == player && board[i].charAt(1) == player && board[i].charAt(2) == player)
return true;
if (board[0].charAt(i) == player && board[1].charAt(i) == player && board[2].charAt(i) == player)
return true;
}
if (board[0].charAt(0) == player && board[1].charAt(1) == player && board[2].charAt(2) == player)
return true;
if (board[0].charAt(2) == player && board[1].charAt(1) == player && board[2].charAt(0) == player)
return true;
return false;
}
public boolean validTicTacToe(String[] board) {
int xCount = 0, oCount = 0;
for (String row : board) {
for (char c : row.toCharArray()) {
if (c == 'X') xCount++;
else if (c == 'O') oCount++;
}
}
if (oCount > xCount || xCount - oCount > 1) return false;
boolean xWin = win(board, 'X');
boolean oWin = win(board, 'O');
if (xWin && oWin) return false;
if (xWin && xCount != oCount + 1) return false;
if (oWin && xCount != oCount) return false;
return true;
}
}
var validTicTacToe = function(board) {
function win(player) {
for (let i = 0; i < 3; i++) {
if (board[i][0] === player && board[i][1] === player && board[i][2] === player)
return true;
if (board[0][i] === player && board[1][i] === player && board[2][i] === player)
return true;
}
if (board[0][0] === player && board[1][1] === player && board[2][2] === player)
return true;
if (board[0][2] === player && board[1][1] === player && board[2][0] === player)
return true;
return false;
}
let xCount = 0, oCount = 0;
for (let row of board) {
for (let c of row) {
if (c === 'X') xCount++;
else if (c === 'O') oCount++;
}
}
if (oCount > xCount || xCount - oCount > 1) return false;
let xWin = win('X');
let oWin = win('O');
if (xWin && oWin) return false;
if (xWin && xCount !== oCount + 1) return false;
if (oWin && xCount !== oCount) return false;
return true;
};
You are given a 3x3 Tic-Tac-Toe board, represented as an array of strings board
, where each string is a row of the board. Each cell contains either 'X'
, 'O'
, or a space ' '
(for empty). You must determine if the given board state is a valid Tic-Tac-Toe state.
'X'
always goes first, and players alternate turns.'X'
is always equal to or exactly one more than the number of 'O'
.'X'
and 'O'
win at the same time.
Return true
if the board is a valid state, and false
otherwise.
To determine if a Tic-Tac-Toe board is valid, we need to check more than just the number of 'X'
and 'O'
. We must ensure that the game rules are followed: 'X'
starts, players alternate, and once there is a winner, the game stops.
A brute-force approach might try to simulate every possible game, but that's inefficient and unnecessary. Instead, we can use the properties of the board: count of each symbol, and check for win conditions. If the counts or win states violate the rules, the board is invalid.
The trickiest part is handling cases where both players appear to have won, or where the move counts don't match the winner. We need to carefully examine all winning lines and the move counts to validate the state.
'X'
and 'O'
on the board.
'O'
should never exceed 'X'
.'X'
should never be more than one greater than 'O'
.'X'
or 'O'
has a winning line.'X'
and 'O'
win, the board is invalid.'X'
wins, 'X'
must have one more move than 'O'
.'O'
wins, 'X'
and 'O'
must have the same number of moves.This approach ensures we check all the essential rules efficiently, using simple counting and line checks.
Consider the board:
["XOX", " X ", " "]
'X'
: 3; Count 'O'
: 13 - 1 = 2
(should be 0 or 1). So, invalid state.Another example:
["XOX", "O O", "XOX"]
'X'
: 5; Count 'O'
: 45 - 4 = 1
(valid).To validate a Tic-Tac-Toe board, we count the number of moves for each player, check for any winning lines, and ensure that the move counts and win states are consistent with the game rules. This approach is efficient (constant time and space), avoids unnecessary simulation, and is robust against tricky edge cases. The elegance comes from reducing the problem to counting and simple line checks, using the fixed size of the board to our advantage.