Build a Configurable Two-Player Tic-Tac-Toe Board in React
RobloxFrontend Engineer · Technical ScreenLast updated
Tests your ability to architect a scalable, accessible React component with dynamic state, efficient win-detection logic for large grid sizes, and robust handling of prop updates.
Problem Statement
Implement a configurable, two-player Tic-Tac-Toe component in React. The component accepts an integer prop size ($N \times N$ board) where $3 \le N \le 20$.
Two players alternatingly place marks on the board: Player X always starts first, followed by Player O. The game ends when either player places $N$ consecutive marks in any row, column, or diagonal, or when all cells are filled resulting in a draw.
Functional Requirements
- Board Rendering: Render an $N \times N$ grid of clickable cells based on the
sizeprop (default to3if omitted or invalid). - Turn Management: Alternate turns starting with
'X'. Clicking an already occupied cell or clicking after the game is over must have no effect. - Win & Draw Detection: Identify a winner immediately when $N$ marks align horizontally, vertically, or diagonally. If all $N^2$ cells are filled without a winner, declare a draw.
- Status Display: Display whose turn it is (e.g.,
"Turn: X"), who won (e.g.,"Winner: X"), or if it is a draw (e.g.,"Draw!"). - Reset Action: Provide a button that resets the current game without unmounting the component.
- Prop Reactivity: If the
sizeprop changes at runtime, reset the game state to match the new board size. - Accessibility (a11y): Use semantic grid semantics (
role="grid",role="row",role="gridcell"), make cells keyboard-navigable (Tab/Enter), and ensure status updates are announced to screen readers viaaria-live.
Component Signature
interface TicTacToeProps {
size?: number; // integer between 3 and 20, default 3
}
export const TicTacToe: React.FC = ({ size = 3 }) => {
// Implementation
};
Required Selectors (data-testid)
To facilitate automated testing, your component must include:
status: For the text element displaying current turn, winner, or draw.cell-{row}-{col}: Zero-indexed cell buttons (e.g.,cell-0-0,cell-2-1).reset-button: For the reset button.
Performance & Edge Cases
- At $N = 20$, the board has 400 cells. Avoid scanning the entire $N \times N$ matrix on every move; instead, determine game outcome in $O(1)$ or $O(N)$ time per move using row, column, and diagonal counters.
- Guard against invalid prop updates (e.g., non-integers, values $ 20$).
Hints
Hint 1
Rather than traversing all cells after every move, maintain count arrays for rows, columns, and the two diagonals where 'X' adds 1 and 'O' subtracts 1.
Hint 2
Handle the `size` prop change either by tracking previous size in state or using a `key` pattern to reset board state automatically.
Hint 3
Ensure screen readers announce turns and game outcomes dynamically by adding an `aria-live="polite"` region to your status message.
Follow-up questions
- How would you modify the win-checking algorithm if the win condition is modified to $K$ in a row (e.g., Gomoku style: $K=5$ on a $20 \times 20$ board)?
- How would you implement full undo/redo functionality while preserving $O(1)$ time complexity per move?
- If this board were connected to a real-time WebSocket backend for multiplayer play, how would you handle optimistic updates and race conditions?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.