📂
Interview Prep
LLD Questions
LLD Questions
  • LLD Introduction
  • Meeting Scheduler
  • Distributed Cache System
  • Rate limiter
  • Multi-Tier Elevator System
  • MyGate System
  • Uber Sytem LLD
  • Parking Lot System
  • Online book store
  • Library Management System
  • Movie Ticket Booking System
  • Hotel Management System
  • File Storage System
    • Solution 2
  • Chat Application
  • Social Media Platform
  • Notification System
  • Airline Reservation System
  • ATM System
  • E-commerce Website
  • Food Delivery System
  • Shopping Cart System
  • URL Shortener system
  • Chess Tournament System
  • Threading therory
  • OOP questions
Powered by GitBook
On this page
  • 1. System Overview and Entities
  • 2. Detailed Java Code
  • 3. Explanation and Pros/Cons
  • 4. Conclusion

Chess Tournament System

Below is a comprehensive low‑level design (LLD) for a Chess Tournament System implemented in Java. This design models the core entities (Players, Matches, Rounds, and the Tournament) and uses several design patterns to create a modular and extensible system. In our design we use:

  • Singleton Pattern: To ensure that only one instance of the TournamentManager exists.

  • Factory Pattern: To encapsulate the creation of Match objects.

  • Strategy Pattern: To enable different pairing algorithms (for example, Round‑Robin pairing) when scheduling rounds.

  • Observer Pattern: To notify observers (such as a ScoreBoard or players) when match results are updated.

Below is the detailed explanation along with Java code examples and inline comments.


1. System Overview and Entities

Core Entities

  • Player: Represents a chess player (with name, rating, and unique ID).

  • Match: Represents a game between two players. It holds references to the two players, a result (WIN, LOSS, DRAW, or PENDING), and a scheduled time.

  • Round: Represents one round of the tournament and holds a list of matches.

  • ChessTournament: Aggregates all players and rounds.

  • TournamentManager (Singleton): Coordinates tournament operations, such as scheduling rounds and recording results.

Pairing Strategy

  • PairingStrategy (Strategy Pattern): An interface that defines how to pair players for matches in each round. We provide a concrete implementation (e.g. RoundRobinPairingStrategy) to illustrate one pairing method.

Observers

  • MatchObserver (Observer Pattern): An interface for objects that want to receive notifications when a match result is updated. For example, a ScoreBoard observer might update the overall standings.


2. Detailed Java Code

import java.time.LocalDateTime;
import java.util.*;

// --------------------- ENUMS ---------------------

enum MatchResult {
    WIN, LOSS, DRAW, PENDING
}

// --------------------- ENTITIES ---------------------

// Represents a chess player.
class Player {
    private String playerId;
    private String name;
    private int rating;
    
    public Player(String playerId, String name, int rating) {
        this.playerId = playerId;
        this.name = name;
        this.rating = rating;
    }
    
    public String getPlayerId() { return playerId; }
    public String getName() { return name; }
    public int getRating() { return rating; }
    
    @Override
    public String toString() {
        return name + " (" + rating + ")";
    }
}

// Represents a match between two players.
class Match {
    private Player player1;
    private Player player2;
    private MatchResult result;
    private LocalDateTime scheduledTime;
    
    // Observers for match result updates.
    private List<MatchObserver> observers = new ArrayList<>();
    
    public Match(Player player1, Player player2, LocalDateTime scheduledTime) {
        this.player1 = player1;
        this.player2 = player2;
        this.scheduledTime = scheduledTime;
        this.result = MatchResult.PENDING;
    }
    
    public Player getPlayer1() { return player1; }
    public Player getPlayer2() { return player2; }
    public MatchResult getResult() { return result; }
    public LocalDateTime getScheduledTime() { return scheduledTime; }
    
    // Update match result and notify observers.
    public void setResult(MatchResult result) {
        this.result = result;
        notifyObservers("Result updated to: " + result);
    }
    
    public void addObserver(MatchObserver observer) {
        observers.add(observer);
    }
    
