f | class Material: | f | class Material: |
| """Class, that represent material""" | | """Class, that represent material""" |
| density = 0 | | density = 0 |
| | | |
| def __init__(self, mass): | | def __init__(self, mass): |
| """Initialize Material instance""" | | """Initialize Material instance""" |
| self.mass = mass | | self.mass = mass |
| self.used = False | | self.used = False |
| | | |
| @property | | @property |
| def volume(self): | | def volume(self): |
| """Calculate the volume""" | | """Calculate the volume""" |
n | return float(self.mass / self.density) | n | return self.mass / self.density |
| | | |
| def mark_as_used(self): | | def mark_as_used(self): |
| """Mark the material as used""" | | """Mark the material as used""" |
| self.used = True | | self.used = True |
| | | |
| | | |
| class Concrete(Material): | | class Concrete(Material): |
| """Class, that represent Concrete material""" | | """Class, that represent Concrete material""" |
| density = 2500 | | density = 2500 |
| | | |
| | | |
| class Brick(Material): | | class Brick(Material): |
| """Class, that represent Brick material""" | | """Class, that represent Brick material""" |
| density = 2000 | | density = 2000 |
| | | |
| | | |
| class Stone(Material): | | class Stone(Material): |
| """Class, that represent Stone material""" | | """Class, that represent Stone material""" |
| density = 1600 | | density = 1600 |
| | | |
| | | |
| class Wood(Material): | | class Wood(Material): |
| """Class, that represent Wood material""" | | """Class, that represent Wood material""" |
| density = 600 | | density = 600 |
| | | |
| | | |
| class Steel(Material): | | class Steel(Material): |
| """Class, that represent Steel material""" | | """Class, that represent Steel material""" |
| density = 7700 | | density = 7700 |
| | | |
| | | |
| class Factory: | | class Factory: |
| """Represent a factory that create and manage materials""" | | """Represent a factory that create and manage materials""" |
| _shared_classes = { | | _shared_classes = { |
| "Concrete": Concrete, | | "Concrete": Concrete, |
| "Brick": Brick, | | "Brick": Brick, |
| "Stone": Stone, | | "Stone": Stone, |
| "Wood": Wood, | | "Wood": Wood, |
| "Steel": Steel | | "Steel": Steel |
| } | | } |
| _all_materials = [] | | _all_materials = [] |
| | | |
| def __init__(self): | | def __init__(self): |
| """Initialize Factory instance""" | | """Initialize Factory instance""" |
| self.valid_materials = [] | | self.valid_materials = [] |
| | | |
| def call_for_kwargs(self, **kwargs): | | def call_for_kwargs(self, **kwargs): |
| """Create material from kwargs""" | | """Create material from kwargs""" |
| result = [] | | result = [] |
| for name, mass in kwargs.items(): | | for name, mass in kwargs.items(): |
| material = self._get_class_by_name(name)(mass) | | material = self._get_class_by_name(name)(mass) |
| result.append(material) | | result.append(material) |
| self.valid_materials.extend(result) | | self.valid_materials.extend(result) |
n | self.__class__._all_materials.extend(result) | n | self._all_materials.extend(result) |
| return tuple(result) | | return tuple(result) |
| | | |
| @classmethod | | @classmethod |
| def _get_class_by_name(cls, name): | | def _get_class_by_name(cls, name): |
| """Get a material class by its name""" | | """Get a material class by its name""" |
n | for clas in cls._shared_classes.values(): | n | # for clas in cls._shared_classes.values(): |
| if clas.__name__ == name: | | # if clas.__name__ == name: |
| return clas | | # return clas |
| | | # raise ValueError("Not existing material") |
| | | if name in cls._shared_classes: |
| | | return cls._shared_classes[name] |
| raise ValueError("Not existing material") | | raise ValueError("Not existing material") |
| | | |
| def call_for_args(self, *args): | | def call_for_args(self, *args): |
| """Combine material from args""" | | """Combine material from args""" |
| for arg in args: | | for arg in args: |
| if arg.used: | | if arg.used: |
| raise AssertionError("This material has already been used.") | | raise AssertionError("This material has already been used.") |
| arg.mark_as_used() | | arg.mark_as_used() |
| | | |
| material_classes = [] | | material_classes = [] |
| mass = 0 | | mass = 0 |
| for arg in args: | | for arg in args: |
| for class_name in type(arg).__name__.split('_'): | | for class_name in type(arg).__name__.split('_'): |
| material_classes.append(self._get_class_by_name(class_name)) | | material_classes.append(self._get_class_by_name(class_name)) |
| mass += arg.mass | | mass += arg.mass |
| material_classes.sort(key=lambda obj: obj.__name__) | | material_classes.sort(key=lambda obj: obj.__name__) |
| class_name = "_".join([base.__name__ for base in material_classes]) | | class_name = "_".join([base.__name__ for base in material_classes]) |
| try: | | try: |
| target_class = self._get_class_by_name(class_name) | | target_class = self._get_class_by_name(class_name) |
| instance = target_class(mass) | | instance = target_class(mass) |
| self.valid_materials.append(instance) | | self.valid_materials.append(instance) |
n | self.__class__._all_materials.append(instance) | n | self._all_materials.append(instance) |
| return instance | | return instance |
| except ValueError: | | except ValueError: |
| avg_density = sum(mat.density for mat in material_classes) / len(material_classes) | | avg_density = sum(mat.density for mat in material_classes) / len(material_classes) |
| new_class = type(class_name, (Material,), {"density": avg_density}) | | new_class = type(class_name, (Material,), {"density": avg_density}) |
| instance = new_class(mass) | | instance = new_class(mass) |
| self.valid_materials.append(instance) | | self.valid_materials.append(instance) |
t | self.__class__._all_materials.append(instance) | t | self._all_materials.append(instance) |
| self._shared_classes[class_name] = new_class | | self._shared_classes[class_name] = new_class |
| return instance | | return instance |
| | | |
| def __call__(self, *args, **kwargs): | | def __call__(self, *args, **kwargs): |
| """Create materials""" | | """Create materials""" |
| if (args and kwargs) or (not args and not kwargs): | | if (args and kwargs) or (not args and not kwargs): |
| raise ValueError("Wrong arguments") | | raise ValueError("Wrong arguments") |
| if args: | | if args: |
| return self.call_for_args(*args) | | return self.call_for_args(*args) |
| if kwargs: | | if kwargs: |
| return self.call_for_kwargs(**kwargs) | | return self.call_for_kwargs(**kwargs) |
| | | |
| def can_build(self, volume_required): | | def can_build(self, volume_required): |
| """Check if the unused materials in this factory can satisfy a required volume""" | | """Check if the unused materials in this factory can satisfy a required volume""" |
| total_volume = sum(material.volume for material in self.valid_materials if not material.used) | | total_volume = sum(material.volume for material in self.valid_materials if not material.used) |
| return total_volume >= volume_required | | return total_volume >= volume_required |
| | | |
| @classmethod | | @classmethod |
| def can_build_together(cls, volume_required): | | def can_build_together(cls, volume_required): |
| """Check if the unused materials across all factories can satisfy a required volume""" | | """Check if the unused materials across all factories can satisfy a required volume""" |
| total_volume = sum(material.volume for material in cls._all_materials if not material.used) | | total_volume = sum(material.volume for material in cls._all_materials if not material.used) |
| return total_volume >= volume_required | | return total_volume >= volume_required |