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

OA: Shop inventory with timed holds and backorders

hard 4 levels ~90 min

Level 1 Stock and orders

You're building the stock service for a small online shop. Implement InventorySystem, which starts with no stock. Every method takes a timestamp first (an integer, milliseconds). Timestamps never decrease from one call to the next. Products are identified by a SKU string, and quantities are positive integers.

Placing an order doesn't ship anything yet. It holds the units, so nobody else can take them, until the order is fulfilled or cancelled.

  • add_stock(timestamp, sku, quantity) -> int: new units arrive. Return how many units of sku are now free (in stock and not held).
  • get_stock(timestamp, sku) -> int: the free units of sku (0 for a SKU never seen).
  • get_reserved(timestamp, sku) -> int: the units of sku currently held by orders.
  • place_order(timestamp, skus, quantities) -> str | None: an order for quantities[i] units of skus[i]. A SKU can appear on several lines; the order then needs their total. If every line can be covered by free units, hold them all and return an id: "order1", "order2", … numbered across the whole system, counting only orders that were accepted. Otherwise return None and change nothing.
  • fulfil_order(timestamp, order_id) -> bool: the held units ship: they stop being held and are gone. False unless the order is pending.
  • cancel_order(timestamp, order_id) -> bool: the held units become free again. False unless the order is pending.
  • order_status(timestamp, order_id) -> str | None: "pending", "fulfilled" or "cancelled", or None for an unknown id.
inv = InventorySystem()
inv.add_stock(1, "apple", 10)                                # 10
inv.add_stock(2, "pear", 3)                                  # 3
inv.place_order(3, ["apple", "pear"], [4, 1])                # "order1"
inv.get_stock(4, "apple")                                    # 6
inv.get_reserved(5, "apple")                                 # 4
inv.place_order(6, ["pear", "apple", "pear"], [2, 1, 1])     # None: needs 3 pears, only 2 free
inv.place_order(7, ["apple"], [6])                           # "order2"
inv.fulfil_order(8, "order1")                                # True
inv.get_reserved(9, "apple")                                 # 6
inv.cancel_order(10, "order2")                               # True
inv.get_stock(11, "apple")                                   # 6
inv.cancel_order(12, "order1")                               # False: already fulfilled
inv.order_status(13, "order2")                               # "cancelled"

Constraints

  • skus and quantities have the same length, between 1 and 10. Quantities are at most 10^6.
  • Up to 10^5 calls. Aim for each call to cost O(lines in the order).
Show hint

Keep two numbers per SKU, free and held, and one record per order holding its lines and its status.

Level 2 unlocks when level 1 passes.

Level 3 unlocks when level 2 passes.

Level 4 unlocks when level 3 passes.

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

0:00
Ctrl ' run · Ctrl ↵ submit
esc