Course contents

LLD problem — Elevator

Sign in to run this lab and save your progress

Learn

Before you start

Elevator is a classic design problem that combines two module-3 patterns: State (idle/up/down) and Strategy (dispatch algorithm). Whether you use them BOTH, ONE, or NEITHER is the design decision.

The state question

An elevator has three phases: idle, moving up, moving down. Each step() behaves differently:

  • Idle → check requests, maybe pick a direction, maybe stay
  • Moving up → move to next floor, maybe stop, maybe keep going
  • Moving down → same, other direction

Full State pattern (one class per state) is one answer. A simple _direction field plus branching in step() is another. Both work. Argue your choice.

The strategy question

"How do we pick the next floor?" has multiple valid algorithms:

  • SCAN (this lesson) — go all the way up, then all the way down
  • LOOK — reverse as soon as there are no more requests in the current direction
  • Nearest-car / SSTF — always go to the closest pending request

If you make dispatch a Strategy, swapping algorithms is one line. If you inline SCAN, adding LOOK later touches step(). Argue your choice — for MVP, either is defensible.

The rules discipline

Elevator has strong rules:

  • Floor always in [0, N-1]. Never overshoot the bounds.
  • Serving a floor clears requests. Both external calls (both directions) and internal selects for that floor.
  • Idle → no motion. No requests, no movement.

Each has a clear place to enforce it. Name them.

Interviewer follow-up questions

For design problems, always anticipate these:

  • "How would you add multiple elevators?" — a bank of elevators + a dispatcher. Introduces the "which elevator takes this call" problem. A new Strategy layer.
  • "How would you handle express floors (skip some)?" — per-elevator config; SCAN skips not-allowed floors.
  • "How would you handle door-open events?" — a new state (stopping-with-door-open). State pattern shines here.

Your design.md doesn't have to answer these — but if it puts your code in a position where answering them is easy, that's the extensibility signal interviewers care about.

Your task

Model a single elevator serving multi-floor requests. Emphasizes STATE and STRATEGY signals in one problem.

The problem

One elevator, N floors (0 to N-1). Riders press:

  • External buttons (on floors) to CALL the elevator going up or down: call(floor, direction) where direction is "up" or "down".
  • Internal buttons (inside the car) to SELECT a destination floor: select(floor).

The elevator moves ONE floor per step() call (this is the tick). Each step, based on the pending calls + selections AND the current direction, it decides: move up, move down, or stay (idle).

Movement rules (simple SCAN):

  • If there are pending stops in the current direction of travel, keep going that way. Stop at each requested floor along the way.
  • When no more stops in the current direction, reverse.
  • If no stops anywhere → go idle.
  • Stopping at a floor: fulfil ALL calls/selections at that floor (both directions).

Requirement-gathering questions

  1. Doors / dwell time? — Not modeled. Stopping = fulfilled.
  2. Weight capacity? — Not for MVP.
  3. Multiple elevators? — No, one elevator.
  4. Emergency stop? — Not for MVP.
  5. Dispatch algorithm? — SCAN for MVP, but design should leave room for other strategies (LOOK, nearest-car, round-robin between banks). Hint: Strategy signal.

Design goals

  • State — idle vs moving-up vs moving-down have real different behavior per step.
  • Strategy — replacing SCAN with LOOK should be a manageable change.
  • Invariants: floor always in [0, N-1]; never move past bounds; fulfilled requests get cleared.

Your task

Public API:

from main import Elevator

el = Elevator(num_floors=10)   # starts idle at floor 0
el.call(3, "up")               # someone on floor 3 wants up
el.call(7, "down")             # someone on floor 7 wants down
el.select(5)                   # someone inside wants floor 5

el.step()                      # tick — returns dict:
                               #   {"floor": int, "direction": "up"|"down"|"idle",
                               #    "stopped": bool}
el.floor()                     # int
el.direction()                 # "up"|"down"|"idle"
el.pending_stops()             # sorted list of floors with active calls/selects

When the elevator STOPS at a floor, all calls and selections for that floor are cleared (in ONE tick).

Click Submit to run the tests.

Starter files

Preview only — open the lab to edit and run.

files_dir
05-elevator-starter