Setting Requirements and Objects
What this lesson covers
This lesson starts the main project of the low level design series, a turn-based game AI engine, by deliberately writing it with no class diagram and no thought for extensibility. The point is to show that such code feels easy in the short term but leads to repeated refactoring as new concepts are introduced and requirements change. Starting from a simple product requirement, being able to play a game through AI, the video identifies the backend APIs: a start function that returns a board, a move function that applies a player's move to a board, and an isComplete function. A boolean is shown to be insufficient for completion, because callers need to know both whether the game is over and who won or whether it was a draw, so a GameResult object is introduced. Board, Player, Move and GameResult classes are created on the fly in a single file, which the lesson notes often happens in interviews. To make things concrete, a TicTacToeBoard extends Board with a three by three grid of cells that hold X or O. The win check iterates over rows, columns, the main diagonal and the reverse diagonal, comparing each cell with the first character of its line, with small optimizations such as breaking out early and returning as soon as a line is complete. A draw is detected when every cell is filled. The resulting code is long, repetitive and handles only tic-tac-toe, which sets up the critique in the following lessons.
- Code written without upfront design is quick at first but tends to need repeated refactoring
- The engine's core API is start, move and isComplete
- A boolean cannot express both completion and the winner, so a GameResult object is needed
- The tic-tac-toe win check covers rows, columns and both diagonals, plus a draw when the board is full
- Game-specific checks inside the engine make it hard to extend to games such as chess