    private void notifyObservers(String message) {
        for (MatchObserver observer : observers) {
            observer.update(this, message);
        }
    }
    
    @Override
    public String toString() {
        return player1 + " vs " + player2 + " at " + scheduledTime + " [" + result + "]";
    }
}

// Represents a round in the tournament.
class Round {
    private int roundNumber;
    private List<Match> matches;
    
    public Round(int roundNumber) {
        this.roundNumber = roundNumber;
        this.matches = new ArrayList<>();
    }
    
    public int getRoundNumber() { return roundNumber; }
    public List<Match> getMatches() { return matches; }
    
    public void addMatch(Match match) {
        matches.add(match);
    }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("Round " + roundNumber + ":\n");
        for (Match match : matches) {
            sb.append("  ").append(match).append("\n");
        }
        return sb.toString();
    }
}

// Represents the chess tournament.
class ChessTournament {
    private String tournamentId;
    private String name;
    private List<Player> players;
    private List<Round> rounds;
    
    public ChessTournament(String tournamentId, String name) {
        this.tournamentId = tournamentId;
        this.name = name;
        this.players = new ArrayList<>();
        this.rounds = new ArrayList<>();
    }
    
    public String getTournamentId() { return tournamentId; }
    public String getName() { return name; }
    public List<Player> getPlayers() { return players; }
    public List<Round> getRounds() { return rounds; }
    
    public void addPlayer(Player player) {
        players.add(player);
    }
    
    public void addRound(Round round) {
        rounds.add(round);
    }
}

// --------------------- OBSERVER PATTERN ---------------------

// Observer interface for match updates.
interface MatchObserver {
    void update(Match match, String message);
}

// Concrete observer that could update a scoreboard.
class ScoreBoardObserver implements MatchObserver {
    @Override
    public void update(Match match, String message) {
        System.out.println("ScoreBoard Update: " + match + " -> " + message);
    }
}

// --------------------- FACTORY PATTERN ---------------------

/*
 * Factory Pattern: MatchFactory centralizes creation of Match objects.
 */
class MatchFactory {
    public static Match createMatch(Player player1, Player player2, LocalDateTime scheduledTime) {
        return new Match(player1, player2, scheduledTime);
    }
}

// --------------------- STRATEGY PATTERN ---------------------

/*
 * Strategy Pattern: PairingStrategy defines how players are paired for matches.
 */
interface PairingStrategy {
    List<Match> generateMatches(List<Player> players, LocalDateTime scheduledTime);
}

// A simple Round-Robin pairing strategy.
class RoundRobinPairingStrategy implements PairingStrategy {
    @Override
    public List<Match> generateMatches(List<Player> players, LocalDateTime scheduledTime) {
        List<Match> matches = new ArrayList<>();
        int n = players.size();
        // For round-robin, every player plays with every other player once.
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j < n; j++) {
                Match match = MatchFactory.createMatch(players.get(i), players.get(j), scheduledTime);
                matches.add(match);
            }
        }
        return matches;
    }
}

// --------------------- SINGLETON: TOURNAMENT MANAGER ---------------------

/*
 * Singleton Pattern: TournamentManager is responsible for managing the tournament.
 */
class TournamentManager {
    private static TournamentManager instance;
    private ChessTournament tournament;
    private PairingStrategy pairingStrategy;
    
    private TournamentManager() {
        // Default pairing strategy is RoundRobin.
        pairingStrategy = new RoundRobinPairingStrategy();
    }
    
    public static synchronized TournamentManager getInstance() {
        if (instance == null) {
            instance = new TournamentManager();
        }
        return instance;
    }
    
    public void setTournament(ChessTournament tournament) {
        this.tournament = tournament;
    }
    
    public ChessTournament getTournament() {
        return tournament;
    }
    
    public void setPairingStrategy(PairingStrategy strategy) {
        this.pairingStrategy = strategy;
    }
    
