Bird
Raised Fist0

Snake and Ladder Game

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
GameMaster Singleton

GameMaster is a Singleton with volatile instance and synchronized getInstance() to ensure safe lazy initialization in Java.

🎯 Tests if candidate understands volatile prevents instruction reordering and synchronized ensures atomic check-and-set for singleton instance creation.
public class GameMaster {
    private static volatile GameMaster instance;
    private GameMaster() { }
    public static synchronized GameMaster getInstance() {
        if (instance == null) {
            instance = new GameMaster();
        }
        return instance;
    }
}
Board composition of Cells

Board has a composition relationship with Cell array, meaning Board owns Cells lifecycle and Cells cannot exist independently.

🎯 Tests if candidate distinguishes composition (strong lifecycle) from association and understands Board creates and manages Cells internally.
public class Board {
    private final Cell[] cells;
    public Board(int size) {
        cells = new Cell[size];
        for (int i = 0; i < size; i++) {
            cells[i] = new Cell(i);
        }
    }
    public Cell getCell(int position) {
        return cells[position];
    }
}
Dice as Strategy interface

Dice is designed as a Strategy interface to allow different dice rolling algorithms without modifying GameMaster, enforcing OCP.

🎯 Tests if candidate knows interface cannot hold state and Strategy pattern enables runtime behavior change without code modification.
public interface Dice {
    int roll();
}
public class StandardDice implements Dice {
    public int roll() {
        return (int)(Math.random() * 6) + 1;
    }
}
Player state and behavior

Player holds mutable state (position) and behavior (move), showing why Player is a concrete class with encapsulated state.

🎯 Tests if candidate understands why Player cannot be interface due to state and how move method updates position atomically.
public class Player {
    private final String name;
    private int position;
    public Player(String name) {
        this.name = name;
        this.position = 0;
    }
    public synchronized void move(int steps) {
        position += steps;
    }
    public int getPosition() {
        return position;
    }
}
📐
Class Diagram
Class Diagram
       +----------------+
       |    <<Singleton>>|
       |   GameMaster   |
       +----------------+
       | -inst: volatile GameMaster |
       | -board: Board  |
       | -dice: Dice    |
       | -players: List |
       +----------------+
       | +getInstance(): GameMaster [sync]
       | +startGame(): void
       | +playTurn(): void
       +----------------+
              │
              │ composition
              ▼
       +----------------+
       |     Board      |
       +----------------+
       | -cells: Cell[] |
       +----------------+
       | +getCell(int): Cell
       +----------------+
              │ composition
              ▼
       +----------------+
       |     Cell       |
       +----------------+
       | -position: int |
       | -jumpTo: int   |
       +----------------+
       | +getPosition(): int
       | +getJumpTo(): int
       +----------------+
              ▲
              │ association
       +----------------+
       |     Player     |
       +----------------+
       | -name: String  |
       | -position: int |
       +----------------+
       | +move(int): void
       | +getPosition(): int
       +----------------+
              ▲
              │ realization
       +----------------+
       |     Dice       |
       +----------------+
       | +roll(): int   |
       +----------------+
       | <<Strategy>>   |
       +----------------+

This class diagram illustrates four key design decisions in the Snake and Ladder game. First, GameMaster is implemented as a Singleton with a volatile instance and synchronized getInstance() method to ensure thread-safe lazy initialization, preventing partially constructed instances. Second, Board composes Cells, enforcing strong lifecycle ownership; Cells cannot exist without Board, which manages their creation. Third, Dice is an interface representing the Strategy pattern, allowing different dice roll implementations to be plugged in without modifying GameMaster, adhering to the Open-Closed Principle. Finally, Player is a concrete class encapsulating mutable state (position) and synchronized move behavior, demonstrating why an abstract class or interface is insufficient here due to state management needs. These decisions collectively ensure extensibility, thread safety, and clear lifecycle ownership in Java.

Primary Focus

✓ Composition lifecycle + Strategy pattern OCP + Singleton volatile + Abstract class state

Practice

(1/5)
1. In a vehicle rental system, should Vehicle be designed as an abstract class or an interface if it needs to hold common state like licensePlate and rentalStatus? Why?
easy
A. Abstract class, because it forces all subclasses to implement all methods explicitly.
B. Interface, because it allows multiple inheritance and enforces method signatures without state.
C. Interface, because Java interfaces can now have default methods and fields for state.
D. Abstract class, because it can hold shared state and provide default behavior for subclasses.

