f | class Material: | f | class Material: |
n | | n | |
| | | density = -1 |
| | | |
| def __init__(self, weight): | | def __init__(self, weight): |
| self.weight = weight | | self.weight = weight |
| self.used = False | | self.used = False |
n | | n | |
| density = -1 | | |
| | | |
| @property | | @property |
| def volume(self): | | def volume(self): |
| return self.weight / self.density | | return self.weight / self.density |
| | | |
| | | |
| class Concrete(Material): | | class Concrete(Material): |
| | | |
| density = 2500 | | density = 2500 |
| | | |
| | | |
| class Brick(Material): | | class Brick(Material): |
| | | |
| density = 2000 | | density = 2000 |
| | | |
| | | |
| class Stone(Material): | | class Stone(Material): |
| | | |
| density = 1600 | | density = 1600 |
| | | |
| | | |
| class Wood(Material): | | class Wood(Material): |
| | | |
| density = 600 | | density = 600 |
| | | |
| | | |
| class Steel(Material): | | class Steel(Material): |
| | | |
| density = 7700 | | density = 7700 |
| | | |
| | | |
| existing_materials = { | | existing_materials = { |
| "Concrete" : Concrete, "Brick" : Brick, | | "Concrete" : Concrete, "Brick" : Brick, |
| "Stone" : Stone, "Wood" : Wood, "Steel" : Steel | | "Stone" : Stone, "Wood" : Wood, "Steel" : Steel |
| } | | } |
| | | |
| | | |
| class Factory: | | class Factory: |
| | | |
n | all_factories = [] | n | _all_factories = [] |
| | | |
| def __init__(self): | | def __init__(self): |
| self.materials_made = [] | | self.materials_made = [] |
n | Factory.all_factories.append(self) | n | Factory._all_factories.append(self) |
| | | |
| def _create_alloy(self, *args): | | def _create_alloy(self, *args): |
| unique_material_names = [] | | unique_material_names = [] |
| for material in args: | | for material in args: |
| unique_material_names.extend(material.__class__.__name__.split("_")) | | unique_material_names.extend(material.__class__.__name__.split("_")) |
| alloy_name = "_".join(sorted(unique_material_names)) | | alloy_name = "_".join(sorted(unique_material_names)) |
| try: | | try: |
n | existing_materials[alloy_name] | n | for material in args: |
| | | material.used = True |
| | | return existing_materials[alloy_name](sum(material.weight for material in args)) |
| except KeyError: | | except KeyError: |
n | | n | density = sum(existing_materials[material_name].density |
| | | for material_name in unique_material_names) / (alloy_name.count("_") + 1) |
| existing_materials[alloy_name] = type(alloy_name, | | existing_materials[alloy_name] = type(alloy_name, (Material, ), {'density': density}) |
| (Material, ), | | |
| { | | |
| 'density': sum( | | |
| existing_materials[material_name].density | | |
| for material_name in unique_material_names | | |
| ) | | |
| / (alloy_name.count("_") + 1) | | |
| } | | |
| ) | | |
| finally: | | |
| for material in args: | | |
| material.used = True | | |
| return existing_materials[alloy_name](sum(material.weight for material in args)) | | return existing_materials[alloy_name](sum(material.weight for material in args)) |
| | | |
| def __call__(self, *args, **kwargs): | | def __call__(self, *args, **kwargs): |
| if not args and not kwargs: | | if not args and not kwargs: |
| raise ValueError("Cannot call Factory without arguments.") | | raise ValueError("Cannot call Factory without arguments.") |
| if args and kwargs: | | if args and kwargs: |
| raise ValueError("Cannot call Factory with both positional and keyword arguments.") | | raise ValueError("Cannot call Factory with both positional and keyword arguments.") |
| if kwargs: | | if kwargs: |
| try: | | try: |
| materials = [] | | materials = [] |
| for material, weight in kwargs.items(): | | for material, weight in kwargs.items(): |
| materials.append(existing_materials[material](weight)) | | materials.append(existing_materials[material](weight)) |
| except KeyError: | | except KeyError: |
| raise ValueError("Incorrect input for materials.") | | raise ValueError("Incorrect input for materials.") |
| self.materials_made.extend(materials) | | self.materials_made.extend(materials) |
| return tuple(materials) | | return tuple(materials) |
| else: | | else: |
| if any(material.used for material in args): | | if any(material.used for material in args): |
| raise AssertionError("Materials already used.") | | raise AssertionError("Materials already used.") |
| else: | | else: |
| new_alloy = self._create_alloy(*args) | | new_alloy = self._create_alloy(*args) |
| self.materials_made.append(new_alloy) | | self.materials_made.append(new_alloy) |
| return new_alloy | | return new_alloy |
| | | |
| def can_build(self, target_volume): | | def can_build(self, target_volume): |
| return sum(material.volume for material in self.materials_made if not material.used) >= target_volume | | return sum(material.volume for material in self.materials_made if not material.used) >= target_volume |
| | | |
| @classmethod | | @classmethod |
| def can_build_together(cls, target_volume): | | def can_build_together(cls, target_volume): |
| total_volume = 0 | | total_volume = 0 |
t | for factory in cls.all_factories: | t | for factory in cls._all_factories: |
| total_volume += sum(material.volume for material in factory.materials_made if not material.used) | | total_volume += sum(material.volume for material in factory.materials_made if not material.used) |
| return total_volume >= target_volume | | return total_volume >= target_volume |