~/problems / Simulation & OOP design / Object-oriented design and extensible simulations

OA: Dasher pay from an event stream

medium 3 levels ~60 min DoorDash

Level 1 Paid minutes

A dasher's day is a list of events (minute, order_id, status), sorted by minute. Several events can share a minute; list order is the order they happened. For now, status is one of:

  • "ACCEPTED": the dasher takes the order.
  • "FULFILLED": the order is delivered.
  • "CANCELED": the order is called off.

Every order is accepted exactly once and then gets at most one FULFILLED or CANCELED, which always comes later in the list.

The dasher earns rate cents for each minute in which at least one delivery that ends up fulfilled is in progress. A fulfilled order is in progress over the half-open range [accepted minute, fulfilled minute). Several orders at once still earn rate once per minute. Canceled orders, and orders still open at the end of the list, earn nothing and don't count toward covered minutes.

Write dasher_pay(events: list[tuple[int, str, str]], rate: int) -> int, returning total pay in cents.

Minutes can be as large as 10^9 and there can be 100,000 orders, so don't loop minute by minute. Keep the code tidy: a small record per order (a dataclass works well) makes the later levels easy.

events = [
    (0, "a", "ACCEPTED"),
    (5, "b", "ACCEPTED"),
    (10, "a", "FULFILLED"),   # a covers [0, 10)
    (12, "c", "ACCEPTED"),
    (15, "b", "FULFILLED"),   # b covers [5, 15)
    (20, "c", "CANCELED"),    # c earns nothing
]
dasher_pay(events, 30)   # covered minutes [0, 15) -> 15 * 30 = 450

Level 2 unlocks when level 1 passes.

Level 3 unlocks when level 2 passes.

Topic: Object-oriented design and extensible simulations. Classes that survive new requirements: games, payments, subscriptions, refactors.

0:00
Ctrl ' run · Ctrl ↵ submit
esc