1class Material:
2 def __init__(self, mass, density, is_alloy = False):
3 self.density = density
4 self.mass = mass
5 self.used = False
6 self.alloy = is_alloy
7
8 @property
9 def volume(self):
10 return self.mass / self.density
11
12 def __str__(self):
13 return self.__class__.__name__
14
15
16class Concrete(Material):
17 DENSITY = 2500
18 def __init__(self, arg):
19 super().__init__(arg, self.DENSITY)
20
21
22class Brick(Material):
23 DENSITY = 2000
24 def __init__(self, arg):
25 super().__init__(arg, self.DENSITY)
26
27
28class Stone(Material):
29 DENSITY = 1600
30 def __init__(self, arg):
31 super().__init__(arg, self.DENSITY)
32
33
34class Wood(Material):
35 DENSITY = 600
36 def __init__(self, arg):
37 super().__init__(arg, self.DENSITY)
38
39
40class Steel(Material):
41 DENSITY = 7700
42 def __init__(self, arg):
43 super().__init__(arg, self.DENSITY)
44
45
46class Factory:
47 factories = []
48 dynamic_classes = {}
49
50 def __init__(self):
51 self.used_materials = []
52 self.existing_alloys = set()
53 self.__class__.factories.append(self)
54
55 def get_subclass(self, name):
56 subclasses = {cls.__name__: cls for cls in Material.__subclasses__()}
57 if name in subclasses:
58 return subclasses[name]
59 return None
60
61 def call_with_named_args(self, kwargs):
62 result = []
63 for key, value in kwargs.items():
64 if self.get_subclass(key):
65 result.append(self.get_subclass(key)(value))
66 else:
67 raise ValueError("invalid materials")
68 self.materials = tuple(result)
69
70 def call_with_pos_args(self, args):
71 used_materials = []
72 materials_list = []
73 new_mass = new_density = 0
74 names = []
75 for material in args:
76 if self.get_subclass(str(material)) is None:
77 raise TypeError("invalid material")
78 elif material.used:
79 raise AssertionError("material is already used")
80 elif material.alloy == False:
81 names.append(str(material))
82 new_density += material.density
83 materials_list.append(material)
84 else:
85 for m in material.materials:
86 names.append(str(m))
87 new_density += m.density
88 materials_list.append(m)
89 used_materials.append(material)
90 material.used = True
91 new_mass += material.mass
92 new_density = new_density / len(names)
93 new_name = "_".join(sorted(names))
94 if new_name in Factory.dynamic_classes:
95 new_class = Factory.dynamic_classes[new_name]
96 else:
97 def init(self, mass):
98 Material.__init__(self, mass, new_density, True)
99 self.materials = materials_list
100
101 new_class = type(new_name, (Material,), {"__init__": init})
102 Factory.dynamic_classes[new_name] = new_class
103 new_instance = new_class(new_mass)
104 self.used_materials.extend(used_materials)
105 self.existing_alloys.add(new_instance)
106 return new_instance
107
108 def __call__(self, *args, **kwargs):
109 if not args and kwargs:
110 self.call_with_named_args(kwargs)
111 return self.materials
112 elif args and not kwargs:
113 new_class_instance = self.call_with_pos_args(args)
114 return new_class_instance
115 raise ValueError("invalid arguments")
116
117 def sum_of_volumes(self):
118 sum_of_volumes = 0
119 for material in self.used_materials:
120 if not material.used:
121 sum_of_volumes += material.volume
122 for material in self.existing_alloys:
123 if not material.used:
124 sum_of_volumes += material.volume
125 return sum_of_volumes
126
127 def can_build(self, needed_volume):
128 sum_of_volumes = self.sum_of_volumes()
129 return needed_volume <= sum_of_volumes
130
131 @classmethod
132 def can_build_together(cls, needed_volume):
133 sum_of_volumes = 0
134 for factory in cls.factories:
135 sum_of_volumes += factory.sum_of_volumes()
136 return needed_volume <= sum_of_volumes
.F...F.F..
======================================================================
FAIL: test_can_build (test.TestFactory.test_can_build)
Test can_build methods.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 174, in test_can_build
self.assertTrue(self.factory1.can_build(2.0))
AssertionError: False is not true
======================================================================
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 113, in __call__
new_class_instance = self.call_with_pos_args(args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 79, in call_with_pos_args
raise AssertionError("material is already used")
AssertionError: material is already used
======================================================================
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 'solution.Concrete'> is not <class 'solution.Concrete'>
----------------------------------------------------------------------
Ran 10 tests in 0.011s
FAILED (failures=3)
26.11.2024 13:19
26.11.2024 13:20
26.11.2024 13:20
26.11.2024 13:21
26.11.2024 13:22
26.11.2024 13:24
26.11.2024 13:26
26.11.2024 13:23