f | class MaterialType(type): | f | class MaterialType(type): |
| @property | | @property |
| def name(self): | | def name(self): |
| """Make the class name accessible via "name" for better utility.""" | | """Make the class name accessible via "name" for better utility.""" |
| return self.__name__ # self in this case is the _Material class | | return self.__name__ # self in this case is the _Material class |
| | | |
| | | |
| class _Material(metaclass=MaterialType): | | class _Material(metaclass=MaterialType): |
| """Class that implements all of the materials behaviour.""" | | """Class that implements all of the materials behaviour.""" |
| density = None # Placeholder | | density = None # Placeholder |
| individual_materials = [] # Placeholder | | individual_materials = [] # Placeholder |
| | | |
| def __init__(self, mass): | | def __init__(self, mass): |
| self.mass = mass | | self.mass = mass |
| | | |
| @property | | @property |
| def name(self): | | def name(self): |
| return self.__class__.__name__ | | return self.__class__.__name__ |
| | | |
| @property | | @property |
| def volume(self): | | def volume(self): |
| return self.mass / self.density | | return self.mass / self.density |
| | | |
| @classmethod | | @classmethod |
| def create_composite_material(cls, input_materials): | | def create_composite_material(cls, input_materials): |
| """Create a new material (type) from multiple existing ones.""" | | """Create a new material (type) from multiple existing ones.""" |
| individual_materials = [material | | individual_materials = [material |
| for input_material in input_materials | | for input_material in input_materials |
| for material in input_material.individual_materials] | | for material in input_material.individual_materials] |
| new_material_name = "_".join(sorted(material.__name__ for material in individual_materials)) | | new_material_name = "_".join(sorted(material.__name__ for material in individual_materials)) |
n | new_material_density = sum(material.density for material in individual_materials) / len(individual_materials) | n | new_material_density = sum(material.density |
| | | for material in individual_materials) / len(individual_materials) |
| new_material = cls.create_material(new_material_name, new_material_density) | | new_material = cls.create_material(new_material_name, new_material_density) |
| new_material.individual_materials = individual_materials | | new_material.individual_materials = individual_materials |
| return new_material | | return new_material |
| | | |
| @classmethod | | @classmethod |
| def create_material(cls, name, density): | | def create_material(cls, name, density): |
| """Create a new material (type) based on name and density.""" | | """Create a new material (type) based on name and density.""" |
| new_material = MaterialType(name, (cls,), {"density": density}) | | new_material = MaterialType(name, (cls,), {"density": density}) |
| new_material.individual_materials = [new_material] | | new_material.individual_materials = [new_material] |
| return new_material | | return new_material |
| | | |
| | | |
| STARTING_MATERIALS = {"Brick": 2000, "Concrete": 2500, "Steel": 7700, "Stone": 1600, "Wood": 600} | | STARTING_MATERIALS = {"Brick": 2000, "Concrete": 2500, "Steel": 7700, "Stone": 1600, "Wood": 600} |
| Brick, Concrete, Steel, Stone, Wood = (_Material.create_material(name, density) | | Brick, Concrete, Steel, Stone, Wood = (_Material.create_material(name, density) |
| for name,density in STARTING_MATERIALS.items()) | | for name,density in STARTING_MATERIALS.items()) |
| | | |
| | | |
| class Factory: | | class Factory: |
| """A factory that produces materials and pieces of a given material.""" | | """A factory that produces materials and pieces of a given material.""" |
| existing_materials = {material.name: material for material in (Brick, Concrete, Steel, Stone, Wood)} | | existing_materials = {material.name: material for material in (Brick, Concrete, Steel, Stone, Wood)} |
n | expended_material_pieces = [] | n | expended_material_pieces = set() |
| factories = [] | | factories = [] |
| | | |
| def __init__(self): | | def __init__(self): |
n | self.produced_material_pieces = [] | n | self.produced_material_pieces = set() |
| self.factories.append(self) | | self.factories.append(self) |
| | | |
| def __call__(self, *args, **kwargs): | | def __call__(self, *args, **kwargs): |
| """Make an order to the factory.""" | | """Make an order to the factory.""" |
| if not bool(args) ^ bool(kwargs): | | if not bool(args) ^ bool(kwargs): |
| raise ValueError("Ебем ти и вноса.") | | raise ValueError("Ебем ти и вноса.") |
| if args: | | if args: |
| return self.create_new_material(args) | | return self.create_new_material(args) |
| if kwargs: | | if kwargs: |
| if any(material not in self.existing_materials for material in kwargs): | | if any(material not in self.existing_materials for material in kwargs): |
| raise ValueError("Ебем ти и вноса.") | | raise ValueError("Ебем ти и вноса.") |
| return self._produce_materials(kwargs) | | return self._produce_materials(kwargs) |
| | | |
| def create_new_material(self, input_materials): | | def create_new_material(self, input_materials): |
| """Create a new material (type) and register it, return a piece of that material.""" | | """Create a new material (type) and register it, return a piece of that material.""" |
| if any(material in self.expended_material_pieces for material in input_materials): | | if any(material in self.expended_material_pieces for material in input_materials): |
| raise AssertionError("Ти кого се опитваш да ментиш?") | | raise AssertionError("Ти кого се опитваш да ментиш?") |
n | self.expended_material_pieces.extend(input_materials) # Register the used materials | n | self.expended_material_pieces.update(input_materials) # Register the used materials |
| | | |
| new_material = _Material.create_composite_material(input_materials) | | new_material = _Material.create_composite_material(input_materials) |
| new_material_mass = sum(material.mass for material in input_materials) | | new_material_mass = sum(material.mass for material in input_materials) |
| if new_material.name not in self.existing_materials: | | if new_material.name not in self.existing_materials: |
| self.existing_materials[new_material.name] = new_material # Register the new material | | self.existing_materials[new_material.name] = new_material # Register the new material |
| return self._produce_material(new_material.name, new_material_mass) | | return self._produce_material(new_material.name, new_material_mass) |
| | | |
| def _produce_material(self, name, mass): | | def _produce_material(self, name, mass): |
| """Produce a piece of a material and register it's production.""" | | """Produce a piece of a material and register it's production.""" |
n | self.produced_material_pieces.append(production := self.existing_materials[name](mass)) | n | self.produced_material_pieces.add(production := self.existing_materials[name](mass)) |
| return production | | return production |
| | | |
| def _produce_materials(self, input_materials): | | def _produce_materials(self, input_materials): |
| """Produce pieces of multiple materials.""" | | """Produce pieces of multiple materials.""" |
| return tuple(self._produce_material(name, mass) for name, mass in input_materials.items()) | | return tuple(self._produce_material(name, mass) for name, mass in input_materials.items()) |
| | | |
| def can_build(self, wall_volume): | | def can_build(self, wall_volume): |
| """Determine if the factory has produced enough materials to build a wall.""" | | """Determine if the factory has produced enough materials to build a wall.""" |
t | | t | # A compromise must be made here between getting close to proper line length limits |
| | | # and having to define a single "useless" variable |
| return sum(piece.volume for piece in self.produced_material_pieces if piece not in self.expended_material_pieces) >= wall_volume | | pieces = (piece.volume for piece in self.produced_material_pieces - self.expended_material_pieces) |
| | | return sum(pieces) >= wall_volume |
| | | |
| @classmethod | | @classmethod |
| def can_build_together(cls, wall_volume): | | def can_build_together(cls, wall_volume): |
| """Determine if all factories together have produced enough materials to build a wall.""" | | """Determine if all factories together have produced enough materials to build a wall.""" |
| all_factory_volumes = (piece.volume | | all_factory_volumes = (piece.volume |
| for factory in cls.factories | | for factory in cls.factories |
| for piece in factory.produced_material_pieces | | for piece in factory.produced_material_pieces |
| if piece not in factory.expended_material_pieces) | | if piece not in factory.expended_material_pieces) |
| return sum(all_factory_volumes) >= wall_volume | | return sum(all_factory_volumes) >= wall_volume |