    // Schedule a new round using the pairing strategy.
    public void scheduleRound(LocalDateTime scheduledTime) {
        if (tournament == null || tournament.getPlayers().isEmpty()) {
            System.out.println("Tournament or player list is not initialized.");
            return;
        }
        int roundNumber = tournament.getRounds().size() + 1;
        Round round = new Round(roundNumber);
        List<Match> matches = pairingStrategy.generateMatches(tournament.getPlayers(), scheduledTime);
        // For simplicity, we add all generated matches in this round.
        for (Match match : matches) {
            // Optionally, add observers to each match.
            match.addObserver(new ScoreBoardObserver());
            round.addMatch(match);
        }
        tournament.addRound(round);
        System.out.println("Scheduled " + round);
    }
}

// --------------------- MAIN APPLICATION ---------------------

public class ChessTournamentApp {
    public static void main(String[] args) {
        // Create a tournament.
        ChessTournament tournament = new ChessTournament("T001", "Spring Chess Championship");
        
        // Add players.
        tournament.addPlayer(new Player("P001", "Alice", 2000));
        tournament.addPlayer(new Player("P002", "Bob", 1950));
        tournament.addPlayer(new Player("P003", "Charlie", 2100));
        tournament.addPlayer(new Player("P004", "Diana", 2050));
        
        // Get the TournamentManager singleton.
        TournamentManager manager = TournamentManager.getInstance();
        manager.setTournament(tournament);
        
        // Schedule a round at a given time.
        LocalDateTime scheduledTime = LocalDateTime.now().plusDays(1);
        manager.scheduleRound(scheduledTime);
        
        // For demonstration, update a match result.
        // Let’s say the first match in the first round.
        if (!tournament.getRounds().isEmpty()) {
            Round firstRound = tournament.getRounds().get(0);
            if (!firstRound.getMatches().isEmpty()) {
                Match firstMatch = firstRound.getMatches().get(0);
                firstMatch.setResult(MatchResult.WIN);
            }
        }
    }
}

3. Explanation and Pros/Cons

OOP Concepts & Entities

  • Encapsulation & Abstraction: Each entity (Player, Match, Round) encapsulates its own data and behavior, hiding complex logic from other parts of the system.

  • Modularity: Classes are designed to have single responsibilities (e.g., Match only handles match-related data), improving maintainability.

Design Patterns Employed

  1. Singleton Pattern (TournamentManager):

    • Pros: Ensures a single point of control over tournament management and reduces resource overhead.

    • Cons: Can create tight coupling and hinder testing if global state isn’t managed properly.

  2. Factory Pattern (MatchFactory):

    • Pros: Centralizes object creation, making it easy to change the creation process without affecting client code.

    • Cons: Introduces an extra layer of abstraction which may be unnecessary for very simple objects.

  3. Strategy Pattern (PairingStrategy):

    • Pros: Provides flexibility in choosing different pairing algorithms (e.g., RoundRobin, Swiss-system) without modifying the TournamentManager.

    • Cons: Increases the number of classes and requires careful design to switch strategies dynamically.

  4. Observer Pattern (MatchObserver):

    • Pros: Decouples the subject (Match) from its observers, allowing dynamic subscription and notification of events.

    • Cons: Can lead to unexpected behavior if observers are not managed carefully (e.g., memory leaks from unregistered observers).

Use Case in Tournament Management

  • Scheduling Rounds: The TournamentManager uses the pairing strategy to generate matches for a round and notifies observers (like a scoreboard) when match results update.

  • Result Updates: Matches notify registered observers when their state changes, keeping external components in sync.


4. Conclusion

This LLD for a Chess Tournament System demonstrates a robust, modular design by leveraging core OOP principles and multiple design patterns. It provides:

  • Clear modeling of entities (Player, Match, Round, ChessTournament).

  • A flexible tournament management solution using the Singleton, Factory, Strategy, and Observer patterns.

  • An extendable framework where different pairing algorithms and observer implementations can be plugged in without significant changes to the core system.

This detailed explanation and accompanying code serve as a strong blueprint for designing complex tournament systems and can be further extended to cover more advanced tournament formats or real‑time updates in production environments.

Feel free to ask for further clarifications or additional examples!

PreviousURL Shortener systemNextThreading therory

Last updated 2 months ago