Katkat

Implement Generalized Tic-Tac-Toe

DatabricksSoftware Engineer · Onsite

Last updated

Design and implement a generalized m x n Tic-Tac-Toe game supporting an arbitrary winning streak length k. Tests grid simulation, efficient line checking around the latest move, and handling boundary conditions.

Generalized Tic-Tac-Toe

Design a generalized Tic-Tac-Toe game played by two players on an m x n grid. The game is won when a player places k or more consecutive marks horizontally, vertically, or diagonally.

Implement the TicTacToe class:

  • TicTacToe(m: int, n: int, k: int): Initializes the board with m rows, n columns, and a target streak length of k.
  • move(row: int, col: int, player: int) -> int: Places a mark on the board at (row, col) for player player (where player is either 1 or 2).
    • Returns 0 if no player has won after this move.
    • Returns 1 if Player 1 wins after this move.
    • Returns 2 if Player 2 wins after this move.
    • Once a player has won, no more moves are made (or you may assume all subsequent calls are invalid).

Rules and Clarifications

  • A line of length greater than or equal to k consecutive marks of the same player constitutes a win.
  • You only need to check lines passing through the cell (row, col) of the current move.
  • Diagonal checks must account for both main diagonals (\) and anti-diagonals (/), which may have lengths shorter or longer than k depending on the board dimensions and cell location.
  • Assume all inputs given to move are within bounds and played on an empty cell.

Example

game = TicTacToe(3, 4, 3)

# Board is 3 rows, 4 cols. Need 3 consecutive marks to win.
game.move(0, 0, 1)  # returns 0
game.move(1, 0, 2)  # returns 0
game.move(0, 1, 1)  # returns 0
game.move(1, 1, 2)  # returns 0
game.move(0, 2, 1)  # returns 1 (Player 1 has 3 marks in row 0: (0,0), (0,1), (0,2))

Constraints

  • 1 <= m, n <= 10^4
  • m * n <= 10^6
  • 1 <= k <= max(m, n)
  • player in (1, 2)
  • At most m * n calls will be made to move.
  • Each move call takes a distinct, previously unoccupied (row, col).

Hints

Hint 1

Instead of scanning the entire board on each move, only check the four directional axes passing through the newly placed piece.

Hint 2

For each axis (horizontal, vertical, diagonal, anti-diagonal), count consecutive matching marks extending in both opposite directions from (row, col) and sum them.

Hint 3

If m and n can be large, consider using a hash map or sparse representation to store occupied cells rather than allocating a full m x n grid.

Follow-up questions

  • How would you optimize your solution to determine a tie/draw as early as possible before the entire board is filled?
  • If this class is accessed concurrently by multiple worker threads in a distributed gaming service, how would you ensure thread safety and consistency?
  • Can you maintain running counters per row, column, and diagonal to achieve O(1) time per move for the classic case where k = m = n, and how does this generalize when k < min(m, n)?