Skip to content
Snippets Groups Projects
plant.py 2.85 KiB
import random
from abc import ABC, abstractmethod
from copy import copy

from exceptions import DeadPlantError, NoMoreFruitsError
from fruit import Fruit
from root import Root


class Plant(ABC):
    def __init__(self, species: str, growth_factor: float):
        self.species = species
        self.growth_factor = growth_factor
        self._size = 1
        self.dead = False

    def __repr__(self):
        return f"{self.species}"

    def __str__(self):
        return f"{self.species} of size {self.size:.1f}"

    @property
    def growth_factor(self):
        return self._growth_factor

    @growth_factor.setter
    def growth_factor(self, growth_factor: float):
        if growth_factor <= 1:
            raise ValueError(f"Invalid growth_factor: {growth_factor} (>1 required)")
        self._growth_factor = growth_factor

    @property
    def size(self):
        return self._size

    def grow(self) -> None:
        if self.dead:
            raise DeadPlantError("{self} is dead, it can't grow")
        self._size *= self.growth_factor

    @abstractmethod
    def harvest(self) -> list:
        raise NotImplementedError


class FruitBearingPlant(Plant):
    def __init__(self, species: str, growth_factor: float, fruit_template: Fruit):
        super().__init__(species, growth_factor)
        self.fruit_template = fruit_template
        self._fruits = []

    def __str__(self):
        return f"{self.species} of size {self.size:.1f} with {len(self.fruits)} fruits"

    @property
    def fruits(self):
        return self._fruits

    @fruits.deleter
    def fruits(self):
        self._fruits.clear()

    def grow(self) -> None:
        super().grow()
        if random.randrange(100) < self.size:
            self.fruits.append(copy(self.fruit_template))

    def pick(self) -> Fruit:
        if not self.fruits:
            raise NoMoreFruitsError(f"{self} is empty, you can't pick any more fruits :(")
        return self.fruits.pop()

    def harvest(self) -> list:
        harvested = []
        while True:
            try:
                harvested.append(self.pick())
            except NoMoreFruitsError:
                return harvested


class RootVegetable(Plant):
    def __init__(self,
                 species: str,
                 growth_factor: float,
                 calories_per_root_length: int,
                 plant_size_to_root_length_factor: float):
        super().__init__(species, growth_factor)
        self._root = Root(self.species, calories_per_root_length)
        self._plant_size_to_root_length_factor = plant_size_to_root_length_factor

    def grow(self):
        super().grow()
        self._root.length = self._size * self._plant_size_to_root_length_factor

    def harvest(self) -> list:
        self.dead = True
        if self._root is None:
            return []
        harvested = [self._root]
        self._root = None
        return harvested