Bird
Raised Fist0

Design a Chess Game - Board, Pieces, Move Validation, Check Detection, Turn

LLDhardInterview freq: medium
Choose your preparation mode4 modes available
🏗️
Design a Chess Game - Board, Pieces, Move Validation, Check Detection, Turn
Design a robust, extensible chess game engine with move validation, check detection, and turn management using Java OOP principles.
hardGame DesignFreq: medium
Prerequisites:OOP DesignPolymorphismJava Concurrency Basics
⚙️
Functional Requirements
  • Represent an 8x8 chess board with pieces
  • Validate moves according to piece rules and game state
  • Detect check, checkmate, and stalemate conditions
  • Enforce turn order strictly
  • Support piece promotion and castling
  • Prevent illegal moves that leave king in check
  • Allow querying current board state
👤
Use Cases
  • Player makes a move
  • Game engine validates move legality
  • Detect check and checkmate states
  • Switch turns between players
  • Undo last move (optional)
  • Display board state
🧑‍💻
Actors
  • Player
  • Game Engine
  • UI Renderer
  • Move Validator
❓
Clarifying Questions to Ask
  • How many concurrent players or threads can interact with the game engine? (Usually 1 active player thread)
  • Is there a need for undo/redo functionality and how should it be handled?
  • Should the system support asynchronous move validation or is synchronous validation sufficient?
  • Are draw conditions like threefold repetition or 50-move rule required?
  • How should illegal moves be reported or handled?
  • Is there a pricing or monetization strategy affecting design? (e.g., premium features)
  • What edge cases should be handled, such as promotion to different pieces or en passant?
Out of Scope
✗ Network multiplayer
✗ AI opponent
✗ Time controls and clocks
✗ Move history persistence
✗ Graphical UI rendering
⚡
QPS Calculation
expected moves per second1
peak concurrent games1000
total qps1000
🖥️
Server Estimate
servers needed2
rationaleTwo servers to handle peak load with redundancy and failover.
🔢
Enumerations
enum PieceType
KING | QUEEN | ROOK | BISHOP | KNIGHT | PAWN
Defines all chess piece types explicitly to prevent typo bugs and enable exhaustive switch statements for move logic.
enum Color
WHITE | BLACK
Represents player sides; using enum avoids string errors and allows clear color-based logic.
enum GameState
ONGOING | CHECK | CHECKMATE | STALEMATE | DRAW
Tracks overall game status to enforce rules and end conditions, enabling clear state transitions.
enum MoveType
NORMAL | CASTLING | EN_PASSANT | PROMOTION
Categorizes move kinds to handle special rules and validations distinctly.
📦
Position
2 fields
private final int rowprivate final int column
Immutable value object representing a cell on the chess board with row and column coordinates.
public boolean equals(Object obj)Overrides equals to compare positions by row and column.
public int hashCode()Overrides hashCode consistent with equals.
public String toString()Returns human-readable position like 'e4'.
📦
Piece
4 fields
private final PieceType typeprivate final Color colorprivate Position positionprivate boolean hasMoved
Abstract base class for all chess pieces holding type, color, current position, and move state.
public abstract List<Position> getLegalMoves(Board board)Abstract method to compute legal moves for the piece on the given board.
public synchronized void moveTo(Position newPosition)Atomically updates piece position and marks hasMoved true.
public boolean isOpponentPiece(Piece other)Checks if another piece belongs to the opponent.
📦
Board
1 fields
private final Piece[][] grid = new Piece[8][8]
Represents the chess board grid and manages piece placement and retrieval.
public synchronized Piece getPieceAt(Position position)Returns the piece at the given position or null if empty.
public synchronized void setPieceAt(Position position, Piece piece)Places a piece at the specified position atomically.
public synchronized boolean movePiece(Position from, Position to)Atomically moves a piece if valid; returns success status.
📦
Move
5 fields
private final Position fromprivate final Position toprivate final MoveType moveTypeprivate final Piece movedPieceprivate final Piece capturedPiece
Encapsulates a move including source, destination, type, and involved pieces.
public boolean isCapture()Returns true if the move captures an opponent piece.
public String toString()Returns a string representation of the move.
📦
Game
4 fields
private final Board boardprivate volatile Color currentTurnprivate volatile GameState gameStateprivate final List<Move> moveHistory
Manages game lifecycle, turn order, move validation, and game state transitions.
public synchronized boolean makeMove(Move move)Validates and executes a move atomically, updates game state and turn.
public synchronized boolean isInCheck(Color color)Checks if the specified color's king is under attack.
private synchronized void switchTurn()Switches currentTurn to the other player.
public GameState getGameState()Returns current game state.
📦
MoveValidator
0 fields
Provides static methods to validate moves according to chess rules and current board state.
public static boolean isValidMove(Board board, Move move, Color currentTurn)Checks if the move is legal including piece rules and check prevention.
public static boolean wouldCauseCheck(Board board, Move move, Color color)Simulates move to verify if it leaves king in check.
🔗
Relationships
Game◆──►Board[1 to 1]
compositionBoard lifecycle bound to Game lifecycle
Board◇──►Piece[1 to 0..32]
aggregationPieces can exist independently of Board
🗄️
Games
PK: game_id
game_id UUIDcreated_at TIMESTAMPcurrent_turn VARCHARgame_state VARCHAR
Stores metadata and current state of each chess game.
🗄️
Moves
PK: game_id
game_id UUIDmove_number INTfrom_position VARCHARto_position VARCHARmove_type VARCHARmoved_piece VARCHARcaptured_piece VARCHAR
Stores moves made in each game in order.
🔌
MakeMove
Request
{
  "game_id": "UUID",
  "from": "String (e.g., 'e2')",
  "to": "String (e.g., 'e4')",
  "promotion_piece": "Optional String"
}
Response
{
  "success": "Boolean",
  "message": "String",
  "game_state": "String"
}
Validates and applies a move if legal, returns updated game state.
🔌
GetBoardState
Request
{
  "game_id": "UUID"
}
Response
{
  "board": "2D array of pieces or empty",
  "current_turn": "String",
  "game_state": "String"
}
Returns current board layout and game status.
🔌
UndoMove
Request
{
  "game_id": "UUID"
}
Response
{
  "success": "Boolean",
  "message": "String",
  "game_state": "String"
}
Reverts last move if undo is supported and allowed.

