Design an Elevator System
You'll learn to
- -Design the elevator, request, and scheduler classes, and pick a dispatch strategy (e.g. SCAN/LOOK) via Strategy
- -Handle multi-elevator coordination and starvation without over-complicating the first-pass design
The elevator system prompt tests something the parking lot prompt does not: a genuinely interesting scheduling algorithm, plus coordination across multiple elevators competing to serve the same building. It rewards candidates who resist the urge to over-engineer the scheduler on the first pass.
Step 1: Requirements and Core Classes
Assume: a building with multiple elevators, each elevator has a current floor and direction, requests come from both inside the elevator (a passenger pressing a floor button) and outside (a hall call pressing up/down on a floor), and the dispatcher must decide which elevator handles which hall call.
from enum import Enum
class Direction(Enum):
UP = 1
DOWN = -1
IDLE = 0
class Request:
def __init__(self, floor: int, direction: Direction | None = None):
self.floor = floor
self.direction = direction # None for an internal "go to floor" request
class Elevator:
def __init__(self, elevator_id: int):
self.id = elevator_id
self.current_floor = 0
self.direction = Direction.IDLE
self._requests: set[int] = set() # floors this elevator must stop at
def add_request(self, floor: int) -> None:
self._requests.add(floor)
def step(self) -> None:
if not self._requests:
self.direction = Direction.IDLE
return
target = min(self._requests, key=lambda f: abs(f - self.current_floor))
self.direction = Direction.UP if target > self.current_floor else Direction.DOWN
self.current_floor += self.direction.value
if self.current_floor in self._requests:
self._requests.remove(self.current_floor) # arrived, doors openStep 2: SCAN/LOOK Scheduling as a Strategy
Real elevators do not jump straight to the nearest request - they use SCAN (or the more efficient LOOK variant): continue moving in the current direction, picking up every request along the way, and only reverse once there are no more requests in the current direction. This avoids the "elevator bouncing back and forth" behavior a naive nearest-request approach produces, and it is a natural fit for the Strategy pattern from earlier in this course - the scheduling algorithm is exactly the kind of thing that should be swappable behind a common interface.
class SchedulingStrategy(ABC):
@abstractmethod
def next_floor(self, elevator: Elevator) -> int | None: ...
class ScanStrategy(SchedulingStrategy):
def next_floor(self, elevator: Elevator) -> int | None:
requests = elevator._requests
if not requests:
return None
if elevator.direction != Direction.DOWN:
ahead = [f for f in requests if f >= elevator.current_floor]
if ahead:
return min(ahead) # continue up, picking up requests along the way
behind = [f for f in requests if f <= elevator.current_floor]
if behind:
return max(behind) # no more requests ahead - reverse direction
return min(requests, key=lambda f: abs(f - elevator.current_floor))Step 3: Dispatching Among Multiple Elevators
For a hall call (someone on floor 5 pressing "up"), the Dispatcher needs to decide which of N elevators should respond. A reasonable first-pass heuristic: prefer an elevator already moving in the requested direction and about to pass that floor, then fall back to the closest idle elevator - avoiding sending a fully loaded elevator moving away from the request when a closer, idle one is available.
class Dispatcher:
def __init__(self, elevators: list[Elevator]):
self._elevators = elevators
def dispatch(self, request: Request) -> Elevator:
idle = [e for e in self._elevators if e.direction == Direction.IDLE]
candidates = idle or self._elevators # prefer idle; fall back to all
best = min(candidates, key=lambda e: abs(e.current_floor - request.floor))
best.add_request(request.floor)
return bestA strong candidate names the trade-off explicitly here rather than pretending the dispatcher is optimal: "this heuristic is deliberately simple - a production system would also weigh current load and passenger wait time, but for this design, closest-idle-first is a defensible, easy-to-reason-about first pass."
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.