1class Material:
2 _densities = {"Concrete": 2500, "Brick": 2000, "Stone": 1600, "Wood": 600, "Steel": 7700}
3
4 def __init__(self, mass):
5 self.mass = mass
6 self.used = False
7
8 def use(self):
9 self.used = True
10
11 @property
12 def density(self):
13 return self.__class__.density
14
15 @property
16 def volume(self):
17 return float(self.mass / self.density)
18
19class Concrete(Material):
20 density = Material._densities["Concrete"]
21
22class Brick(Material):
23 density = Material._densities["Brick"]
24
25class Stone(Material):
26 density = Material._densities["Stone"]
27
28class Wood(Material):
29 density = Material._densities["Wood"]
30
31class Steel(Material):
32 density = Material._densities["Steel"]
33
34class Alloy(Material):
35 density = None
36 _base_materials = []
37
38 @classmethod
39 def calculate_density(cls):
40 if not cls._base_materials:
41 return None
42 return sum(Material._densities[material] for material in cls._base_materials) / len(cls._base_materials)
43
44class Factory:
45 _material_classes = {"Concrete": Concrete, "Brick": Brick, "Stone": Stone, "Wood": Wood, "Steel": Steel}
46 all_factories_available_materials = []
47
48 def __init__(self):
49 self.__available_materials = []
50
51 def __call__(self, *args, **kwargs):
52 if (args and kwargs) or (not args and not kwargs):
53 raise ValueError("Invalid arguments")
54 if kwargs:
55 return self.__create_materials(**kwargs)
56 elif args:
57 return self.__create_alloy(*args)
58
59 def __create_materials(self, **kwargs):
60 current_materials = []
61 for name, mass in kwargs.items():
62 if name in self._material_classes:
63 material_type = self._material_classes[name]
64 else:
65 raise ValueError("Invalid argument name")
66 material = material_type(mass)
67 current_materials.append(material)
68 self.__available_materials.append(material)
69 self.all_factories_available_materials.append(material)
70 return tuple(current_materials)
71
72 def __create_alloy(self, *args):
73 for material in args:
74 if material.used:
75 raise AssertionError("Material already used")
76 else:
77 material.use()
78
79 alloy_name = "_".join(sorted(material for name in args for material in name.__class__.__name__.split("_")))
80 sum_mass = sum(material.mass for material in args)
81 if alloy_name in self._material_classes:
82 alloy_class = self._material_classes[alloy_name]
83 else:
84 base_materials = [material for material in alloy_name.split("_")]
85 avg_density = sum(Material._densities[material] for material in base_materials) / len(base_materials)
86 alloy_class = type(alloy_name, (Alloy,), {"_base_materials": base_materials, "density": avg_density})
87 self._material_classes[alloy_name] = alloy_class
88 instance = alloy_class(sum_mass)
89 self.__available_materials.append(instance)
90 self.all_factories_available_materials.append(instance)
91 return instance
92
93 def can_build(self, volume):
94 avaible_volume = sum(material.volume for material in self.__available_materials if not material.used)
95 return avaible_volume >= volume
96
97 @classmethod
98 def can_build_together(cls, volume):
99 avaible_volume = sum(material.volume for material in cls.all_factories_available_materials if not material.used)
100 return avaible_volume >= volume
.....F....
======================================================================
FAIL: 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 116, in test_positional_arguments_multiple_argument_from_initial_set
concrete_wood = self.factory1(concrete, wood)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 57, in __call__
return self.__create_alloy(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 75, in __create_alloy
raise AssertionError("Material already used")
AssertionError: Material already used
----------------------------------------------------------------------
Ran 10 tests in 0.013s
FAILED (failures=1)
f | 1 | class Material: | f | 1 | class Material: |
2 | _densities = {"Concrete": 2500, "Brick": 2000, "Stone": 1600, "Wood": 600, "Steel": 7700} | 2 | _densities = {"Concrete": 2500, "Brick": 2000, "Stone": 1600, "Wood": 600, "Steel": 7700} | ||
3 | 3 | ||||
4 | def __init__(self, mass): | 4 | def __init__(self, mass): | ||
5 | self.mass = mass | 5 | self.mass = mass | ||
6 | self.used = False | 6 | self.used = False | ||
7 | 7 | ||||
8 | def use(self): | 8 | def use(self): | ||
9 | self.used = True | 9 | self.used = True | ||
10 | 10 | ||||
11 | @property | 11 | @property | ||
12 | def density(self): | 12 | def density(self): | ||
13 | return self.__class__.density | 13 | return self.__class__.density | ||
14 | 14 | ||||
15 | @property | 15 | @property | ||
16 | def volume(self): | 16 | def volume(self): | ||
17 | return float(self.mass / self.density) | 17 | return float(self.mass / self.density) | ||
18 | 18 | ||||
19 | class Concrete(Material): | 19 | class Concrete(Material): | ||
20 | density = Material._densities["Concrete"] | 20 | density = Material._densities["Concrete"] | ||
21 | 21 | ||||
22 | class Brick(Material): | 22 | class Brick(Material): | ||
23 | density = Material._densities["Brick"] | 23 | density = Material._densities["Brick"] | ||
24 | 24 | ||||
25 | class Stone(Material): | 25 | class Stone(Material): | ||
26 | density = Material._densities["Stone"] | 26 | density = Material._densities["Stone"] | ||
27 | 27 | ||||
28 | class Wood(Material): | 28 | class Wood(Material): | ||
29 | density = Material._densities["Wood"] | 29 | density = Material._densities["Wood"] | ||
30 | 30 | ||||
31 | class Steel(Material): | 31 | class Steel(Material): | ||
32 | density = Material._densities["Steel"] | 32 | density = Material._densities["Steel"] | ||
33 | 33 | ||||
34 | class Alloy(Material): | 34 | class Alloy(Material): | ||
35 | density = None | 35 | density = None | ||
36 | _base_materials = [] | 36 | _base_materials = [] | ||
t | 37 | t | |||
38 | def __init__(self, mass, density=None): | ||||
39 | super().__init__(mass) | ||||
40 | self.__class__.density = density if density else self.__class__.calculate_density() | ||||
41 | 37 | ||||
42 | @classmethod | 38 | @classmethod | ||
43 | def calculate_density(cls): | 39 | def calculate_density(cls): | ||
44 | if not cls._base_materials: | 40 | if not cls._base_materials: | ||
45 | return None | 41 | return None | ||
46 | return sum(Material._densities[material] for material in cls._base_materials) / len(cls._base_materials) | 42 | return sum(Material._densities[material] for material in cls._base_materials) / len(cls._base_materials) | ||
47 | 43 | ||||
48 | class Factory: | 44 | class Factory: | ||
49 | _material_classes = {"Concrete": Concrete, "Brick": Brick, "Stone": Stone, "Wood": Wood, "Steel": Steel} | 45 | _material_classes = {"Concrete": Concrete, "Brick": Brick, "Stone": Stone, "Wood": Wood, "Steel": Steel} | ||
50 | all_factories_available_materials = [] | 46 | all_factories_available_materials = [] | ||
51 | 47 | ||||
52 | def __init__(self): | 48 | def __init__(self): | ||
53 | self.__available_materials = [] | 49 | self.__available_materials = [] | ||
54 | 50 | ||||
55 | def __call__(self, *args, **kwargs): | 51 | def __call__(self, *args, **kwargs): | ||
56 | if (args and kwargs) or (not args and not kwargs): | 52 | if (args and kwargs) or (not args and not kwargs): | ||
57 | raise ValueError("Invalid arguments") | 53 | raise ValueError("Invalid arguments") | ||
58 | if kwargs: | 54 | if kwargs: | ||
59 | return self.__create_materials(**kwargs) | 55 | return self.__create_materials(**kwargs) | ||
60 | elif args: | 56 | elif args: | ||
61 | return self.__create_alloy(*args) | 57 | return self.__create_alloy(*args) | ||
62 | 58 | ||||
63 | def __create_materials(self, **kwargs): | 59 | def __create_materials(self, **kwargs): | ||
64 | current_materials = [] | 60 | current_materials = [] | ||
65 | for name, mass in kwargs.items(): | 61 | for name, mass in kwargs.items(): | ||
66 | if name in self._material_classes: | 62 | if name in self._material_classes: | ||
67 | material_type = self._material_classes[name] | 63 | material_type = self._material_classes[name] | ||
68 | else: | 64 | else: | ||
69 | raise ValueError("Invalid argument name") | 65 | raise ValueError("Invalid argument name") | ||
70 | material = material_type(mass) | 66 | material = material_type(mass) | ||
71 | current_materials.append(material) | 67 | current_materials.append(material) | ||
72 | self.__available_materials.append(material) | 68 | self.__available_materials.append(material) | ||
73 | self.all_factories_available_materials.append(material) | 69 | self.all_factories_available_materials.append(material) | ||
74 | return tuple(current_materials) | 70 | return tuple(current_materials) | ||
75 | 71 | ||||
76 | def __create_alloy(self, *args): | 72 | def __create_alloy(self, *args): | ||
77 | for material in args: | 73 | for material in args: | ||
78 | if material.used: | 74 | if material.used: | ||
79 | raise AssertionError("Material already used") | 75 | raise AssertionError("Material already used") | ||
80 | else: | 76 | else: | ||
81 | material.use() | 77 | material.use() | ||
82 | 78 | ||||
83 | alloy_name = "_".join(sorted(material for name in args for material in name.__class__.__name__.split("_"))) | 79 | alloy_name = "_".join(sorted(material for name in args for material in name.__class__.__name__.split("_"))) | ||
84 | sum_mass = sum(material.mass for material in args) | 80 | sum_mass = sum(material.mass for material in args) | ||
85 | if alloy_name in self._material_classes: | 81 | if alloy_name in self._material_classes: | ||
86 | alloy_class = self._material_classes[alloy_name] | 82 | alloy_class = self._material_classes[alloy_name] | ||
87 | else: | 83 | else: | ||
88 | base_materials = [material for material in alloy_name.split("_")] | 84 | base_materials = [material for material in alloy_name.split("_")] | ||
89 | avg_density = sum(Material._densities[material] for material in base_materials) / len(base_materials) | 85 | avg_density = sum(Material._densities[material] for material in base_materials) / len(base_materials) | ||
90 | alloy_class = type(alloy_name, (Alloy,), {"_base_materials": base_materials, "density": avg_density}) | 86 | alloy_class = type(alloy_name, (Alloy,), {"_base_materials": base_materials, "density": avg_density}) | ||
91 | self._material_classes[alloy_name] = alloy_class | 87 | self._material_classes[alloy_name] = alloy_class | ||
92 | instance = alloy_class(sum_mass) | 88 | instance = alloy_class(sum_mass) | ||
93 | self.__available_materials.append(instance) | 89 | self.__available_materials.append(instance) | ||
94 | self.all_factories_available_materials.append(instance) | 90 | self.all_factories_available_materials.append(instance) | ||
95 | return instance | 91 | return instance | ||
96 | 92 | ||||
97 | def can_build(self, volume): | 93 | def can_build(self, volume): | ||
98 | avaible_volume = sum(material.volume for material in self.__available_materials if not material.used) | 94 | avaible_volume = sum(material.volume for material in self.__available_materials if not material.used) | ||
99 | return avaible_volume >= volume | 95 | return avaible_volume >= volume | ||
100 | 96 | ||||
101 | @classmethod | 97 | @classmethod | ||
102 | def can_build_together(cls, volume): | 98 | def can_build_together(cls, volume): | ||
103 | avaible_volume = sum(material.volume for material in cls.all_factories_available_materials if not material.used) | 99 | avaible_volume = sum(material.volume for material in cls.all_factories_available_materials if not material.used) | ||
104 | return avaible_volume >= volume | 100 | return avaible_volume >= volume |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | class Material: | f | 1 | class Material: |
n | 2 | _densities = {"Concrete": 2500, "Brick": 2000, "Stone": 1600, "Wood": 600, "Steel": 7700, "Alloy": None} | n | 2 | _densities = {"Concrete": 2500, "Brick": 2000, "Stone": 1600, "Wood": 600, "Steel": 7700} |
3 | 3 | ||||
n | 4 | def __init__(self, mass, material_type): | n | 4 | def __init__(self, mass): |
5 | self.mass = mass | 5 | self.mass = mass | ||
n | 6 | self.density = self._densities[material_type] | n | ||
7 | self.used = False | 6 | self.used = False | ||
8 | 7 | ||||
9 | def use(self): | 8 | def use(self): | ||
10 | self.used = True | 9 | self.used = True | ||
11 | 10 | ||||
12 | @property | 11 | @property | ||
n | n | 12 | def density(self): | ||
13 | return self.__class__.density | ||||
14 | |||||
15 | @property | ||||
13 | def volume(self): | 16 | def volume(self): | ||
14 | return float(self.mass / self.density) | 17 | return float(self.mass / self.density) | ||
15 | 18 | ||||
16 | class Concrete(Material): | 19 | class Concrete(Material): | ||
n | 17 | def __init__(self, mass): | n | 20 | density = Material._densities["Concrete"] |
18 | super().__init__(mass, "Concrete") | ||||
19 | 21 | ||||
20 | class Brick(Material): | 22 | class Brick(Material): | ||
n | 21 | def __init__(self, mass): | n | 23 | density = Material._densities["Brick"] |
22 | super().__init__(mass, "Brick") | ||||
23 | 24 | ||||
24 | class Stone(Material): | 25 | class Stone(Material): | ||
n | 25 | def __init__(self, mass): | n | 26 | density = Material._densities["Stone"] |
26 | super().__init__(mass, "Stone") | ||||
27 | 27 | ||||
28 | class Wood(Material): | 28 | class Wood(Material): | ||
n | 29 | def __init__(self, mass): | n | 29 | density = Material._densities["Wood"] |
30 | super().__init__(mass, "Wood") | ||||
31 | 30 | ||||
32 | class Steel(Material): | 31 | class Steel(Material): | ||
n | 33 | def __init__(self, mass): | n | 32 | density = Material._densities["Steel"] |
34 | super().__init__(mass, "Steel") | ||||
35 | 33 | ||||
36 | class Alloy(Material): | 34 | class Alloy(Material): | ||
n | n | 35 | density = None | ||
36 | _base_materials = [] | ||||
37 | |||||
37 | def __init__(self, mass, density = None): | 38 | def __init__(self, mass, density=None): | ||
38 | super().__init__(mass, "Alloy") | 39 | super().__init__(mass) | ||
39 | self.density = self.__class__.density if self.__class__.density else density | 40 | self.__class__.density = density if density else self.__class__.calculate_density() | ||
40 | 41 | ||||
41 | @classmethod | 42 | @classmethod | ||
42 | def calculate_density(cls): | 43 | def calculate_density(cls): | ||
43 | if not cls._base_materials: | 44 | if not cls._base_materials: | ||
44 | return None | 45 | return None | ||
45 | return sum(Material._densities[material] for material in cls._base_materials) / len(cls._base_materials) | 46 | return sum(Material._densities[material] for material in cls._base_materials) / len(cls._base_materials) | ||
n | 46 | n | |||
47 | @classmethod | ||||
48 | def add_material(cls, material): | ||||
49 | cls._base_materials.append(material) | ||||
50 | 47 | ||||
51 | class Factory: | 48 | class Factory: | ||
52 | _material_classes = {"Concrete": Concrete, "Brick": Brick, "Stone": Stone, "Wood": Wood, "Steel": Steel} | 49 | _material_classes = {"Concrete": Concrete, "Brick": Brick, "Stone": Stone, "Wood": Wood, "Steel": Steel} | ||
53 | all_factories_available_materials = [] | 50 | all_factories_available_materials = [] | ||
54 | 51 | ||||
55 | def __init__(self): | 52 | def __init__(self): | ||
56 | self.__available_materials = [] | 53 | self.__available_materials = [] | ||
57 | 54 | ||||
58 | def __call__(self, *args, **kwargs): | 55 | def __call__(self, *args, **kwargs): | ||
59 | if (args and kwargs) or (not args and not kwargs): | 56 | if (args and kwargs) or (not args and not kwargs): | ||
60 | raise ValueError("Invalid arguments") | 57 | raise ValueError("Invalid arguments") | ||
61 | if kwargs: | 58 | if kwargs: | ||
62 | return self.__create_materials(**kwargs) | 59 | return self.__create_materials(**kwargs) | ||
63 | elif args: | 60 | elif args: | ||
64 | return self.__create_alloy(*args) | 61 | return self.__create_alloy(*args) | ||
65 | 62 | ||||
66 | def __create_materials(self, **kwargs): | 63 | def __create_materials(self, **kwargs): | ||
67 | current_materials = [] | 64 | current_materials = [] | ||
68 | for name, mass in kwargs.items(): | 65 | for name, mass in kwargs.items(): | ||
69 | if name in self._material_classes: | 66 | if name in self._material_classes: | ||
70 | material_type = self._material_classes[name] | 67 | material_type = self._material_classes[name] | ||
71 | else: | 68 | else: | ||
72 | raise ValueError("Invalid argument name") | 69 | raise ValueError("Invalid argument name") | ||
73 | material = material_type(mass) | 70 | material = material_type(mass) | ||
74 | current_materials.append(material) | 71 | current_materials.append(material) | ||
75 | self.__available_materials.append(material) | 72 | self.__available_materials.append(material) | ||
76 | self.all_factories_available_materials.append(material) | 73 | self.all_factories_available_materials.append(material) | ||
77 | return tuple(current_materials) | 74 | return tuple(current_materials) | ||
78 | 75 | ||||
79 | def __create_alloy(self, *args): | 76 | def __create_alloy(self, *args): | ||
80 | for material in args: | 77 | for material in args: | ||
81 | if material.used: | 78 | if material.used: | ||
82 | raise AssertionError("Material already used") | 79 | raise AssertionError("Material already used") | ||
83 | else: | 80 | else: | ||
84 | material.use() | 81 | material.use() | ||
85 | 82 | ||||
86 | alloy_name = "_".join(sorted(material for name in args for material in name.__class__.__name__.split("_"))) | 83 | alloy_name = "_".join(sorted(material for name in args for material in name.__class__.__name__.split("_"))) | ||
87 | sum_mass = sum(material.mass for material in args) | 84 | sum_mass = sum(material.mass for material in args) | ||
88 | if alloy_name in self._material_classes: | 85 | if alloy_name in self._material_classes: | ||
89 | alloy_class = self._material_classes[alloy_name] | 86 | alloy_class = self._material_classes[alloy_name] | ||
n | 90 | if len(alloy_name.split("_"))==1: | n | ||
91 | instance = alloy_class(sum_mass) | ||||
92 | else: | ||||
93 | instance = alloy_class(sum_mass, alloy_class.density) | ||||
94 | else: | 87 | else: | ||
95 | base_materials = [material for material in alloy_name.split("_")] | 88 | base_materials = [material for material in alloy_name.split("_")] | ||
96 | avg_density = sum(Material._densities[material] for material in base_materials) / len(base_materials) | 89 | avg_density = sum(Material._densities[material] for material in base_materials) / len(base_materials) | ||
n | 97 | alloy_class = type(alloy_name, (Alloy,), {"_base_materials": [], "density": avg_density}) | n | 90 | alloy_class = type(alloy_name, (Alloy,), {"_base_materials": base_materials, "density": avg_density}) |
98 | self._material_classes[alloy_name] = alloy_class | 91 | self._material_classes[alloy_name] = alloy_class | ||
t | 99 | instance = alloy_class(sum_mass, alloy_class.density) | t | 92 | instance = alloy_class(sum_mass) |
100 | self.__available_materials.append(instance) | 93 | self.__available_materials.append(instance) | ||
101 | self.all_factories_available_materials.append(instance) | 94 | self.all_factories_available_materials.append(instance) | ||
102 | return instance | 95 | return instance | ||
103 | 96 | ||||
104 | def can_build(self, volume): | 97 | def can_build(self, volume): | ||
105 | avaible_volume = sum(material.volume for material in self.__available_materials if not material.used) | 98 | avaible_volume = sum(material.volume for material in self.__available_materials if not material.used) | ||
106 | return avaible_volume >= volume | 99 | return avaible_volume >= volume | ||
107 | 100 | ||||
108 | @classmethod | 101 | @classmethod | ||
109 | def can_build_together(cls, volume): | 102 | def can_build_together(cls, volume): | ||
110 | avaible_volume = sum(material.volume for material in cls.all_factories_available_materials if not material.used) | 103 | avaible_volume = sum(material.volume for material in cls.all_factories_available_materials if not material.used) | ||
111 | return avaible_volume >= volume | 104 | return avaible_volume >= volume |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|