Bird
Raised Fist0
LLDsystem_design~7 mins

Special moves (castling, en passant) in LLD - System Design Guide

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Problem Statement
Without special handling, chess game logic cannot correctly enforce or recognize unique moves like castling and en passant. This leads to incorrect game states, illegal moves being allowed, and a poor player experience.
Solution
Implement explicit rules and state tracking for special moves within the chess game logic. For castling, verify conditions such as unmoved king and rook, empty spaces, and no check along the path. For en passant, track the opponent's last pawn move and allow capture only immediately after. This ensures the game enforces these rare but critical moves correctly.
Architecture
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│ Player Move   │──────▶│ Move Validator│──────▶│ Game State    │
│ Input         │       │ (includes     │       │ (tracks board,│
│               │       │ special moves)│       │ move history) │
└───────────────┘       └───────────────┘       └───────────────┘
                                │                       ▲
                                │                       │
                                └───────────────────────┘

This diagram shows the flow from player input through move validation including special moves, updating the game state with board and move history.

Trade-offs
✓ Pros
Ensures correct enforcement of chess rules for special moves, preserving game integrity.
Improves player experience by allowing all legal moves.
Enables easier debugging and extension by isolating special move logic.
✗ Cons
Adds complexity to move validation logic.
Requires additional state tracking, increasing memory usage slightly.
May introduce subtle bugs if special move conditions are not exhaustively checked.
When building a complete chess game engine that must support all official chess rules including special moves.
For simplified chess variants or educational tools where special moves are intentionally omitted to reduce complexity.
Real World Examples
Lichess
Implements castling and en passant rules in their open-source chess engine to ensure official chess rules compliance.
Chess.com
Handles special moves in their game logic to provide accurate gameplay and fair competition.
Code Example
The before code only checks basic moves without special rules. The after code adds methods to detect and validate castling and en passant moves, tracking necessary state like king and rook movement and move history.
LLD
### Before: naive move validation without special moves
class ChessGame:
    def is_valid_move(self, start, end):
        # Only basic move validation
        return self.is_valid_basic_move(start, end)

### After: enhanced validation including castling and en passant
class ChessGame:
    def __init__(self):
        self.board = ...
        self.move_history = []
        self.king_moved = {'white': False, 'black': False}
        self.rook_moved = {'white': {'a': False, 'h': False}, 'black': {'a': False, 'h': False}}

    def is_valid_move(self, start, end):
        if self.is_castling_move(start, end):
            return self.can_castle(start, end)
        if self.is_en_passant_move(start, end):
            return self.can_en_passant(start, end)
        return self.is_valid_basic_move(start, end)

    def can_castle(self, start, end):
        # Check king and rook unmoved, path clear, not in check
        pass

    def can_en_passant(self, start, end):
        # Check last move was opponent pawn double step adjacent
        pass

    def is_castling_move(self, start, end):
        # Detect castling move pattern
        pass

    def is_en_passant_move(self, start, end):
        # Detect en passant move pattern
        pass
OutputSuccess
Alternatives
Simplified move validation
Ignores special moves and only validates basic piece movements.
Use when: When building a minimal chess demo or teaching basic piece movement without full rule enforcement.
Summary
Special moves like castling and en passant require explicit rules and state tracking in chess game logic.
Proper validation ensures legal moves and maintains game integrity.
Implementing these rules adds complexity but is essential for a complete chess engine.

Practice

(1/5)
1. Which of the following conditions must be true for castling to be allowed in a chess game?
easy
A. The king is currently in check and moves two squares towards the rook.
B. Neither the king nor the rook involved has moved before, and no pieces are between them.
C. The rook has moved once, but the king has not moved.
D. The king moves diagonally two squares towards the rook.

Solution

  1. Step 1: Understand castling rules

    Castling requires that neither the king nor the rook involved has moved before, and the squares between them are empty.
  2. Step 2: Check king safety conditions

    The king cannot be in check, nor can it pass through or land on a square under attack during castling.
  3. Final Answer:

    Neither the king nor the rook involved has moved before, and no pieces are between them. -> Option B
  4. Quick Check:

    Castling conditions = Neither the king nor the rook involved has moved before, and no pieces are between them. [OK]
Hint: Castling needs unmoved king and rook with clear path [OK]
Common Mistakes:
  • Allowing castling when king is in check
  • Ignoring if rook has moved
  • Allowing king to move diagonally during castling
