From add19108024a48c89dc6485cd754c1ed480f77b5 Mon Sep 17 00:00:00 2001 From: Axy Date: Wed, 7 Jan 2026 16:28:47 +0100 Subject: [PATCH] Simple things done complexly i love this subject --- ex2/ft_plant_growth.py | 4 +- ex3/ft_plant_factory.py | 9 +- ex4/ft_garden_security.py | 8 +- ex5/ft_plant_types.py | 18 ++-- ex6/ft_garden_analytics.py | 213 +++++++++++++++++++++++++++++++++++++ 5 files changed, 231 insertions(+), 21 deletions(-) create mode 100644 ex6/ft_garden_analytics.py diff --git a/ex2/ft_plant_growth.py b/ex2/ft_plant_growth.py index 5769595..62e44fc 100644 --- a/ex2/ft_plant_growth.py +++ b/ex2/ft_plant_growth.py @@ -15,10 +15,10 @@ class Plant: + f"{self.age_days} days old" ) - def grow(self, by_cm: int): + def grow(self, by_cm: int) -> None: self.height_cm += by_cm - def age(self, by_days: int): + def age(self, by_days: int) -> None: # We assume a growth rate of 1cm per day self.grow(by_days) self.age_days += by_days diff --git a/ex3/ft_plant_factory.py b/ex3/ft_plant_factory.py index f64a217..fa16289 100644 --- a/ex3/ft_plant_factory.py +++ b/ex3/ft_plant_factory.py @@ -15,20 +15,17 @@ class Plant: + f"{self.age_days} days old" ) - def grow(self, by_cm: int): + def grow(self, by_cm: int) -> None: self.height_cm += by_cm - def age(self, by_days: int): + def age(self, by_days: int) -> None: # We assume a growth rate of 1cm per day self.grow(by_days) self.age_days += by_days class PlantFactory: - plants: list[Plant] - - def __init__(self): - self.plants = [] + plants: list[Plant] = [] def create(self, name: str, height_cm: int, age_days: int) -> Plant: plant = Plant(name, height_cm, age_days) diff --git a/ex4/ft_garden_security.py b/ex4/ft_garden_security.py index ae69fb5..a908d95 100644 --- a/ex4/ft_garden_security.py +++ b/ex4/ft_garden_security.py @@ -13,15 +13,15 @@ class SecurePlant: 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" @@ -30,7 +30,7 @@ class SecurePlant: 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" diff --git a/ex5/ft_plant_types.py b/ex5/ft_plant_types.py index d94d822..a1448c0 100644 --- a/ex5/ft_plant_types.py +++ b/ex5/ft_plant_types.py @@ -30,7 +30,7 @@ class Plant: ", ", self.get_attributes() ) - def action(self): + def action(self) -> None: pass @@ -47,10 +47,10 @@ class Flower(Plant): 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() @@ -59,7 +59,7 @@ class Tree(Plant): 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 @@ -71,11 +71,11 @@ class Tree(Plant): 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() @@ -90,7 +90,7 @@ class Vegetable(Plant): 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 @@ -101,10 +101,10 @@ class Vegetable(Plant): 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() diff --git a/ex6/ft_garden_analytics.py b/ex6/ft_garden_analytics.py new file mode 100644 index 0000000..5f704d2 --- /dev/null +++ b/ex6/ft_garden_analytics.py @@ -0,0 +1,213 @@ +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() -- 2.51.0