Practice

(1/5)
1. In designing the User and Message classes for the messaging system, should User be an abstract class or an interface, and why?
easy
A. User should be an interface to allow multiple inheritance of user behaviors.
B. User should be an interface because it only defines behavior without state.
C. User should be an abstract class because it holds common user state like userId and username.
D. User should be an abstract class to enforce implementation of all methods in subclasses.

Solution

  1. Step 1: Analyze if User has state or just behavior

    User holds common state such as userId and username, which requires fields and possibly default implementations.
  2. Step 2: Determine if abstract class or interface fits state and behavior

    Abstract class supports shared state and partial implementation, while interface cannot hold instance state.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    User has common state -> abstract class fits better than interface [check]
Hint: Stateful base class -> abstract class, stateless -> interface [check]
Common Mistakes:
2. In the ATM system, the Transaction class uses a private constructor and exposes a static synchronized getInstance() method to create transaction objects. Which design pattern is applied here and why is it the correct choice?
easy
A. Factory Method pattern, because it allows subclasses to decide which Transaction subclass to instantiate.
B. Singleton pattern, because it ensures only one Transaction instance exists system-wide.
C. Builder pattern, because it separates complex Transaction construction from its representation.
D. Singleton pattern, because synchronized getInstance() ensures thread-safe lazy initialization.

Solution

  1. Step 1: Identify the pattern from private constructor and static synchronized getInstance()

    This is a classic Singleton pattern implementation ensuring only one instance per JVM with thread-safe lazy initialization.
  2. Step 2: Eliminate other patterns

    Factory Method involves subclassing and delegation, not private constructors. Builder separates construction steps, unrelated here. Singleton pattern, because it ensures only one Transaction instance exists system-wide. is wrong because Singleton is about single instance, but synchronized getInstance() is the key for thread safety.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized getInstance() -> thread-safe Singleton [check]
Hint: Private constructor + synchronized getInstance() -> thread-safe Singleton [check]
Common Mistakes:
3. In a concurrent Job Scheduler, if the scheduleJob() method is not synchronized, which exact thread interleaving causes the same Job to be scheduled twice?
medium
A. Thread 1 and Thread 2 both call scheduleJob() simultaneously and both succeed without checks.
B. Thread 1 adds job, then Thread 2 removes it before completion, causing inconsistency.
C. Thread 1 checks if job exists -> false, context switch; Thread 2 checks -> false; both add job concurrently.
D. Thread 1 waits for Thread 2 to finish scheduling, causing deadlock.

Solution

  1. Step 1: Identify the check-then-act race condition

    Both threads check if the job is already scheduled before adding. Without synchronization, both see job absent.
  2. Step 2: Trace thread interleaving

    Thread 1 checks -> false, context switch before adding; Thread 2 checks -> false, adds job; Thread 1 resumes and adds job again, causing double scheduling.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Check-then-act gap without synchronization -> double scheduling [check]
Hint: Check-then-act gap -> double scheduling race [check]
Common Mistakes:
4. To support ElectricCar needing ChargingSpot in the vending machine parking design, what is the minimum change that respects extensibility without modifying existing classes?
hard
A. Create a new ChargingSpot class extending Spot and modify ParkingLot to handle it specially.
B. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
C. Modify existing Vehicle and Spot classes to add electric-specific fields and logic.
D. Add a boolean isElectric flag to Vehicle and Spot classes and add conditional logic everywhere.

Solution

  1. Step 1: Identify extensibility requirements

    Adding new vehicle and spot types without modifying existing classes preserves OCP and avoids class explosion.
  2. Step 2: Evaluate options for minimal invasive change

    Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly. adds new enum values and a subclass, updating compatibility map without changing existing classes. Others modify existing classes or add flags causing complexity.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New enums and subclass extend design without modifying existing classes [check]
Hint: Add enums + subclass + compatibility map, no existing class changes [check]
Common Mistakes:
5. The ESPNcricinfo system needs to support ElectricCar vehicles that require ChargingSpot parking spots. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Modify Vehicle class to add isElectric flag and add charging logic inside existing Spot classes.
B. Create a new ElectricCar class and ChargingSpot class, then modify ParkingLot to handle both types explicitly.
C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar extends Vehicle, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
D. Add a new method in Vehicle interface for charging and implement it only in ElectricCar.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and new subclasses allows extension without changing existing class code.
  2. Step 2: Update compatibility map for new types

    Updating SpotCompatibility.COMPATIBILITY_MAP supports new vehicle-spot matching without altering existing logic.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Extend enums + new subclasses + update compatibility map -> no existing class changes [check]
Hint: Extend enums + new subclasses + compatibility map -> minimal change [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard