Problem statement
Design the object model and core APIs for a two-player Tic-Tac-Toe game engine that a single process runs to drive a match from empty board to a decided outcome. The engine owns the rules; whatever sits on top of it (a console loop, a GUI, a test harness) merely feeds moves in and reads state back.
Operating context. One match at a time, two players who alternate placing their mark on a 3x3 grid. A cell holds at most one mark and is never overwritten. A move is legal only when it is the current player's turn and the target cell is empty and the game is still running. The match ends the moment a player fills a full line (row, column, or either diagonal) with their mark, or in a draw when every cell is filled with no such line. All input arrives as (player, row, column) calls; there is no clock, no network, and no concurrent access — the engine is driven by one caller on one thread.
Out of scope. Rendering / drawing the board, any input parsing or console I/O, an AI opponent or move-search, persistence or save/resume, and networking or matchmaking. Design only the in-process rules engine and its object model, not the UI or transport around it.
What to produce. The class hierarchy (entities such as Board, Cell, Player, Move, Game, and any value objects like Mark or Position), the public API each class exposes, and the state transitions for the game (e.g. not-started, in-progress, won, drawn) and for a cell (empty, marked). Be explicit about: how illegal moves are rejected without corrupting state, how a win or draw is detected after each move, how turn ownership is tracked and enforced, and how the same rules core would extend to an NxN board (win = a full line of N) without rewriting move handling.
Must do 5
Functional requirements
- Apply a move given (player, row, column): validate it, place the mark, and advance the turn to the other player.
- Reject an illegal move (wrong turn, occupied or out-of-range cell, or a game that has already ended) without mutating the board or turn.
- Detect a win immediately after a move when the mover completes a full row, column, or diagonal.