Bird
Raised Fist0
LLDsystem_design~7 mins

Move validation and check detection 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
When move validation and check detection logic are tightly coupled with the main game loop or piece movement code, the system becomes hard to maintain and extend. This coupling leads to duplicated code, bugs when rules change, and difficulty in testing individual parts of the game logic.
Solution
Separate the move validation and check detection into dedicated components or modules. These components independently verify if a move is legal and if the king is in check after a move. This separation allows clear responsibilities, easier testing, and flexible rule updates without affecting the core game flow.
Architecture
Game Loop
Move Validation

This diagram shows the game loop sending move requests to the move validation module, which checks legality using the board state. If valid, the check detection module verifies if the king is under threat, using the king's position and board state.

Trade-offs
✓ Pros
Improves code maintainability by separating concerns.
Enables isolated testing of move rules and check detection.
Facilitates adding new rules or variants without changing core logic.
Reduces bugs caused by duplicated or intertwined logic.
✗ Cons
Introduces additional complexity in communication between modules.
May add slight performance overhead due to modular calls.
Requires careful design to keep modules synchronized with game state.
Use when building chess engines or board games with complex move rules and check conditions, especially if the codebase is expected to grow or require frequent updates.
Avoid if building a very simple or one-off prototype where modularity overhead outweighs benefits, or if performance is critical and profiling shows modular calls are bottlenecks.
Real World Examples
Lichess
Separates move validation and check detection to allow fast, accurate rule enforcement and easy addition of chess variants.
Chess.com
Uses modular validation to support complex rules and real-time move legality checks during online play.
Stockfish
Implements distinct validation and check detection modules to optimize engine evaluation and maintain correctness.
Code Example
The before code mixes move validation and check detection inside the Game class, making it hard to maintain. The after code moves validation and check detection into separate classes, improving modularity and testability.
LLD
### Before: move validation and check detection mixed in Game class
class Game:
    def move(self, from_pos, to_pos):
        # Validate move
        if not self.is_valid_move(from_pos, to_pos):
            return False
        # Make move
        self.board[to_pos] = self.board[from_pos]
        self.board[from_pos] = None
        # Check if king is in check
        if self.is_king_in_check(self.current_player):
            # Undo move
            self.board[from_pos] = self.board[to_pos]
            self.board[to_pos] = None
            return False
        return True

    def is_valid_move(self, from_pos, to_pos):
        # Complex logic here
        pass

    def is_king_in_check(self, player):
        # Complex logic here
        pass

### After: separated MoveValidator and CheckDetector
class MoveValidator:
    def __init__(self, board):
        self.board = board

    def validate(self, from_pos, to_pos):
        # Complex validation logic
        pass

class CheckDetector:
    def __init__(self, board):
        self.board = board

    def is_in_check(self, player):
        # Complex check detection logic
        pass

class Game:
    def __init__(self):
        self.board = ...
        self.validator = MoveValidator(self.board)
        self.check_detector = CheckDetector(self.board)

    def move(self, from_pos, to_pos):
        if not self.validator.validate(from_pos, to_pos):
            return False
        # Make move
        self.board[to_pos] = self.board[from_pos]
        self.board[from_pos] = None
        if self.check_detector.is_in_check(self.current_player):
            # Undo move
            self.board[from_pos] = self.board[to_pos]
            self.board[to_pos] = None
            return False
        return True
OutputSuccess
Alternatives
Monolithic move handling
All move validation and check detection logic is embedded directly in the game loop or piece classes.
Use when: When building very simple or educational chess programs where modularity is not a priority.
Event-driven validation
Move validation and check detection are triggered by events and listeners rather than direct calls.
Use when: When building highly extensible or plugin-based chess platforms requiring dynamic rule changes.
Summary
Separating move validation and check detection prevents tangled code and bugs.
This modular approach improves maintainability and allows easier rule updates.
It is widely used in professional chess engines and online platforms.

Practice

(1/5)
1. What is the primary purpose of move validation in a chess game system?
easy
A. To ensure only legal moves according to game rules are accepted
B. To update the user interface after a move
C. To save the game state to a database
D. To detect if a player is in check