Solution

  1. Step 1: Analyze state requirements

    Vehicle needs to hold common mutable state like licensePlate and rentalStatus, which interfaces cannot hold as fields.
  2. Step 2: Choose correct OOP construct

    Abstract classes can have instance variables and default method implementations, making them suitable for shared state. Interfaces cannot hold instance state, only constants.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Shared mutable state -> abstract class, not interface [check]
Hint: Shared state needs abstract class, interfaces only define behavior [check]
Common Mistakes:
2. In the Ride Booking system, the FareCalculator class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is this the correct use case?
easy
A. Factory pattern, because it creates FareCalculator instances on demand.
B. Prototype pattern, to clone FareCalculator instances for thread safety.
C. Singleton pattern, to ensure only one FareCalculator instance calculates fares consistently.
D. Builder pattern, to construct FareCalculator with complex parameters.

Solution

  1. Step 1: Identify the pattern from constructor and method signatures

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single shared instance, matching Singleton pattern characteristics.
  2. Step 2: Why Singleton fits FareCalculator

    FareCalculator needs consistent fare rules and shared state (e.g., pricing configs). Singleton avoids multiple inconsistent instances and ensures thread-safe access.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static getInstance() = Singleton [check]
Common Mistakes:
3. In an LRU Cache implemented with a HashMap and Doubly Linked List, which design pattern best describes the role of the Doubly Linked List in maintaining cache order?
easy
A. Iterator pattern, because it maintains the order of elements for quick traversal and eviction.
B. Decorator pattern, as it adds caching behavior to the HashMap without modifying it.
C. Composite pattern, since the list nodes form a tree-like structure representing cache entries.
D. Factory pattern, because it creates nodes dynamically when cache entries are added.

Solution

  1. Step 1: Identify the role of the Doubly Linked List

    The Doubly Linked List maintains the order of cache entries from most recently used to least recently used, enabling quick eviction of the least recently used item.
  2. Step 2: Match the pattern to this role

    The Iterator pattern fits because it provides ordered traversal over the cache entries, allowing the system to efficiently move nodes and evict the least recently used.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Doubly Linked List enables ordered traversal and eviction [check]
Hint: Doubly Linked List enables ordered traversal [check]
Common Mistakes:
4. In the Ride Booking system, the parkVehicle() method checks if a parking spot is available and then marks it occupied. Without synchronization, which exact thread interleaving causes double-booking of the same spot?
medium
A. Thread 1 checks isAvailable() -> true, context switch before marking occupied; Thread 2 checks isAvailable() -> true, both mark occupied.
B. Thread 1 reads spot as occupied, Thread 2 reads spot as free, both park simultaneously.
C. Thread 1 marks spot occupied, Thread 2 waits and then parks after spot is freed.
D. Thread 1 and Thread 2 both wait on a lock, preventing double-booking.

Solution

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

    Without synchronization, Thread 1 reads spot as free (isAvailable() -> true) but is preempted before marking it occupied.
  2. Step 2: Thread 2 also reads spot as free and proceeds to mark it occupied, causing double-booking.

    This is the classic check-then-act gap causing race conditions.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act -> double-booking race [check]
Hint: Check-then-act without sync -> double-booking race [check]
Common Mistakes:
5. Adding a WeekendFeeStrategy to the parking lot pricing requires which minimum change to comply with SOLID principles?
medium
A. Add a boolean flag isWeekend to ParkingLot and handle fees internally.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without modifying existing classes.
C. Extend ParkingLot with a subclass WeekendParkingLot that overrides fee calculation.
D. Modify the existing FeeStrategy class to add weekend logic with an if-statement.

Solution

  1. Step 1: Identify the SOLID principle involved

    The Open/Closed Principle (OCP) requires that classes be open for extension but closed for modification.
  2. Step 2: Evaluate options against OCP

    Add a boolean flag isWeekend to ParkingLot and handle fees internally. adds weekend logic inside ParkingLot, modifying existing code and violating OCP. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without modifying existing classes. creates a new strategy class and injects it, adhering to OCP. Modify the existing FeeStrategy class to add weekend logic with an if-statement. modifies FeeStrategy directly, violating OCP. Extend ParkingLot with a subclass WeekendParkingLot that overrides fee calculation. subclasses ParkingLot, which can cause class explosion and violates single responsibility.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Modifying ParkingLot internals violates OCP -> not minimal change [check]
Hint: OCP: extend with new class, don't modify existing code [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