Machine Coding Round: Tic Tac Toe (Advanced)
Design and implement a production-ready version of a Tic Tac Toe game that fulfills the following:
- Game is played between 2 players on a NxN board (not limited to 3x3).
- Support for dynamic board size (N >= 3).
- Players take turns placing their mark (X or O).
- Detect Win/Draw conditions dynamically for any size N.
- Validate inputs to prevent overwrites or invalid moves.
- Extendable to more than 2 players in the future.
- Pluggable win strategy (horizontal, vertical, diagonal, custom win rules).
- AI player (computer opponent) with simple strategies.
- Game logs should be printed after every move.
- Easily testable and extendable for mobile or web frontends.
src/
|-- model/ # Game Models (Player, Cell, Board)
|-- service/ # Business Logic (GameService)
|-- factory/ # Different Players
|-- strategy/ # Win Strategy (Interface + Implementations)
|-- util/ # Helper classes (Logger, Validator)
|-- controller/ # Entry point, input/output control
|-- Main.java # Game bootstrapper-
Strategy Pattern
- Where:
strategy/WinStrategy.java - Why: The game needs to check winning conditions in different ways (horizontal, vertical, diagonal, custom rules). Using Strategy Pattern allows us to plug in new winning rules without modifying the existing code, just by implementing the
WinStrategyinterface. - Benefit: Promotes Open/Closed Principle (OCP) and allows easy testing of win logic independently.
- Where:
-
Factory Pattern (optional but powerful)
- Where: Can be added in
PlayerFactory. - Why: Helps decouple the object creation logic from the main controller. Useful if we need to dynamically create HumanPlayer, AIPlayer, etc.
- Benefit: Simplifies extensibility and object creation logic. Future-proof design.
- Where: Can be added in
-
Singleton Pattern
- Where:
Logger.java - Why: There should be only one logging instance in the game. Singleton ensures controlled access to logging.
- Benefit: Global point of access, ensures logging consistency.
- Where:
-
S - Single Responsibility Principle (SRP)
- Each class has only one responsibility.
GameServicemanages game flow,Boardmanages grid state,WinStrategyonly checks win logic.
- Each class has only one responsibility.
-
O - Open/Closed Principle (OCP)
- New
WinStrategyimplementations can be added without modifying the game logic. The code is open to extension but closed for modification.
- New
-
L - Liskov Substitution Principle (LSP)
- Any class implementing the
WinStrategyinterface can be used in place of any other, without breaking the game logic. Ensures flexibility and reusability.
- Any class implementing the
-
I - Interface Segregation Principle (ISP)
- Interfaces like
WinStrategyare small and specific. We avoid having large interfaces that force implementation of unused methods.
- Interfaces like
-
D - Dependency Inversion Principle (DIP)
GameServicedepends on abstractions likeWinStrategyrather than concrete classes. This allows flexibility and improves testability.
- Encapsulation: Internal state like player details, cell status, and board dimensions are encapsulated.
- Abstraction:
WinStrategyabstracts the winning logic, andGameServiceabstracts the game engine. - Inheritance/Polymorphism: Multiple classes implement
WinStrategyand can be used interchangeably. - Composition: Game is composed of models like
Board,Player, and strategies to drive behavior.
Would you like me to continue with detailed class implementations in this document?