Solution

  1. Step 1: Understand move validation role

    Move validation checks if a move follows the rules of chess, like piece movement and board boundaries.
  2. Step 2: Differentiate from other functions

    Updating UI or saving state are separate tasks; detecting check is related but distinct from move validation.
  3. Final Answer:

    To ensure only legal moves according to game rules are accepted -> Option A
  4. Quick Check:

    Move validation = Legal move check [OK]
Hint: Move validation means checking if a move follows rules [OK]
Common Mistakes:
  • Confusing move validation with UI updates
  • Thinking move validation detects check
  • Assuming move validation saves game state
2. Which of the following code snippets correctly represents a basic move validation check for a rook in chess?
easy
A. if abs(start_row - end_row) == 1 and abs(start_col - end_col) == 1: return True else: return False
B. if start_row == end_row or start_col == end_col: return True else: return False
C. if abs(start_row - end_row) == abs(start_col - end_col): return True else: return False
D. if end_row == start_row + 2 or end_col == start_col + 2: return True else: return False

Solution

  1. Step 1: Recall rook movement rules

    A rook moves any number of squares along a row or column, so either row or column must be the same.
  2. Step 2: Match code to rules

    if start_row == end_row or start_col == end_col: return True else: return False checks if start and end share the same row or column, which matches rook moves.
  3. Final Answer:

    if start_row == end_row or start_col == end_col: return True else: return False -> Option B
  4. Quick Check:

    Rook moves = same row or column [OK]
Hint: Rook moves straight: same row or same column [OK]
Common Mistakes:
  • Confusing rook moves with diagonal moves
  • Using absolute difference for rook incorrectly
  • Checking only fixed steps instead of any distance
3. Given this simplified move validation function for a king:
def is_valid_king_move(start, end):
    row_diff = abs(start[0] - end[0])
    col_diff = abs(start[1] - end[1])
    return (row_diff <= 1 and col_diff <= 1) and (row_diff + col_diff != 0)

What will is_valid_king_move((4,4), (5,5)) return?
medium
A. True
B. False
C. None
D. Error

Solution

  1. Step 1: Calculate row and column differences

    row_diff = |4 - 5| = 1, col_diff = |4 - 5| = 1
  2. Step 2: Evaluate conditions

    row_diff <= 1 and col_diff <= 1 is True; row_diff + col_diff != 0 is True (1+1=2)
  3. Final Answer:

    True -> Option A
  4. Quick Check:

    King moves one step any direction = True [OK]
Hint: King moves one square in any direction, including diagonals [OK]
Common Mistakes:
  • Ignoring diagonal moves for king
  • Mistaking zero move as valid
  • Confusing row and column differences
4. In a check detection system, a bug causes the game to allow moves that leave the king in check. Which is the most likely cause?
medium
A. The system only checks for check after the opponent moves
B. The move validation incorrectly rejects legal moves
C. The system updates the board state before validating moves
D. The system validates moves but does not check if the king remains safe after the move

Solution

  1. Step 1: Understand check detection role

    Check detection ensures no move leaves the king under attack after it is made.
  2. Step 2: Identify bug cause

    If moves are validated but king safety is not checked post-move, illegal moves leaving king in check can occur.
  3. Final Answer:

    The system validates moves but does not check if the king remains safe after the move -> Option D
  4. Quick Check:

    Check detection missing after move = bug [OK]
Hint: Always check king safety after move validation [OK]
Common Mistakes:
  • Assuming move validation covers check detection
  • Checking for check only after opponent moves
  • Updating board before validation causing state errors
5. You are designing a chess engine's move validation and check detection system. Which approach best ensures both correctness and performance?
hard
A. Skip move validation and rely on players to avoid illegal moves
B. Only check if the king is in check before the move, ignoring post-move state
C. First validate move legality, then simulate the move to check if king is in check, rejecting if so
D. Validate moves and check detection simultaneously by scanning the entire board every time

Solution

  1. Step 1: Separate move legality and check detection

    Validate if the move follows piece rules first to avoid unnecessary checks.
  2. Step 2: Simulate move and check king safety

    Temporarily apply the move and verify if the king is attacked; reject if unsafe.
  3. Final Answer:

    First validate move legality, then simulate the move to check if king is in check, rejecting if so -> Option C
  4. Quick Check:

    Validate then simulate for check = best practice [OK]
Hint: Validate move first, then simulate for check detection [OK]
Common Mistakes:
  • Ignoring post-move king safety
  • Checking entire board every time causing slowdowns
  • Skipping move validation entirely