return f"{self.__name}: ({self.__height_cm}cm, {self.__age_days} days)"
@staticmethod
- def __reject_with_message(operation: str, msg: str):
+ def __reject_with_message(operation: str, msg: str) -> None:
print(f"\nInvalid operation attempted: {operation} [REJECTED]")
print(f"Security: {msg}")
@staticmethod
- def __accept_update(field: str, value: str):
+ def __accept_update(field: str, value: str) -> None:
print(f"{field} updated: {value} [OK]")
- def set_height(self, height_cm: int):
+ def set_height(self, height_cm: int) -> None:
if height_cm < 0:
self.__reject_with_message(
f"height {height_cm}cm", "Negative height rejected"
self.__accept_update("Height", f"{height_cm}cm")
self.__height_cm = height_cm
- def set_age(self, age_days: int):
+ def set_age(self, age_days: int) -> None:
if age_days < 0:
self.__reject_with_message(
f"age {age_days} days", "Negative age rejected"
", ", self.get_attributes()
)
- def action(self):
+ def action(self) -> None:
pass
def get_attributes(self) -> list[str]:
return super().get_attributes() + [f"{self.color} color"]
- def bloom(self):
+ def bloom(self) -> None:
print(f"{self.name} is blooming beautifully!")
- def action(self):
+ def action(self) -> None:
self.bloom()
def __init__(
self, name: str, height_cm: int, age_days: int, trunk_diameter_cm: int
- ):
+ ) -> None:
super().__init__(name, height_cm, age_days)
self.trunk_diameter_cm = trunk_diameter_cm
f"{self.trunk_diameter_cm}cm diameter"
]
- def produce_shade(self):
+ def produce_shade(self) -> None:
shade = round(self.trunk_diameter_cm * self.height_cm / 3.2 / 100)
print(f"{self.name} provides {shade} square meters of shade")
- def action(self):
+ def action(self) -> None:
self.produce_shade()
age_days: int,
harvest_season: str,
nutritional_value: str,
- ):
+ ) -> None:
super().__init__(name, height_cm, age_days)
self.harvest_season = harvest_season
self.nutritional_value = nutritional_value
def get_attributes(self) -> list[str]:
return super().get_attributes() + [f"{self.harvest_season} harvest"]
- def nutritional_info(self):
+ def nutritional_info(self) -> None:
print(f"{self.name} is rich in {self.nutritional_value}")
- def action(self):
+ def action(self) -> None:
self.nutritional_info()
--- /dev/null
+def join(sep: str, elements: list[str]) -> str:
+ res: str | None = None
+ for s in elements:
+ if res is None:
+ res = s
+ else:
+ res += sep + s
+ if res is not None:
+ return res
+ return ""
+
+
+class Plant:
+ __name: str
+ __height_cm: int = 0
+
+ def __init__(self, name: str, height_cm: int) -> None:
+ self.__name = name.capitalize()
+ if height_cm >= 0:
+ self.__height_cm = height_cm
+ else:
+ print("[Warning] attempted to instantiate plant with bad height")
+ print("[Warning] defaulting to 0")
+
+ def get_attributes(self) -> list[str]:
+ return [f"{self.__height_cm}cm"]
+
+ def get_type(self) -> str:
+ return "regular"
+
+ def __repr__(self) -> str:
+
+ return f"{self.__name}: " + join(", ", self.get_attributes())
+
+ def get_name(self) -> str:
+ return self.__name
+
+ def get_height(self) -> int:
+ return self.__height_cm
+
+ def grow(self) -> int:
+ """returns the number of centimeters gained"""
+ self.__height_cm += 1
+ print(f"{self.get_name()} grew 1cm")
+ return 1
+
+
+class FloweringPlant(Plant):
+ color: str
+
+ def __init__(self, name: str, height_cm: int, color: str) -> None:
+ super().__init__(name, height_cm)
+ self.color = color
+
+ def get_attributes(self) -> list[str]:
+ return super().get_attributes() + [f"{self.color} flowers (blooming)"]
+
+ def get_type(self) -> str:
+ return "flowering"
+
+
+class PrizeFlower(FloweringPlant):
+ __prize_points: int
+
+ def __init__(
+ self, name: str, height_cm: int, color: str, prize_points: int
+ ) -> None:
+ super().__init__(name, height_cm, color)
+ self.__prize_points = prize_points
+
+ def get_attributes(self) -> list[str]:
+ return super().get_attributes() + [
+ f"Prize points: {self.__prize_points}"
+ ]
+
+ def get_prize_points(self) -> int:
+ return self.__prize_points
+
+ def get_type(self) -> str:
+ return "prize flowers"
+
+
+class Garden:
+ class GardenReport:
+ new_plants: int = 0
+ growth: int = 0
+
+ @staticmethod
+ def count_types(plants: list[Plant]) -> dict[str, int]:
+ res = {}
+ for plant in plants:
+ if plant.get_type() in res:
+ res[plant.get_type()] += 1
+ else:
+ res[plant.get_type()] = 1
+ return res
+
+ def update_growth(self, growth: int) -> None:
+ self.growth += growth
+
+ def update_plant_count(self, count: int) -> None:
+ self.new_plants += count
+
+ def finish(self, plants: list[Plant]) -> str:
+ types = join(
+ ", ",
+ [
+ f"{n} {kind}"
+ for (kind, n) in self.count_types(plants).items()
+ ],
+ )
+ return (
+ f"Plants added: {self.new_plants}, "
+ + f"Total growth: {self.growth}cm\n"
+ + f"Plant types: {types}"
+ )
+
+ plants: list[Plant]
+ report: GardenReport
+
+ def __init__(self) -> None:
+ self.plants = []
+ self.report = self.GardenReport()
+
+ def add_plant(self, plant: Plant) -> None:
+ self.plants += [plant]
+ self.report.update_plant_count(1)
+
+ def grow_all(self) -> None:
+ for plant in self.plants:
+ self.report.update_growth(plant.grow())
+
+ def next_report(self) -> str:
+ report = self.report.finish(self.plants)
+ self.report = self.GardenReport()
+ return (
+ f"Plants in garden:\n"
+ + join("", [f"- {plant}\n" for plant in self.plants])
+ + f"\n{report}"
+ )
+
+
+class GardenManager:
+ class GardenStats:
+ @staticmethod
+ def compute_scores(gardens: dict[str, Garden]) -> dict[str, int]:
+ def compute_score(garden: Garden) -> int:
+ res = 0
+ for plant in garden.plants:
+ if type(plant) is PrizeFlower:
+ res += plant.get_prize_points()
+ return res
+
+ res = {}
+ for k, v in gardens.items():
+ res[k] = compute_score(v)
+ return res
+
+ @staticmethod
+ def format_scores(scores: dict[str, int]) -> str:
+ return "Garden scores - " + join(
+ ", ", [f"{owner}: {n}" for (owner, n) in scores.items()]
+ )
+
+ __gardens: dict[str, Garden] = {}
+
+ def grow_garden(self, owner: str) -> None:
+ print(f"\n{owner} is helping all plants grow...")
+ self.__gardens[owner].grow_all()
+
+ def add_plant(self, owner: str, plant: Plant) -> None:
+ if owner not in self.__gardens:
+ self.__gardens[owner] = Garden()
+ self.__gardens[owner].add_plant(plant)
+ print(f"Added {plant.get_name()} to {owner}'s garden")
+
+ def print_report(self, owner: str) -> None:
+ print(
+ f"\n=== {owner}'s Garden Report ===\n"
+ + self.__gardens[owner].next_report()
+ )
+
+ @staticmethod
+ def create_garden_network(gardens: dict[str, Garden]):
+ res = GardenManager()
+ res.__gardens = gardens
+ for garden in res.__gardens.values():
+ garden.next_report()
+ return res
+
+ def print_stats(self) -> None:
+ scores = self.GardenStats.compute_scores(self.__gardens)
+ print()
+ print(self.GardenStats.format_scores(scores))
+ print(f"Total gardens managed: {len(self.__gardens)}")
+
+
+if __name__ == "__main__":
+ print("=== Garden Management System Demo ===\n")
+
+ manager = GardenManager.create_garden_network({"Alice": Garden()})
+
+ manager.add_plant("Alice", PrizeFlower("sunflower", 80, "yellow", 12))
+ manager.add_plant("Alice", FloweringPlant("violet", 8, "blue"))
+ manager.add_plant("Alice", Plant("oak tree", 410))
+ manager.add_plant("Bob", PrizeFlower("rose", 40, "red", 18))
+
+ manager.grow_garden("Alice")
+ manager.print_report("Alice")
+ manager.print_report("Bob")
+
+ print("=== Garden Network Stats ===")
+ manager.print_stats()