Домашни > Another brick in the wall > Решения > Решението на Нели Илиева

Резултати
6 точки от тестове
0 точки от учител

6 точки общо

6 успешни теста
4 неуспешни теста
Код
Скрий всички коментари

  1from abc import ABC, abstractmethod
  2
  3
  4class Material(ABC):
  5    """Abstract class for materials."""
  6    def __init__(self, mass):
  7        self.mass = mass
  8        self.used = False
  9
 10    @property
 11    @abstractmethod
 12    def density(self):
 13        """Define density."""
 14        pass
 15
 16    @property
 17    def volume(self):
 18        """Calculate volume."""
 19        return self.mass / self.density
 20
 21
 22class Concrete(Material):
 23    DENSITY = 2500
 24
 25    @property
 26    def density(self):
 27        return self.DENSITY
 28
 29
 30class Brick(Material):
 31    DENSITY = 2000
 32
 33    @property
 34    def density(self):
 35        return self.DENSITY
 36
 37
 38class Stone(Material):
 39    DENSITY = 1600
 40
 41    @property
 42    def density(self):
 43        return self.DENSITY
 44
 45
 46class Wood(Material):
 47    DENSITY = 600
 48
 49    @property
 50    def density(self):
 51        return self.DENSITY
 52
 53
 54class Steel(Material):
 55    DENSITY = 7700
 56
 57    @property
 58    def density(self):
 59        return self.DENSITY
 60
 61
 62class Factory:
 63    instances = []
 64    alloys = {}
 65
 66    def __init__(self):
 67        self.created_materials = set()
 68        Factory.instances.append(self)
 69
 70    def __call__(self, *args, **kwargs):
 71        """Handles creation of materials or alloys."""
 72        if not args and not kwargs:
 73            raise ValueError("Factory must be called with arguments.")
 74
 75        if args and kwargs:
 76            raise ValueError("Cannot mix args and kwargs.")
 77
 78        if kwargs:
 79            return self._create_materials(**kwargs)
 80
 81        if args:
 82            return self._create_alloy(*args)
 83
 84    def _create_materials(self, **kwargs):
 85        """Create materials based on provided keyword arguments."""
 86        material_classes = Material.__subclasses__()
 87        result = []
 88
 89        for name, mass in kwargs.items():
 90            matching_classes = [cls for cls in material_classes if cls.__name__ == name]
 91            if not matching_classes:
 92                raise ValueError(f"Invalid material: {name}")
 93
 94            material_class = matching_classes[0]
 95            material_instance = material_class(mass)
 96            self.created_materials.add(material_instance)
 97            result.append(material_instance)
 98
 99        return tuple(result)
100
101    def _create_alloy(self, *args):
102        """Create an alloy by combining existing materials."""
103        for material in args:
104            if not isinstance(material, Material):
105                raise ValueError(f"Invalid object: {material}.")
106            if material.used:
107                raise ValueError(f"Material {material.__class__.__name__} has already been used.")
108
109        material_names = sorted(set(arg.__class__.__name__ for arg in args))
110        alloy_class_name = "_".join(material_names)
111
112        if alloy_class_name not in Factory.alloys:
113            densities = [material.density for material in args]
114            average_density = sum(densities) / len(densities)
115
116            Alloy = type(alloy_class_name, (Material,), {
117                'DENSITY': average_density,
118                '__init__': lambda self, mass: super(Alloy, self).__init__(mass),
119                'density': property(lambda self: self.DENSITY),
120            })
121
122            Factory.alloys[alloy_class_name] = Alloy
123
124        for material in args:
125            material.used = True
126
127        total_mass = sum(material.mass for material in args)
128        alloy_class = Factory.alloys[alloy_class_name]
129        alloy_instance = alloy_class(total_mass)
130        self.created_materials.add(alloy_instance)
131        return alloy_instance
132
133    def can_build(self, wall_volume):
134        """Check if this factory can build a wall with the specified volume."""
135        total_volume = sum(material.volume for material in self.created_materials if not material.used)
136        return total_volume >= wall_volume
137
138    @staticmethod
139    def can_build_together(wall_volume):
140        """Check if all factories together can build a wall with the specified volume."""
141        total_volume = sum(
142            material.volume
143            for factory in Factory.instances
144            for material in factory.created_materials
145            if not material.used
146        )
147        return total_volume >= wall_volume

..E..EFF..
======================================================================
ERROR: test_materials_between_factories (test.TestFactory.test_materials_between_factories)
Test materials sharing.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 162, in test_materials_between_factories
self.factory2(wood)
File "/tmp/solution.py", line 82, in __call__
return self._create_alloy(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 107, in _create_alloy
raise ValueError(f"Material {material.__class__.__name__} has already been used.")
ValueError: Material Wood has already been used.

======================================================================
ERROR: test_positional_arguments_multiple_argument_from_initial_set (test.TestFactory.test_positional_arguments_multiple_argument_from_initial_set)
Test calling a factory using multiple positional arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 102, in test_positional_arguments_multiple_argument_from_initial_set
self.factory1(wood, steel)
File "/tmp/solution.py", line 82, in __call__
return self._create_alloy(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 107, in _create_alloy
raise ValueError(f"Material {material.__class__.__name__} has already been used.")
ValueError: Material Wood has already been used.

======================================================================
FAIL: test_positional_arguments_multiple_argument_with_dynamics (test.TestFactory.test_positional_arguments_multiple_argument_with_dynamics)
Test calling a factory using multiple positional arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 128, in test_positional_arguments_multiple_argument_with_dynamics
self.assertEqual(mega_material.__class__.__name__,
AssertionError: 'Brick_Concrete_Stone_Steel_Wood' != 'Brick_Concrete_Steel_Stone_Wood'
- Brick_Concrete_Stone_Steel_Wood
? ------
+ Brick_Concrete_Steel_Stone_Wood
? ++++++

======================================================================
FAIL: test_positional_arguments_single_argument (test.TestFactory.test_positional_arguments_single_argument)
Test calling a factory using a sigle positional argument.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 80, in test_positional_arguments_single_argument
self.assertIs(type(concrete2), solution.Concrete)
AssertionError: <class 'abc.Concrete'> is not <class 'solution.Concrete'>

----------------------------------------------------------------------
Ran 10 tests in 0.012s

FAILED (failures=2, errors=2)

Дискусия
История
Това решение има само една версия.