Your Code. Their Wait Time.

Write a dispatch algorithm in JavaScript. Watch it succeed—or strand passengers on floor 7. A classic coordination puzzle, now with real-time feedback and nowhere to hide.

Loading simulator...

Elevator Simulation Documentation

Learn how to write algorithms that control elevators to transport passengers efficiently.

Quick Start

Your algorithm controls elevators to pick up waiting passengers and deliver them to their destinations. The goal is to minimize wait times and maximize throughput.

The init and update functions are optional. You can rely entirely on events if you prefer.

{
  init: function(elevators, floors, store) {
    // Called once when simulation starts
    // Set up event handlers and initial state

    elevators.forEach(elevator => {
      elevator.on('idle', function() {
        // Elevator has no destinations - what should it do?
      });

      elevator.on('floorButtonPressed', function(floorNum) {
        // A passenger inside pressed a floor button
        elevator.goToFloor(floorNum);
      });
    });

    floors.forEach(floor => {
      floor.on('callButtonPressed', function(direction) {
        // Someone pressed the call button on this floor
      });
    });
  },

  update: function(dt, elevators, floors, store) {
    // Called every tick - use for periodic logic
  }
}

Elevator API

Properties

elevator.id- Unique identifier (number)
elevator.currentFloor- Current floor number (0-indexed)
elevator.destinationQueue- Array of floor numbers to visit
elevator.passengers- Array of passengers currently riding
elevator.direction- 'up' | 'down' | 'stopped'
elevator.state- 'idle' | 'moving' | 'opening' | 'open' | 'closing'

Movement Methods

goToFloor(n, sorted?)
Add floor to queue. If sorted=true, inserts based on current direction.
goToFloorNow(n)
Move floor n to the front of the queue (keeps other stops).
stop()
Clear the destination queue (does not interrupt a current move).

Status Methods

loadFactor()- Returns 0-1 ratio of passengers to capacity
isFull()- Returns true if at capacity
isEmpty()- Returns true if no passengers
getPassengerCount()- Returns number of passengers
getAvailableSpace()- Remaining capacity

Direction Methods

destinationDirection()- Returns 'up', 'down', or 'stopped'
isGoingToward(floor)- Returns true if elevator will pass floor
getOtherElevators()- Returns array of all other elevators

Queue & Buttons

getPressedFloors()- Floors pressed inside the car
getDestinationQueue()- Current destination queue (copy)
getPassengerDestinations()- Destination floors for onboard passengers

Events

Elevator Events

elevator.on('idle', fn)
Fired when elevator has no destinations
elevator.on('floorButtonPressed', fn)
Fired when passenger presses button inside
elevator.on('stoppedAtFloor', fn)
Fired when elevator stops and opens doors
elevator.on('passengerBoarded', fn)
Fired when a passenger boards (fn(passenger))
elevator.on('passengerExited', fn)
Fired when a passenger exits (fn(passenger))

Floor Events

floor.on('callButtonPressed', fn)
Fired when someone presses call button. Callback receives direction.

Floor API

Floor Properties & Methods

floor.floorNum- Floor number (0-indexed)
floor.buttonStates- Object with {up: bool, down: bool}
floor.waitingPassengers- Array of passengers waiting
floor.getWaitingCount(dir?)- Number of waiting passengers

Store API

The store is persistent key-value storage that persists across ticks. Use it to coordinate between elevators and track global state.

Key-Value Storage

store.get(key)- Get value for key (or undefined)
store.set(key, value)- Store a value
store.has(key)- Check if key exists
store.delete(key)- Remove a key
store.clear()- Remove all keys
store.keys()- Array of all keys
store.getAll()- Snapshot of all entries

Data Structures

Passenger Object

{
  id: "120-4821",
  origin: 3,
  destination: 7,
  spawnTick: 120,
  pickupTick: 140,
  arrivalTick: 200,
  state: "waiting",  // "arriving" | "waiting" | "riding" | "arrived"
  direction: "up"
}

Simulation Config

{
  numElevators: 3,
  numFloors: 10,
  spawnRate: 20,  // percent chance per tick
  seed: 42,
  maxTicks: 2000
}

Sandbox & Determinism

Seeded RNG: Math.random() and rand() are deterministic per simulation seed.

Deterministic clock: Date.now(), new Date(), and performance.now() use a tick-based clock (tick * 1000 ms) with UTC formatting.

Runtime guard: init, update, and event handlers must finish within 50ms.

Reset required: Editing code or config marks the simulation stale. Hit Reset to apply changes.

Console output: console.log()/warn()/error() appear in the event log.

Available globals: Math, rand, Date, performance, Number, String, Array, Object, JSON, Boolean, parseInt, parseFloat, isNaN, isFinite.

Unavailable APIs (non-deterministic):
setTimeout / setInterval / requestAnimationFrame
queueMicrotask / setImmediate / Promise
fetch / XMLHttpRequest / WebSocket
crypto.getRandomValues / randomUUID
Function / eval
navigator / document / location
localStorage / sessionStorage / indexedDB
process / require
Intl
BroadcastChannel / Worker / postMessage

Tips & Strategies

Basic Strategy

  • Always handle the 'idle' event to keep elevators moving
  • Use 'floorButtonPressed' to add passenger destinations
  • Check isFull() before picking up more passengers
  • Use goToFloor(n, true) for sorted insertion

SCAN Algorithm

  • Move in one direction until no more requests that way
  • Then reverse direction
  • Pick up passengers along the way
  • Like a real elevator - efficient for high traffic

Zone Assignment

  • Assign each elevator a range of floors
  • Reduces conflicts between elevators
  • Use overlapping zones for flexibility
  • Track assignments in the store

Coordination

  • Use store to track which requests are claimed
  • Prevent multiple elevators responding to same call
  • Consider distance AND direction when dispatching

Live Metrics

Performance Metrics

Transported: Total passengers delivered to their destination.

Average Wait: Mean time from spawn to pickup (lower is better).

Max Wait: Longest any passenger waited (minimize this!).

Waiting: Current passengers waiting at floors.

Riding: Current passengers in elevators.

Leaderboard Scoring

Algorithms run on 1,000 canonical seeds. Lower scores rank higher.

wait_per_seed = average(pickupTick - spawnTick for each transported passenger)
final_score = average(wait_per_seed over all canonical seeds)
Built for learning algorithms through simulation