Quick Overview

Implement two-player Tic-Tac-Toe with automatic turn changes, board snapshots, rejected moves, winning lines, and full-board draws.

Tic-Tac-Toe with Automatic Turns and Board Snapshots

Company: Databricks

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Onsite

Implement the state transitions of a two-player Tic-Tac-Toe game. A successful move places the current player's mark, automatically switches players if play can continue, and produces a board snapshot for display. A win or a full-board draw ends the game. Implement `play_tic_tac_toe(moves: int[][]) -> string[][]`. Each input row is an attempted `[row, column]`. Return one output row per attempt, using seven strings in this exact order: ```text [accepted, board_row_0, board_row_1, board_row_2, status, next_player, attempted_player] ``` - `accepted` is `"1"` when a mark was placed and `"0"` otherwise. - Each board row is a length-three string using `X`, `O`, and `.`. - `status` is `IN_PROGRESS`, `X_WON`, `O_WON`, or `DRAW`. - `next_player` is `X` or `O` during play, otherwise `-`. - `attempted_player` is the player whose turn it was before the attempt; after the game ends it is `-` for all further attempts. This homogeneous string-matrix encoding makes snapshots portable across languages. A caller can print each snapshot after receiving it. ### Constraints & Assumptions - The board is 3 by 3 and initially empty. `X` starts. - There are at most 100 attempts, each with integer coordinates from 0 through 2. - An occupied-cell attempt is rejected without changing the board or player. - Attempts after a terminal result are rejected without changing the final state. - Check for a win before declaring a full board a draw. - Every output row is an independent snapshot; later moves cannot change prior results. - Starting-player, invalid-move, and serialization rules are explicit practice assumptions. The reported automated-player extension is a separate exercise. ### Examples ```text moves = [[0,0],[1,1]] result = [ ["1","X..","...","...","IN_PROGRESS","O","X"], ["1","X..",".O.","...","IN_PROGRESS","X","O"] ] ``` ```text moves = [[0,0],[0,0]] result = [ ["1","X..","...","...","IN_PROGRESS","O","X"], ["0","X..","...","...","IN_PROGRESS","O","O"] ] ``` ```hint Keep the transition order explicit Separate checking whether a move is allowed, applying it, detecting a terminal result, and choosing whose turn comes next. ```

Overview: Implement two-player Tic-Tac-Toe with automatic turn changes, board snapshots, rejected moves, winning lines, and full-board draws.

Read the full Databricks Software Engineer interview experience this question came from

Implement the state transitions of a two-player Tic-Tac-Toe game. A successful move places the current player's mark, automatically switches players if play can continue, and produces a board snapshot for display. A win or a full-board draw ends the game. Implement `play_tic_tac_toe(moves: int[][]) -> string[][]`. Each input row is an attempted `[row, column]`. Return one output row per attempt, using seven strings in this exact order: ```text [accepted, board_row_0, board_row_1, board_row_2, status, next_player, attempted_player] ``` - `accepted` is `"1"` when a mark was placed and `"0"` otherwise. - Each board row is a length-three string using `X`, `O`, and `.`. - `status` is `IN_PROGRESS`, `X_WON`, `O_WON`, or `DRAW`. - `next_player` is `X` or `O` during play, otherwise `-`. - `attempted_player` is the player whose turn it was before the attempt; after the game ends it is `-` for all further attempts. This homogeneous string-matrix encoding makes snapshots portable across languages. A caller can print each snapshot after receiving it. ### Constraints & Assumptions - The board is 3 by 3 and initially empty. `X` starts. - There are at most 100 attempts, each with integer coordinates from 0 through 2. - An occupied-cell attempt is rejected without changing the board or player. - Attempts after a terminal result are rejected without changing the final state. - Check for a win before declaring a full board a draw. - Every output row is an independent snapshot; later moves cannot change prior results. - Starting-player, invalid-move, and serialization rules are explicit practice assumptions. The reported automated-player extension is a separate exercise. ### Examples ```text moves = [[0,0],[1,1]] result = [ ["1","X..","...","...","IN_PROGRESS","O","X"], ["1","X..",".O.","...","IN_PROGRESS","X","O"] ] ``` ```text moves = [[0,0],[0,0]] result = [ ["1","X..","...","...","IN_PROGRESS","O","X"], ["0","X..","...","...","IN_PROGRESS","O","O"] ] ``` ```hint Keep the transition order explicit Separate checking whether a move is allowed, applying it, detecting a terminal result, and choosing whose turn comes next. ```

Constraints

  • Initially empty 3-by-3 board; X starts.
  • At most 100 attempts, each with coordinates from 0 through 2.
  • Occupied-cell and post-terminal attempts are rejected without state changes.
  • Wins are checked before draw; every result has the exact seven-string snapshot encoding.

Examples

Input: ([[0, 0], [1, 1]],)

Expected Output: [['1', 'X..', '...', '...', 'IN_PROGRESS', 'O', 'X'], ['1', 'X..', '.O.', '...', 'IN_PROGRESS', 'X', 'O']]

Explanation: Accepted moves alternate players and produce separate board snapshots.

Input: ([[0, 0], [0, 0]],)

Expected Output: [['1', 'X..', '...', '...', 'IN_PROGRESS', 'O', 'X'], ['0', 'X..', '...', '...', 'IN_PROGRESS', 'O', 'O']]

Explanation: An occupied-cell attempt leaves O on turn and records O as the attempted player.

Loading coding console...

Show the approach

Approach

Maintain a 3-by-3 board, the current player, the status, and the number of accepted moves. Before each attempt, capture the current player as attempted_player. A terminal state already stores player as minus, so all later attempts report minus. Reject a terminal or occupied-cell attempt without changing anything. Otherwise place the current mark, increment the occupied count, and test the three rows, three columns, and two diagonals for that player. A winning line ends the game before the full-board check; otherwise a full board is a draw, or the player alternates. Serialize a new output row using freshly created board-row strings. Thus every transition matches the contract, rejection consumes no turn, terminal states remain fixed, and subsequent board edits cannot change earlier snapshots. The board is constant-sized, so each attempt takes constant time and working space; returned snapshots take linear space in the number of attempts.

Time complexity:
O(M) for M attempted moves.
Space complexity:
O(1) working space; O(M) returned snapshot storage.