2. Which code snippet correctly checks if an en passant move is possible in a chess game for an opponent pawn landing to the right?
easy
A. if pawn.just_moved_two_squares and opponent_pawn.position == pawn.position + (1, 0): allow_en_passant()
B. if pawn.just_moved_two_squares and opponent_pawn.position == pawn.position + (0, -1): allow_en_passant()
C. if pawn.just_moved_two_squares and opponent_pawn.position == pawn.position + (0, 1): allow_en_passant()
D. if pawn.just_moved_two_squares and opponent_pawn.position == pawn.position + (-1, 0): allow_en_passant()

Solution

  1. Step 1: Understand en passant position logic

    En passant capture happens when an opponent's pawn moves two squares forward and lands beside your pawn horizontally.
  2. Step 2: Identify correct position offset

    The opponent pawn must be exactly one square horizontally adjacent (x+1 or x-1), so position + (1, 0) is correct for right side.
  3. Final Answer:

    if pawn.just_moved_two_squares and opponent_pawn.position == pawn.position + (1, 0): allow_en_passant() -> Option A
  4. Quick Check:

    En passant horizontal check = if pawn.just_moved_two_squares and opponent_pawn.position == pawn.position + (1, 0): allow_en_passant() [OK]
Hint: En passant checks horizontal adjacency after two-step pawn move [OK]
Common Mistakes:
  • Checking vertical instead of horizontal adjacency
  • Using wrong coordinate offsets
  • Ignoring the two-square move condition
3. Given this simplified code snippet for castling validation, what will be the output if the king has moved before?
def can_castle(king_moved, rook_moved, path_clear):
    if king_moved or rook_moved:
        return False
    if not path_clear:
        return False
    return True

print(can_castle(True, False, True))
medium
A. None
B. True
C. False
D. Error

Solution

  1. Step 1: Analyze input parameters

    king_moved is True, rook_moved is False, path_clear is True.
  2. Step 2: Follow function logic

    Since king_moved is True, the first if condition triggers and returns False immediately.
  3. Final Answer:

    False -> Option C
  4. Quick Check:

    King moved disables castling = False [OK]
Hint: If king moved, castling returns False immediately [OK]
Common Mistakes:
  • Ignoring king_moved condition
  • Assuming path_clear overrides king_moved
  • Expecting True despite king having moved
4. Identify the bug in this en passant validation code snippet:
def can_en_passant(pawn_pos, opponent_pawn_pos, last_move):
    if last_move == 'two_squares_forward' and abs(pawn_pos[0] - opponent_pawn_pos[0]) == 1:
        return True
    return False

# Example call
print(can_en_passant((4,4), (5,4), 'two_squares_forward'))
medium
A. The function should return False when pawns are adjacent.
B. The function incorrectly compares x-coordinates instead of y-coordinates.
C. The last_move parameter should be a boolean, not a string.
D. The function does not check if pawns are on the same rank (y-coordinate).

Solution

  1. Step 1: Understand en passant position requirements

    En passant requires pawns to be on the same rank (same y-coordinate) and adjacent files (x-coordinates differ by 1).
  2. Step 2: Analyze code logic

    The code checks x-coordinate difference but does not verify if y-coordinates are equal, missing a key condition.
  3. Final Answer:

    The function does not check if pawns are on the same rank (y-coordinate). -> Option D
  4. Quick Check:

    Missing same rank check = The function does not check if pawns are on the same rank (y-coordinate). [OK]
Hint: En passant needs same rank check besides adjacency [OK]
Common Mistakes:
  • Ignoring y-coordinate equality
  • Assuming x difference alone suffices
  • Misusing last_move parameter type
5. You are designing a chess game system that supports castling and en passant. Which design approach best ensures correct validation of these special moves while keeping the system scalable?
hard
A. Track each piece's move history and board state; validate special moves by checking move history and current board conditions.
B. Only check the current board state without tracking move history, assuming special moves are rare.
C. Allow special moves without validation to simplify the system and fix errors later.
D. Hardcode special move rules without tracking piece movement or board state.

Solution

  1. Step 1: Understand requirements for special moves

    Castling and en passant depend on move history (e.g., whether king or rook moved, or if pawn moved two squares last turn) and current board state.
  2. Step 2: Evaluate design options

    Tracking move history and board state allows accurate validation and supports scalability as game complexity grows.
  3. Final Answer:

    Track each piece's move history and board state; validate special moves by checking move history and current board conditions. -> Option A
  4. Quick Check:

    Move history + board state = correct scalable validation [OK]
Hint: Track moves and board state for reliable special move validation [OK]
Common Mistakes:
  • Ignoring move history for special moves
  • Hardcoding rules without flexibility
  • Skipping validation to simplify design