About Us Contact Us Write for Us Advertise
Home > System Design > Low-Level Design > Design Tic-Tac-Toe (Low-Level Design / OOD)
System Design › Low-Level Design

Design Tic-Tac-Toe (Low-Level Design / OOD)

Design Tic-Tac-Toe in an LLD interview with extensibility in mind: Game/Board/Player/Piece classes, O(N) win-checking with running row/column/diagonal counts, and designing for N×N and other grid games.

Shiv Pandey
Shiv Pandey
Oct 28, 2026 | 2 views
Design Tic-Tac-Toe (Low-Level Design / OOD)

🟢 Low-Level Design · Case Study · Fresher-friendly → 🟠 senior

"Design Tic-Tac-Toe" is a friendly LLD warm-up, but the real test is whether you design it to be extensible — to an N×N board, or even a different game like Connect-4 — rather than hardcoding a 3×3 grid. It's a nice showcase of clean OOD on a small, familiar problem. Let's design it well.

The approach in one line: a Game orchestrates turns between Players placing pieces on a Board; the Board is a generic N×N grid, and after each move you check win conditions efficiently — designed so board size and rules can change.

Step 1 — Requirements

  • Functional: two players alternate placing marks on an N×N board; detect a win (full row / column / diagonal) or a draw (board full); reject invalid moves.
  • Non-functional: extensible to any N (and ideally other grid games), efficient win-checking.

Step 2 — The classes

  • Game — orchestrates the flow: whose turn, apply move, check result.
  • Board — an N×N grid of cells; knows how to place a piece and report its state.
  • Player — has a name and a Piece/Symbol (X or O).
  • Piece / Symbol — the mark; making it a type (not a raw char) allows more players/symbols.
  • Position / Move — a (row, col).
  • Enum GameStatus{IN_PROGRESS, WIN, DRAW}.
Game Board (N×N) Player ×2 Piece (X/O) has

Step 3 — Efficient win-checking

🟠 The naive check after every move scans the whole board (O(N²)). A cleaner, O(N)-per-move trick: keep running counters — a count per row, per column, and the two diagonals, incremented (+1 for X, −1 for O) as pieces are placed. After a move at (r,c), if |rowCount[r]| == N or |colCount[c]| == N or a diagonal count hits ±N, that player has won. You only touch the affected row/col/diagonal, and you never rescan the board.

boolean placeAndCheck(int r, int c, int player) {   // player = +1 (X) or -1 (O)
    board[r][c] = player;
    rows[r] += player;  cols[c] += player;
    if (r == c)          diag += player;
    if (r + c == n - 1)  antiDiag += player;
    int win = n;   // need n in a line
    return Math.abs(rows[r])==win || Math.abs(cols[c])==win
        || Math.abs(diag)==win   || Math.abs(antiDiag)==win;
}

Step 4 — Designing for extensibility

🟠 The senior signal is not hardcoding 3: parameterise the board by N and the win-length. Represent symbols as Piece objects so you could add players or symbols. Keeping win-logic in the Board (or a pluggable WinningStrategy) means you could swap in Connect-4 rules (first to 4 in a line, gravity) without rewriting the Game. The Game just manages turns and asks the Board "is this a winning/valid move?" — clean separation of responsibilities.

Step 5 — Turn & status management

🟠 The Game holds a turn pointer (alternating players, or a queue for >2 players), validates each move (in-bounds, cell empty), applies it, then updates GameStatus (WIN if the check passes, DRAW if the board fills with no winner, else IN_PROGRESS). Using a queue of players makes it trivially extensible beyond two.

The interview-ready walkthrough

"I'd model a Game orchestrating Players (each with a Piece) placing on an N×N Board, with a GameStatus enum. I'd not hardcode 3 — parameterise board size and win-length for extensibility. For win-checking I keep running counts per row, column, and diagonal (+1/−1 per symbol) and after each move check only the affected line, so it's O(N) not O(N²). The Game validates and alternates turns (a player queue extends to N players), and I'd keep win-rules pluggable so Connect-4 could reuse the structure." That balances a clean model with the efficiency and extensibility they're probing for."

What to read next

← Design an LRU cache · Design an ATM →

Related Articles

Design a Parking Lot (Low-Level Design / OOD)
System Design › Low-Level Design

Design a Parking Lot (Low-Level Design / OOD)

Design an LRU Cache (O(1) get & put) — Low-Level Design
System Design › Low-Level Design

Design an LRU Cache (O(1) get & put) — Low-Level Design

Design Splitwise / Expense Sharing (Low-Level Design)
System Design › Low-Level Design

Design Splitwise / Expense Sharing (Low-Level Design)

Design BookMyShow / Movie Booking (Low-Level Design)
System Design › Low-Level Design

Design BookMyShow / Movie Booking (Low-Level Design)