Problem statement
Design the object model and core APIs for a Connect Four game engine that runs a single two-player match from an empty grid to a decided result. The engine owns the rules of a token-drop game: players alternate dropping a disc into a column, the disc falls to the lowest free slot under gravity, and the first player to line up four of their own discs in a row wins. Whatever host drives it (a console loop, a GUI, a test harness) only feeds column drops in and reads state back.
Operating context. One in-process match at a time on a rectangular grid of columns and rows (the familiar setup is 7 columns by 6 rows, but the dimensions and the win length arrive as construction parameters — nothing is hard-coded to 7x6-connect-4). Two players alternate turns; each turn the mover names a column, and the disc settles on top of whatever is already stacked there. A drop is legal only when it is the mover's turn, the column index is in range, the column is not already full, and the match is still running. The match ends the instant a drop completes a straight run of the required length horizontally, vertically, or along either diagonal — or in a draw when every slot is filled and no such run exists. Input arrives as (player, column) calls on one thread; there is no clock, no network, and no concurrent access.
Out of scope. Rendering or animating the falling disc, any console I/O or input parsing, an AI opponent or move search, persistence and 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, Column or Cell, Player, Move, Game, plus value objects like Disc or Position), the public API each class exposes, and the state transitions for the match (not-started, in-progress, won, drawn) and for a slot (empty, filled). Be explicit about: how gravity picks the landing row for a dropped disc; how a win is detected in all four directions right after a drop without rescanning the whole grid; how turn ownership is tracked and enforced; how a drop into a full column is rejected without corrupting state; and how the same core extends to a different board size or win length (say 8x8 with connect-5) without rewriting drop handling.