Assume n
is the size of the game board. The Tic-Tac-Toe board is size n x n
.
A move is guaranteed to be valid and is placed on an empty block.
A player who achieves n same marks (row, column, diagonal, or anti-diagonal) wins the game.
Implement the TicTacToe
class:
TicTacToe(int n)
Initializes the object with the size of the board n
.int move(int row, int col, int player)
Indicates that player player
moves at cell (row, col)
on the board. The function returns:0
if no one wins.1
if player 1 wins.2
if player 2 wins.Example 1:
Input
["TicTacToe", "move", "move", "move", "move", "move", "move"]
[[3], [0, 0, 1], [0, 2, 2], [2, 2, 1], [1, 1, 2], [2, 0, 1], [1, 0, 2]]
Output
[null, 0, 0, 0, 0, 0, 2]
Explanation
TicTacToe ticTacToe = new TicTacToe(3);
// Assume that player 1 is "X" and player 2 is "O"
Board after move("X", 0, 0) =
| X | | |
| | | |
| | | |
move("X", 0, 0); // return 0 (no one wins)
Board after move("O", 0, 2) =
| X | | O |
| | | |
| | | |
move("O", 0, 2); // return 0 (no one wins)
Board after move("X", 2, 2) =
| X | | O |
| | | |
| | | X |
move("X", 2, 2); // return 0 (no one wins)
Board after move("O", 1, 1) =
| X | | O |
| | O | |
| | | X |
move("O", 1, 1); // return 0 (no one wins)
Board after move("X", 2, 0) =
| X | | O |
| | O | |
| X | | X |
move("X", 2, 0); // return 0 (no one wins)
Board after move("O", 1, 0) =
| X | | O |
| O | O | |
| X | | X |
move("O", 1, 0); // return 2 (player 2 wins, because there is a row with three 'O's).
Constraints:
2 <= n <= 100
player
is 1
or 2
.0 <= row, col < n
(row, col)
are valid and empty.n2
calls will be made to move
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
For Tic-Tac-Toe, a brute force approach means checking every possible move after each player's turn to see if anyone has won. We essentially simulate the game from the current state to all possible end states. We don't need to store past moves, we just need to check for a win after each one.
Here's how the algorithm would work step-by-step:
class TicTacToe:
def __init__(self, board_size):
self.board_size = board_size
self.board = [['' for _ in range(board_size)] for _ in range(board_size)]
self.current_player = 'X'
def make_move(self, row, column):
if self.board[row][column] == '':
self.board[row][column] = self.current_player
if self.check_win(self.current_player):
return self.current_player
elif self.check_draw():
return 'Draw'
else:
self.current_player = 'O' if self.current_player == 'X' else 'X'
return None
else:
return 'Invalid Move'
def check_win(self, player):
# Check rows and columns for a win
for i in range(self.board_size):
if all(self.board[i][j] == player for j in range(self.board_size)):
return True
if all(self.board[j][i] == player for j in range(self.board_size)):
return True
# Check diagonals for a win
if all(self.board[i][i] == player for i in range(self.board_size)):
return True
if all(self.board[i][self.board_size - 1 - i] == player for i in range(self.board_size)):
return True
return False
def check_draw(self):
# Check if the board is full
for row in self.board:
if '' in row:
return False
return True
def print_board(self):
for row in self.board:
print('| ' + ' | '.join(row) + ' |')
# Example Usage:
if __name__ == '__main__':
game = TicTacToe(3)
game.print_board()
while True:
row = int(input(f"Player {game.current_player}, enter row (0-{game.board_size-1}): "))
column = int(input(f"Player {game.current_player}, enter column (0-{game.board_size-1}): "))
result = game.make_move(row, column)
game.print_board()
if result == 'Invalid Move':
print("Invalid move. Try again.")
elif result:
print(f"{result}!
")
break
The goal is to simulate the game of Tic-Tac-Toe. The efficient strategy is to directly update the board's state and track winning conditions whenever a player makes a move.
Here's how the algorithm would work step-by-step:
class TicTacToe:
def __init__(self, board_size):
self.board_size = board_size
self.game_board = [[' ' for _ in range(board_size)] for _ in range(board_size)]
self.current_player = 'X'
def move(self, row, column):
if self.game_board[row][column] != ' ':
return False
self.game_board[row][column] = self.current_player
if self.check_win(row, column):
print(f'Player {self.current_player} wins!')
return True
if self.check_draw():
print('Its a draw!')
return True
self.current_player = 'O' if self.current_player == 'X' else 'X'
return True
def check_win(self, row, column):
# Check row
if all(self.game_board[row][i] == self.current_player for i in range(self.board_size)):
return True
# Check column
if all(self.game_board[i][column] == self.current_player for i in range(self.board_size)):
return True
# Check diagonal (top-left to bottom-right)
if row == column and all(self.game_board[i][i] == self.current_player for i in range(self.board_size)):
return True
# Check diagonal (top-right to bottom-left)
if row + column == self.board_size - 1 and all(self.game_board[i][self.board_size - 1 - i] == self.current_player for i in range(self.board_size)):
return True
return False
def check_draw(self):
# Check if the board is full
if all(self.game_board[i][j] != ' ' for i in range(self.board_size) for j in range(self.board_size)):
return True
return False
def print_board(self):
for row in self.game_board:
print('| ' + ' | '.join(row) + ' |')
# Example usage:
# game = TicTacToe(3)
# game.print_board()
# game.move(0, 0)
# game.print_board()
Case | How to Handle |
---|---|
Null or empty game board size | Throw IllegalArgumentException or return error code if size is null/zero/negative, as a valid board must have a positive dimension. |
Invalid player value (not 1 or 2) | Throw IllegalArgumentException if the player value is not 1 or 2. |
Row or column index out of bounds | Throw IndexOutOfBoundsException or return false if the move is out of bounds of the game board. |
Cell already occupied | Return false if the specified cell already contains a move from another player. |
Game already won | Return -1 if the game has already been won, indicating no further moves are possible. |
Large board size (e.g., 1000x1000) | The solution should use O(1) space for tracking wins per row/col/diag, making it memory efficient. |
Integer overflow when calculating win condition for large board sizes with many moves. | Using integer array to store moves per row/col/diag mitigates integer overflow risks because game ends before hitting max int. |
Game ends in a draw (no winner and board is full) | The solution should return 0 if all cells are filled and there is no winner. |