LLD · Simulation
Elevator Control System
A small interview design for elevator classes, dispatch, and SCAN movement. Further reading: Hello Interview — Elevator.
The system manages several elevators. A controller assigns hall calls, while
each elevator owns its requests and moves one simulated tick at a time through
step().
1. Problem understanding and requirements
Prompt: “Design an elevator control system for a building.” Before coding, agree on the scale, request types, simulation model, and exclusions.
Clarifying questions (interview script)
- Scale: 3 elevators, 10 floors (0–9), fixed for now.
- Hall calls: Classic UP/DOWN buttons (not destination dispatch panels).
- Inside elevator: Multiple destination floors allowed.
- Time model: Simulation with
step()/tick()— not hardware interrupts. - Invalid input: Reject bad floors; current-floor request = no-op.
- Out of scope: Capacity, weight sensors, doors, emergency stops.
| Feature | Requirement |
|---|---|
| Capacity | 3 elevators, floors 0–9 |
| Hall call | Floor + direction (UP / DOWN) |
| Destination | Floor only (selected inside the elevator) |
| Simulation | controller.step() advances all elevators one tick |
| Validation | Return false for invalid floor; ignore same-floor requests |
2. Core entities
Use three main classes. Each class owns the state and behavior it understands best.
-
ElevatorController — entry point; receives hall calls;
picks which elevator to dispatch; runs
step()on all elevators. - Elevator — one lift: current floor, direction, request set; movement logic. Does not know about other elevators.
-
Request — value object: target floor + type
(
PICKUP_UP,PICKUP_DOWN,DESTINATION).
3. Enums and value objects
Enums limit direction and request type to known values.
4. Class design
Elevator
Use a Set<Request> so repeated presses for the same floor
and request type create only one pending request.
ElevatorController
5. Dispatch: picking the best elevator
When someone presses UP on floor 5, the controller must choose one elevator.
| Strategy | Idea | Problem |
|---|---|---|
| Nearest | Min distance to floor | May pick an elevator moving away from the call |
| Direction-aware | Prefer elevator moving toward floor in same direction | Ignores whether the lift has already passed the floor |
| Request-aware (best) | Direction + position: elevator will pass the floor before reversing | Slightly more code — preferred in interviews |
Trap: same direction and nearest is not enough
You are on floor 4 and press DOWN (want ground). Elevator A is on floor 3 going DOWN.
A simple rule might pick A because it has the same direction and is only one floor away. That choice is wrong: A is below floor 4 and moving farther away.
Correct rule: For a DOWN call at floor F, prefer an elevator above F that is already moving down. For an UP call, prefer one below F that is already moving up. An idle elevator is the next choice.
Example: Hall call at floor 3 UP. Elevator A at floor 1 going UP → good. Elevator B at floor 6 going DOWN → worse; it must reverse before serving 3 UP.
6. Movement: SCAN (scanning) algorithm
With SCAN, an elevator keeps moving in one direction and
serves matching stops along the way. When no request remains ahead, it
reverses if requests exist behind it; otherwise, it becomes IDLE.
This avoids the repeated back-and-forth movement that a simple FIFO queue can cause.
Direction-aware stopping
Only stop for hall calls that match travel direction.
7. Simulation loop
8. Concurrency
A hall call may arrive while step() is running. One thread could
modify requests during iteration, or two threads could assign the
same idle elevator.
-
Option A — Mutex: Lock around
requestElevator()andstep(). Simple and correct; threads may wait. -
Option B — Drain queue: Thread-safe inbound queue per
elevator; at start of
step(), drain into the internalSet. Separates writes from movement reads.
9. Extensibility and interview depth
-
Express elevator:
boolean isExpressonElevator; controller routes floors 0, 5, 9 only to that lift. -
Cancel request:
removeRequest(floor, type)— trivial with aSet; nextstep()skips if removed. - Junior: Entities + basic movement loop.
- Mid: SCAN + clean IDLE → UP/DOWN transitions.
- Senior: Dispatch tradeoffs, concurrency, express/cancel extensions.
Quick revision
- Scope: 3 elevators, floors 0–9, and a
step()simulation; doors and capacity are excluded. - Entities: Controller (dispatch), Elevator (movement), Request (floor + type).
- Request types:
PICKUP_UP,PICKUP_DOWN,DESTINATION. - Dispatch: Serving elevator → idle nearest → any nearest.
- Dispatch trap: Direction alone is not enough; the elevator must also be approaching the caller.
-
SCAN / scanning: Lift moves in one direction, checks each floor;
serves all stops that way; when none ahead, reverse if opposite requests exist, else
IDLE. - Movement: Stop only if hall-call direction matches travel direction.
- State: Use a
Set<Request>for deduplication andIDLEwhen no request remains. - Concurrency: Protect shared state with a mutex or drain a thread-safe input queue each tick.