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

Greenhouse watering rota

easy ~15 min

A greenhouse volunteer wants a small tool that says which plants need water today. Each plant has its own interval: a fern every 3 days, a cactus every 10. Model it as a class that owns its state, validates every call, and never ends up half-updated.

Implement class Greenhouse:

  • Greenhouse() starts empty. Days are integers (day numbers, not dates).
  • add_plant(name, every, day): pot a new plant on day. Potting counts as a watering on that day. every is how many days it can go between waterings.
    • ValueError if a plant called name already exists, or if every isn't a positive integer.
  • water(name, day): record that name was watered on day.
    • KeyError for an unknown plant; ValueError if day is earlier than that plant's last watering (the log only moves forward; the same day again is fine).
  • remove_plant(name): KeyError if unknown.
  • due(day) -> list[str]: every plant whose next watering (last watering + every) is on or before day. Most overdue first (largest day - next watering), ties broken by name A→Z. Doesn't change anything.

A call that raises must leave the greenhouse exactly as it was.

g = Greenhouse()
g.add_plant("fern", 3, day=0)
g.add_plant("cactus", 10, day=0)
g.add_plant("basil", 1, day=2)
g.due(3)             # ["basil", "fern"]   both due exactly on day 3
g.water("fern", 4)
g.due(5)             # ["basil"]           fern is next due on day 7
g.due(12)            # ["basil", "fern", "cactus"]   overdue by 9, 5 and 2 days
g.water("fern", 1)   # ValueError: earlier than day 4
g.add_plant("fern", 2, day=5)   # ValueError: already exists
g.water("mint", 5)   # KeyError
Show hint

Keep one dict from name to a small record (a dataclass with every and last). Do all the checks at the top of each method, before assigning anything; due is a filter plus sorted(..., key=lambda n: (-(overdue), n)).

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

0:00
Ctrl ' run · Ctrl ↵ submit
esc