1_MATERIALS_DENSITIES = {
2 'Concrete': 2500,
3 'Brick': 2000,
4 'Stone': 1600,
5 'Wood': 600,
6 'Steel': 7700,
7}
8
9class Material:
10 """Base class for materials with mass and density."""
11
12 _DENSITY = 1
13
14 def __init__(self, mass):
15 """Initialize the material with a given mass."""
16 self.mass = mass
17 self._is_valid = True
18
19 @property
20 def volume(self):
21 """Calculate the volume of the material."""
22 return self.mass / self._DENSITY
23
24 def validate(self):
25 """Check if the material is still valid for use."""
26 if not self._is_valid:
27 raise AssertionError('Not valid material found.')
28
29 def invalidate(self):
30 """Mark the material as invalid."""
31 self._is_valid = False
32
33 def get_base_materials(self):
34 return [type(self).__name__]
35
36
37class Concrete(Material):
38 """Concrete material with predefined density."""
39 _DENSITY = _MATERIALS_DENSITIES['Concrete']
40
41
42class Brick(Material):
43 """Brick material with predefined density."""
44 _DENSITY = _MATERIALS_DENSITIES['Brick']
45
46
47class Stone(Material):
48 """Stone material with predefined density."""
49 _DENSITY = _MATERIALS_DENSITIES['Stone']
50
51
52class Wood(Material):
53 """Wood material with predefined density."""
54 _DENSITY = _MATERIALS_DENSITIES['Wood']
55
56
57class Steel(Material):
58 """Steel material with predefined density."""
59 _DENSITY = _MATERIALS_DENSITIES['Steel']
60
61
62class Factory:
63 """Create and manage materials and alloys."""
64
65 _MATERIALS_CREATED = {
66 'Concrete': Concrete,
67 'Brick': Brick,
68 'Stone': Stone,
69 'Wood': Wood,
70 'Steel': Steel,
71 }
72
73 all_created_materials = []
74
75 def __init__(self):
76 self.materials_created_by_instance = []
77
78 def __call__(self, *args, **kwargs):
79 """Enable the factory instance to be called."""
80 if args and kwargs:
81 raise ValueError('One type of arguments are allowed.')
82 elif (len(args), len(kwargs)) == (0, 0):
83 raise ValueError('No arguments found.')
84
85 if len(args) > 0:
86 return self.positional_call(*args)
87 return self.keyword_call(**kwargs)
88
89 def positional_call(self, *args):
90 """Handle creation of alloys from positional arguments."""
91
92 for material in args:
93 material.validate()
94 material.invalidate()
95
96 base_materials = []
97 for material in args:
98 base_materials.extend(material.get_base_materials())
99
100 unique_base_materials = sorted(set(base_materials))
101
102 alloy_name = '_'.join(unique_base_materials)
103 alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials)
104 alloy_mass = sum(material.mass for material in args)
105
106 if alloy_name in self._MATERIALS_CREATED:
107 alloy_class = self._MATERIALS_CREATED[alloy_name]
108 else:
109 alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials)
110
111 alloy_instance = alloy_class(alloy_mass)
112 self.materials_created_by_instance.append(alloy_instance)
113 Factory.all_created_materials.append(alloy_instance)
114
115 return alloy_instance
116
117 def create_alloy_class(self, alloy_name, alloy_density, base_materials):
118 """Dynamically create a class for an alloy."""
119
120 alloy_class = type(
121 alloy_name,
122 (Material,),
123 {
124 '_DENSITY': alloy_density,
125 '_base_materials': base_materials,
126 'get_base_materials': lambda self: base_materials,
127 }
128 )
129
130 self._MATERIALS_CREATED[alloy_name] = alloy_class
131 _MATERIALS_DENSITIES[alloy_name] = alloy_density
132 return alloy_class
133
134 def keyword_call(self, **kwargs):
135 """Handle creation of materials from keyword arguments."""
136 material_instances = []
137 for material, mass in kwargs.items():
138 if material not in self._MATERIALS_CREATED:
139 raise ValueError('Not valid material found.')
140
141 material_instance = self._MATERIALS_CREATED[material](mass)
142 material_instances.append(material_instance)
143 self.materials_created_by_instance.append(material_instance)
144 self.all_created_materials.append(material_instance)
145
146 return tuple(material_instances)
147
148 def can_build(self, target):
149 """Check if the factory's materials can build a wall of target volume."""
150 valid_materials = [
151 material for material in self.materials_created_by_instance if material._is_valid
152 ]
153
154 volume_sum = sum(material.volume for material in valid_materials)
155 return volume_sum >= target
156
157 @classmethod
158 def can_build_together(cls, target):
159 """Check if all factories together can build a wall of target volume."""
160 valid_materials = [
161 material for material in cls.all_created_materials if material._is_valid
162 ]
163
164 used_materials = set(
165 material for material in cls.all_created_materials if not material._is_valid
166 )
167
168 final_valid_materials = [material for material in valid_materials if material not in used_materials]
169 total_volume = sum(material.volume for material in final_valid_materials)
170 return total_volume >= target
.....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 86, in __call__
return self.positional_call(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 93, in positional_call
material.validate()
File "/tmp/solution.py", line 27, in validate
raise AssertionError('Not valid material found.')
AssertionError: Not valid material found.
----------------------------------------------------------------------
Ran 10 tests in 0.024s
FAILED (failures=1)
f | 1 | _MATERIALS_DENSITIES = { | f | 1 | _MATERIALS_DENSITIES = { |
2 | 'Concrete': 2500, | 2 | 'Concrete': 2500, | ||
3 | 'Brick': 2000, | 3 | 'Brick': 2000, | ||
4 | 'Stone': 1600, | 4 | 'Stone': 1600, | ||
5 | 'Wood': 600, | 5 | 'Wood': 600, | ||
6 | 'Steel': 7700, | 6 | 'Steel': 7700, | ||
7 | } | 7 | } | ||
8 | 8 | ||||
9 | class Material: | 9 | class Material: | ||
10 | """Base class for materials with mass and density.""" | 10 | """Base class for materials with mass and density.""" | ||
11 | 11 | ||||
12 | _DENSITY = 1 | 12 | _DENSITY = 1 | ||
13 | 13 | ||||
14 | def __init__(self, mass): | 14 | def __init__(self, mass): | ||
15 | """Initialize the material with a given mass.""" | 15 | """Initialize the material with a given mass.""" | ||
16 | self.mass = mass | 16 | self.mass = mass | ||
17 | self._is_valid = True | 17 | self._is_valid = True | ||
18 | 18 | ||||
19 | @property | 19 | @property | ||
20 | def volume(self): | 20 | def volume(self): | ||
21 | """Calculate the volume of the material.""" | 21 | """Calculate the volume of the material.""" | ||
22 | return self.mass / self._DENSITY | 22 | return self.mass / self._DENSITY | ||
23 | 23 | ||||
24 | def validate(self): | 24 | def validate(self): | ||
25 | """Check if the material is still valid for use.""" | 25 | """Check if the material is still valid for use.""" | ||
26 | if not self._is_valid: | 26 | if not self._is_valid: | ||
27 | raise AssertionError('Not valid material found.') | 27 | raise AssertionError('Not valid material found.') | ||
n | n | 28 | |||
29 | def invalidate(self): | ||||
30 | """Mark the material as invalid.""" | ||||
31 | self._is_valid = False | ||||
32 | |||||
33 | def get_base_materials(self): | ||||
34 | return [type(self).__name__] | ||||
28 | 35 | ||||
29 | 36 | ||||
30 | class Concrete(Material): | 37 | class Concrete(Material): | ||
31 | """Concrete material with predefined density.""" | 38 | """Concrete material with predefined density.""" | ||
32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | 39 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | ||
33 | 40 | ||||
34 | 41 | ||||
35 | class Brick(Material): | 42 | class Brick(Material): | ||
36 | """Brick material with predefined density.""" | 43 | """Brick material with predefined density.""" | ||
37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | 44 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | ||
38 | 45 | ||||
39 | 46 | ||||
40 | class Stone(Material): | 47 | class Stone(Material): | ||
41 | """Stone material with predefined density.""" | 48 | """Stone material with predefined density.""" | ||
42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | 49 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | ||
43 | 50 | ||||
44 | 51 | ||||
45 | class Wood(Material): | 52 | class Wood(Material): | ||
46 | """Wood material with predefined density.""" | 53 | """Wood material with predefined density.""" | ||
47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | 54 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | ||
48 | 55 | ||||
49 | 56 | ||||
50 | class Steel(Material): | 57 | class Steel(Material): | ||
51 | """Steel material with predefined density.""" | 58 | """Steel material with predefined density.""" | ||
52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | 59 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | ||
53 | 60 | ||||
54 | 61 | ||||
55 | class Factory: | 62 | class Factory: | ||
56 | """Create and manage materials and alloys.""" | 63 | """Create and manage materials and alloys.""" | ||
57 | 64 | ||||
58 | _MATERIALS_CREATED = { | 65 | _MATERIALS_CREATED = { | ||
59 | 'Concrete': Concrete, | 66 | 'Concrete': Concrete, | ||
60 | 'Brick': Brick, | 67 | 'Brick': Brick, | ||
61 | 'Stone': Stone, | 68 | 'Stone': Stone, | ||
62 | 'Wood': Wood, | 69 | 'Wood': Wood, | ||
63 | 'Steel': Steel, | 70 | 'Steel': Steel, | ||
64 | } | 71 | } | ||
65 | 72 | ||||
66 | all_created_materials = [] | 73 | all_created_materials = [] | ||
67 | 74 | ||||
68 | def __init__(self): | 75 | def __init__(self): | ||
69 | self.materials_created_by_instance = [] | 76 | self.materials_created_by_instance = [] | ||
70 | 77 | ||||
71 | def __call__(self, *args, **kwargs): | 78 | def __call__(self, *args, **kwargs): | ||
72 | """Enable the factory instance to be called.""" | 79 | """Enable the factory instance to be called.""" | ||
n | 73 | if len(args) > 0 and len(kwargs) > 0: | n | 80 | if args and kwargs: |
74 | raise ValueError('One type of arguments are allowed.') | 81 | raise ValueError('One type of arguments are allowed.') | ||
75 | elif (len(args), len(kwargs)) == (0, 0): | 82 | elif (len(args), len(kwargs)) == (0, 0): | ||
76 | raise ValueError('No arguments found.') | 83 | raise ValueError('No arguments found.') | ||
77 | 84 | ||||
78 | if len(args) > 0: | 85 | if len(args) > 0: | ||
79 | return self.positional_call(*args) | 86 | return self.positional_call(*args) | ||
80 | return self.keyword_call(**kwargs) | 87 | return self.keyword_call(**kwargs) | ||
81 | 88 | ||||
82 | def positional_call(self, *args): | 89 | def positional_call(self, *args): | ||
83 | """Handle creation of alloys from positional arguments.""" | 90 | """Handle creation of alloys from positional arguments.""" | ||
n | 84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | n | 91 | |
85 | for material in args: | 92 | for material in args: | ||
86 | material.validate() | 93 | material.validate() | ||
n | 87 | material._is_valid = False | n | 94 | material.invalidate() |
88 | 95 | ||||
89 | base_materials = [] | 96 | base_materials = [] | ||
90 | for material in args: | 97 | for material in args: | ||
n | 91 | if hasattr(material, '_base_materials'): | n | ||
92 | base_materials.extend(material._base_materials) | 98 | base_materials.extend(material.get_base_materials()) | ||
93 | else: | ||||
94 | base_materials.append(type(material).__name__) | ||||
95 | 99 | ||||
96 | unique_base_materials = sorted(set(base_materials)) | 100 | unique_base_materials = sorted(set(base_materials)) | ||
97 | 101 | ||||
98 | alloy_name = '_'.join(unique_base_materials) | 102 | alloy_name = '_'.join(unique_base_materials) | ||
99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | 103 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | ||
100 | alloy_mass = sum(material.mass for material in args) | 104 | alloy_mass = sum(material.mass for material in args) | ||
101 | 105 | ||||
102 | if alloy_name in self._MATERIALS_CREATED: | 106 | if alloy_name in self._MATERIALS_CREATED: | ||
103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | 107 | alloy_class = self._MATERIALS_CREATED[alloy_name] | ||
104 | else: | 108 | else: | ||
105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | 109 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | ||
106 | 110 | ||||
107 | alloy_instance = alloy_class(alloy_mass) | 111 | alloy_instance = alloy_class(alloy_mass) | ||
108 | self.materials_created_by_instance.append(alloy_instance) | 112 | self.materials_created_by_instance.append(alloy_instance) | ||
109 | Factory.all_created_materials.append(alloy_instance) | 113 | Factory.all_created_materials.append(alloy_instance) | ||
110 | 114 | ||||
111 | return alloy_instance | 115 | return alloy_instance | ||
112 | 116 | ||||
113 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | 117 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | ||
114 | """Dynamically create a class for an alloy.""" | 118 | """Dynamically create a class for an alloy.""" | ||
n | n | 119 | |||
115 | alloy_class = type( | 120 | alloy_class = type( | ||
116 | alloy_name, | 121 | alloy_name, | ||
117 | (Material,), | 122 | (Material,), | ||
118 | { | 123 | { | ||
119 | '_DENSITY': alloy_density, | 124 | '_DENSITY': alloy_density, | ||
120 | '_base_materials': base_materials, | 125 | '_base_materials': base_materials, | ||
n | n | 126 | 'get_base_materials': lambda self: base_materials, | ||
121 | } | 127 | } | ||
122 | ) | 128 | ) | ||
123 | 129 | ||||
124 | self._MATERIALS_CREATED[alloy_name] = alloy_class | 130 | self._MATERIALS_CREATED[alloy_name] = alloy_class | ||
125 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | 131 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | ||
126 | return alloy_class | 132 | return alloy_class | ||
127 | 133 | ||||
128 | def keyword_call(self, **kwargs): | 134 | def keyword_call(self, **kwargs): | ||
129 | """Handle creation of materials from keyword arguments.""" | 135 | """Handle creation of materials from keyword arguments.""" | ||
130 | material_instances = [] | 136 | material_instances = [] | ||
131 | for material, mass in kwargs.items(): | 137 | for material, mass in kwargs.items(): | ||
132 | if material not in self._MATERIALS_CREATED: | 138 | if material not in self._MATERIALS_CREATED: | ||
133 | raise ValueError('Not valid material found.') | 139 | raise ValueError('Not valid material found.') | ||
134 | 140 | ||||
135 | material_instance = self._MATERIALS_CREATED[material](mass) | 141 | material_instance = self._MATERIALS_CREATED[material](mass) | ||
136 | material_instances.append(material_instance) | 142 | material_instances.append(material_instance) | ||
137 | self.materials_created_by_instance.append(material_instance) | 143 | self.materials_created_by_instance.append(material_instance) | ||
138 | self.all_created_materials.append(material_instance) | 144 | self.all_created_materials.append(material_instance) | ||
139 | 145 | ||||
140 | return tuple(material_instances) | 146 | return tuple(material_instances) | ||
141 | 147 | ||||
142 | def can_build(self, target): | 148 | def can_build(self, target): | ||
143 | """Check if the factory's materials can build a wall of target volume.""" | 149 | """Check if the factory's materials can build a wall of target volume.""" | ||
144 | valid_materials = [ | 150 | valid_materials = [ | ||
145 | material for material in self.materials_created_by_instance if material._is_valid | 151 | material for material in self.materials_created_by_instance if material._is_valid | ||
146 | ] | 152 | ] | ||
147 | 153 | ||||
148 | volume_sum = sum(material.volume for material in valid_materials) | 154 | volume_sum = sum(material.volume for material in valid_materials) | ||
149 | return volume_sum >= target | 155 | return volume_sum >= target | ||
150 | 156 | ||||
151 | @classmethod | 157 | @classmethod | ||
152 | def can_build_together(cls, target): | 158 | def can_build_together(cls, target): | ||
153 | """Check if all factories together can build a wall of target volume.""" | 159 | """Check if all factories together can build a wall of target volume.""" | ||
154 | valid_materials = [ | 160 | valid_materials = [ | ||
155 | material for material in cls.all_created_materials if material._is_valid | 161 | material for material in cls.all_created_materials if material._is_valid | ||
156 | ] | 162 | ] | ||
157 | 163 | ||||
n | 158 | alloy_materials = set( | n | 164 | used_materials = set( |
159 | material for material in cls.all_created_materials if not material._is_valid | 165 | material for material in cls.all_created_materials if not material._is_valid | ||
160 | ) | 166 | ) | ||
161 | 167 | ||||
t | 162 | final_valid_materials = [material for material in valid_materials if material not in alloy_materials] | t | 168 | final_valid_materials = [material for material in valid_materials if material not in used_materials] |
163 | total_volume = sum(material.volume for material in final_valid_materials) | 169 | total_volume = sum(material.volume for material in final_valid_materials) | ||
164 | return total_volume >= target | 170 | return total_volume >= target |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | _MATERIALS_DENSITIES = { | f | 1 | _MATERIALS_DENSITIES = { |
2 | 'Concrete': 2500, | 2 | 'Concrete': 2500, | ||
3 | 'Brick': 2000, | 3 | 'Brick': 2000, | ||
4 | 'Stone': 1600, | 4 | 'Stone': 1600, | ||
5 | 'Wood': 600, | 5 | 'Wood': 600, | ||
6 | 'Steel': 7700, | 6 | 'Steel': 7700, | ||
7 | } | 7 | } | ||
8 | 8 | ||||
9 | class Material: | 9 | class Material: | ||
10 | """Base class for materials with mass and density.""" | 10 | """Base class for materials with mass and density.""" | ||
11 | 11 | ||||
12 | _DENSITY = 1 | 12 | _DENSITY = 1 | ||
13 | 13 | ||||
14 | def __init__(self, mass): | 14 | def __init__(self, mass): | ||
15 | """Initialize the material with a given mass.""" | 15 | """Initialize the material with a given mass.""" | ||
16 | self.mass = mass | 16 | self.mass = mass | ||
17 | self._is_valid = True | 17 | self._is_valid = True | ||
18 | 18 | ||||
19 | @property | 19 | @property | ||
20 | def volume(self): | 20 | def volume(self): | ||
21 | """Calculate the volume of the material.""" | 21 | """Calculate the volume of the material.""" | ||
22 | return self.mass / self._DENSITY | 22 | return self.mass / self._DENSITY | ||
23 | 23 | ||||
24 | def validate(self): | 24 | def validate(self): | ||
25 | """Check if the material is still valid for use.""" | 25 | """Check if the material is still valid for use.""" | ||
26 | if not self._is_valid: | 26 | if not self._is_valid: | ||
27 | raise AssertionError('Not valid material found.') | 27 | raise AssertionError('Not valid material found.') | ||
28 | 28 | ||||
29 | 29 | ||||
30 | class Concrete(Material): | 30 | class Concrete(Material): | ||
31 | """Concrete material with predefined density.""" | 31 | """Concrete material with predefined density.""" | ||
32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | 32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | ||
33 | 33 | ||||
34 | 34 | ||||
35 | class Brick(Material): | 35 | class Brick(Material): | ||
36 | """Brick material with predefined density.""" | 36 | """Brick material with predefined density.""" | ||
37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | 37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | ||
38 | 38 | ||||
39 | 39 | ||||
40 | class Stone(Material): | 40 | class Stone(Material): | ||
41 | """Stone material with predefined density.""" | 41 | """Stone material with predefined density.""" | ||
42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | 42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | ||
43 | 43 | ||||
44 | 44 | ||||
45 | class Wood(Material): | 45 | class Wood(Material): | ||
46 | """Wood material with predefined density.""" | 46 | """Wood material with predefined density.""" | ||
47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | 47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | ||
48 | 48 | ||||
49 | 49 | ||||
50 | class Steel(Material): | 50 | class Steel(Material): | ||
51 | """Steel material with predefined density.""" | 51 | """Steel material with predefined density.""" | ||
52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | 52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | ||
53 | 53 | ||||
54 | 54 | ||||
55 | class Factory: | 55 | class Factory: | ||
56 | """Create and manage materials and alloys.""" | 56 | """Create and manage materials and alloys.""" | ||
57 | 57 | ||||
58 | _MATERIALS_CREATED = { | 58 | _MATERIALS_CREATED = { | ||
59 | 'Concrete': Concrete, | 59 | 'Concrete': Concrete, | ||
60 | 'Brick': Brick, | 60 | 'Brick': Brick, | ||
61 | 'Stone': Stone, | 61 | 'Stone': Stone, | ||
62 | 'Wood': Wood, | 62 | 'Wood': Wood, | ||
63 | 'Steel': Steel, | 63 | 'Steel': Steel, | ||
64 | } | 64 | } | ||
65 | 65 | ||||
66 | all_created_materials = [] | 66 | all_created_materials = [] | ||
67 | 67 | ||||
68 | def __init__(self): | 68 | def __init__(self): | ||
69 | self.materials_created_by_instance = [] | 69 | self.materials_created_by_instance = [] | ||
70 | 70 | ||||
71 | def __call__(self, *args, **kwargs): | 71 | def __call__(self, *args, **kwargs): | ||
72 | """Enable the factory instance to be called.""" | 72 | """Enable the factory instance to be called.""" | ||
73 | if len(args) > 0 and len(kwargs) > 0: | 73 | if len(args) > 0 and len(kwargs) > 0: | ||
74 | raise ValueError('One type of arguments are allowed.') | 74 | raise ValueError('One type of arguments are allowed.') | ||
75 | elif (len(args), len(kwargs)) == (0, 0): | 75 | elif (len(args), len(kwargs)) == (0, 0): | ||
76 | raise ValueError('No arguments found.') | 76 | raise ValueError('No arguments found.') | ||
77 | 77 | ||||
78 | if len(args) > 0: | 78 | if len(args) > 0: | ||
79 | return self.positional_call(*args) | 79 | return self.positional_call(*args) | ||
80 | return self.keyword_call(**kwargs) | 80 | return self.keyword_call(**kwargs) | ||
81 | 81 | ||||
82 | def positional_call(self, *args): | 82 | def positional_call(self, *args): | ||
83 | """Handle creation of alloys from positional arguments.""" | 83 | """Handle creation of alloys from positional arguments.""" | ||
84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | 84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | ||
85 | for material in args: | 85 | for material in args: | ||
86 | material.validate() | 86 | material.validate() | ||
87 | material._is_valid = False | 87 | material._is_valid = False | ||
88 | 88 | ||||
89 | base_materials = [] | 89 | base_materials = [] | ||
90 | for material in args: | 90 | for material in args: | ||
91 | if hasattr(material, '_base_materials'): | 91 | if hasattr(material, '_base_materials'): | ||
92 | base_materials.extend(material._base_materials) | 92 | base_materials.extend(material._base_materials) | ||
93 | else: | 93 | else: | ||
94 | base_materials.append(type(material).__name__) | 94 | base_materials.append(type(material).__name__) | ||
95 | 95 | ||||
96 | unique_base_materials = sorted(set(base_materials)) | 96 | unique_base_materials = sorted(set(base_materials)) | ||
97 | 97 | ||||
98 | alloy_name = '_'.join(unique_base_materials) | 98 | alloy_name = '_'.join(unique_base_materials) | ||
99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | 99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | ||
100 | alloy_mass = sum(material.mass for material in args) | 100 | alloy_mass = sum(material.mass for material in args) | ||
101 | 101 | ||||
102 | if alloy_name in self._MATERIALS_CREATED: | 102 | if alloy_name in self._MATERIALS_CREATED: | ||
103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | 103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | ||
104 | else: | 104 | else: | ||
105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | 105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | ||
t | 106 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | t | ||
107 | 106 | ||||
108 | alloy_instance = alloy_class(alloy_mass) | 107 | alloy_instance = alloy_class(alloy_mass) | ||
109 | self.materials_created_by_instance.append(alloy_instance) | 108 | self.materials_created_by_instance.append(alloy_instance) | ||
110 | Factory.all_created_materials.append(alloy_instance) | 109 | Factory.all_created_materials.append(alloy_instance) | ||
111 | 110 | ||||
112 | return alloy_instance | 111 | return alloy_instance | ||
113 | 112 | ||||
114 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | 113 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | ||
115 | """Dynamically create a class for an alloy.""" | 114 | """Dynamically create a class for an alloy.""" | ||
116 | alloy_class = type( | 115 | alloy_class = type( | ||
117 | alloy_name, | 116 | alloy_name, | ||
118 | (Material,), | 117 | (Material,), | ||
119 | { | 118 | { | ||
120 | '_DENSITY': alloy_density, | 119 | '_DENSITY': alloy_density, | ||
121 | '_base_materials': base_materials, | 120 | '_base_materials': base_materials, | ||
122 | } | 121 | } | ||
123 | ) | 122 | ) | ||
124 | 123 | ||||
125 | self._MATERIALS_CREATED[alloy_name] = alloy_class | 124 | self._MATERIALS_CREATED[alloy_name] = alloy_class | ||
126 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | 125 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | ||
127 | return alloy_class | 126 | return alloy_class | ||
128 | 127 | ||||
129 | def keyword_call(self, **kwargs): | 128 | def keyword_call(self, **kwargs): | ||
130 | """Handle creation of materials from keyword arguments.""" | 129 | """Handle creation of materials from keyword arguments.""" | ||
131 | material_instances = [] | 130 | material_instances = [] | ||
132 | for material, mass in kwargs.items(): | 131 | for material, mass in kwargs.items(): | ||
133 | if material not in self._MATERIALS_CREATED: | 132 | if material not in self._MATERIALS_CREATED: | ||
134 | raise ValueError('Not valid material found.') | 133 | raise ValueError('Not valid material found.') | ||
135 | 134 | ||||
136 | material_instance = self._MATERIALS_CREATED[material](mass) | 135 | material_instance = self._MATERIALS_CREATED[material](mass) | ||
137 | material_instances.append(material_instance) | 136 | material_instances.append(material_instance) | ||
138 | self.materials_created_by_instance.append(material_instance) | 137 | self.materials_created_by_instance.append(material_instance) | ||
139 | self.all_created_materials.append(material_instance) | 138 | self.all_created_materials.append(material_instance) | ||
140 | 139 | ||||
141 | return tuple(material_instances) | 140 | return tuple(material_instances) | ||
142 | 141 | ||||
143 | def can_build(self, target): | 142 | def can_build(self, target): | ||
144 | """Check if the factory's materials can build a wall of target volume.""" | 143 | """Check if the factory's materials can build a wall of target volume.""" | ||
145 | valid_materials = [ | 144 | valid_materials = [ | ||
146 | material for material in self.materials_created_by_instance if material._is_valid | 145 | material for material in self.materials_created_by_instance if material._is_valid | ||
147 | ] | 146 | ] | ||
148 | 147 | ||||
149 | volume_sum = sum(material.volume for material in valid_materials) | 148 | volume_sum = sum(material.volume for material in valid_materials) | ||
150 | return volume_sum >= target | 149 | return volume_sum >= target | ||
151 | 150 | ||||
152 | @classmethod | 151 | @classmethod | ||
153 | def can_build_together(cls, target): | 152 | def can_build_together(cls, target): | ||
154 | """Check if all factories together can build a wall of target volume.""" | 153 | """Check if all factories together can build a wall of target volume.""" | ||
155 | valid_materials = [ | 154 | valid_materials = [ | ||
156 | material for material in cls.all_created_materials if material._is_valid | 155 | material for material in cls.all_created_materials if material._is_valid | ||
157 | ] | 156 | ] | ||
158 | 157 | ||||
159 | alloy_materials = set( | 158 | alloy_materials = set( | ||
160 | material for material in cls.all_created_materials if not material._is_valid | 159 | material for material in cls.all_created_materials if not material._is_valid | ||
161 | ) | 160 | ) | ||
162 | 161 | ||||
163 | final_valid_materials = [material for material in valid_materials if material not in alloy_materials] | 162 | final_valid_materials = [material for material in valid_materials if material not in alloy_materials] | ||
164 | total_volume = sum(material.volume for material in final_valid_materials) | 163 | total_volume = sum(material.volume for material in final_valid_materials) | ||
165 | return total_volume >= target | 164 | return total_volume >= target |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | _MATERIALS_DENSITIES = { | f | 1 | _MATERIALS_DENSITIES = { |
2 | 'Concrete': 2500, | 2 | 'Concrete': 2500, | ||
3 | 'Brick': 2000, | 3 | 'Brick': 2000, | ||
4 | 'Stone': 1600, | 4 | 'Stone': 1600, | ||
5 | 'Wood': 600, | 5 | 'Wood': 600, | ||
6 | 'Steel': 7700, | 6 | 'Steel': 7700, | ||
7 | } | 7 | } | ||
8 | 8 | ||||
9 | class Material: | 9 | class Material: | ||
10 | """Base class for materials with mass and density.""" | 10 | """Base class for materials with mass and density.""" | ||
11 | 11 | ||||
12 | _DENSITY = 1 | 12 | _DENSITY = 1 | ||
13 | 13 | ||||
14 | def __init__(self, mass): | 14 | def __init__(self, mass): | ||
15 | """Initialize the material with a given mass.""" | 15 | """Initialize the material with a given mass.""" | ||
16 | self.mass = mass | 16 | self.mass = mass | ||
17 | self._is_valid = True | 17 | self._is_valid = True | ||
18 | 18 | ||||
19 | @property | 19 | @property | ||
20 | def volume(self): | 20 | def volume(self): | ||
21 | """Calculate the volume of the material.""" | 21 | """Calculate the volume of the material.""" | ||
22 | return self.mass / self._DENSITY | 22 | return self.mass / self._DENSITY | ||
23 | 23 | ||||
24 | def validate(self): | 24 | def validate(self): | ||
25 | """Check if the material is still valid for use.""" | 25 | """Check if the material is still valid for use.""" | ||
26 | if not self._is_valid: | 26 | if not self._is_valid: | ||
27 | raise AssertionError('Not valid material found.') | 27 | raise AssertionError('Not valid material found.') | ||
28 | 28 | ||||
29 | 29 | ||||
30 | class Concrete(Material): | 30 | class Concrete(Material): | ||
31 | """Concrete material with predefined density.""" | 31 | """Concrete material with predefined density.""" | ||
32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | 32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | ||
33 | 33 | ||||
34 | 34 | ||||
35 | class Brick(Material): | 35 | class Brick(Material): | ||
36 | """Brick material with predefined density.""" | 36 | """Brick material with predefined density.""" | ||
37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | 37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | ||
38 | 38 | ||||
39 | 39 | ||||
40 | class Stone(Material): | 40 | class Stone(Material): | ||
41 | """Stone material with predefined density.""" | 41 | """Stone material with predefined density.""" | ||
42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | 42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | ||
43 | 43 | ||||
44 | 44 | ||||
45 | class Wood(Material): | 45 | class Wood(Material): | ||
46 | """Wood material with predefined density.""" | 46 | """Wood material with predefined density.""" | ||
47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | 47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | ||
48 | 48 | ||||
49 | 49 | ||||
50 | class Steel(Material): | 50 | class Steel(Material): | ||
51 | """Steel material with predefined density.""" | 51 | """Steel material with predefined density.""" | ||
52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | 52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | ||
53 | 53 | ||||
54 | 54 | ||||
55 | class Factory: | 55 | class Factory: | ||
56 | """Create and manage materials and alloys.""" | 56 | """Create and manage materials and alloys.""" | ||
57 | 57 | ||||
58 | _MATERIALS_CREATED = { | 58 | _MATERIALS_CREATED = { | ||
59 | 'Concrete': Concrete, | 59 | 'Concrete': Concrete, | ||
60 | 'Brick': Brick, | 60 | 'Brick': Brick, | ||
61 | 'Stone': Stone, | 61 | 'Stone': Stone, | ||
62 | 'Wood': Wood, | 62 | 'Wood': Wood, | ||
63 | 'Steel': Steel, | 63 | 'Steel': Steel, | ||
64 | } | 64 | } | ||
65 | 65 | ||||
66 | all_created_materials = [] | 66 | all_created_materials = [] | ||
67 | 67 | ||||
68 | def __init__(self): | 68 | def __init__(self): | ||
69 | self.materials_created_by_instance = [] | 69 | self.materials_created_by_instance = [] | ||
70 | 70 | ||||
71 | def __call__(self, *args, **kwargs): | 71 | def __call__(self, *args, **kwargs): | ||
72 | """Enable the factory instance to be called.""" | 72 | """Enable the factory instance to be called.""" | ||
73 | if len(args) > 0 and len(kwargs) > 0: | 73 | if len(args) > 0 and len(kwargs) > 0: | ||
74 | raise ValueError('One type of arguments are allowed.') | 74 | raise ValueError('One type of arguments are allowed.') | ||
75 | elif (len(args), len(kwargs)) == (0, 0): | 75 | elif (len(args), len(kwargs)) == (0, 0): | ||
76 | raise ValueError('No arguments found.') | 76 | raise ValueError('No arguments found.') | ||
77 | 77 | ||||
78 | if len(args) > 0: | 78 | if len(args) > 0: | ||
79 | return self.positional_call(*args) | 79 | return self.positional_call(*args) | ||
80 | return self.keyword_call(**kwargs) | 80 | return self.keyword_call(**kwargs) | ||
81 | 81 | ||||
82 | def positional_call(self, *args): | 82 | def positional_call(self, *args): | ||
83 | """Handle creation of alloys from positional arguments.""" | 83 | """Handle creation of alloys from positional arguments.""" | ||
84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | 84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | ||
85 | for material in args: | 85 | for material in args: | ||
86 | material.validate() | 86 | material.validate() | ||
87 | material._is_valid = False | 87 | material._is_valid = False | ||
88 | 88 | ||||
89 | base_materials = [] | 89 | base_materials = [] | ||
90 | for material in args: | 90 | for material in args: | ||
91 | if hasattr(material, '_base_materials'): | 91 | if hasattr(material, '_base_materials'): | ||
92 | base_materials.extend(material._base_materials) | 92 | base_materials.extend(material._base_materials) | ||
93 | else: | 93 | else: | ||
94 | base_materials.append(type(material).__name__) | 94 | base_materials.append(type(material).__name__) | ||
95 | 95 | ||||
96 | unique_base_materials = sorted(set(base_materials)) | 96 | unique_base_materials = sorted(set(base_materials)) | ||
97 | 97 | ||||
98 | alloy_name = '_'.join(unique_base_materials) | 98 | alloy_name = '_'.join(unique_base_materials) | ||
99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | 99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | ||
100 | alloy_mass = sum(material.mass for material in args) | 100 | alloy_mass = sum(material.mass for material in args) | ||
101 | 101 | ||||
102 | if alloy_name in self._MATERIALS_CREATED: | 102 | if alloy_name in self._MATERIALS_CREATED: | ||
103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | 103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | ||
104 | else: | 104 | else: | ||
105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | 105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | ||
n | 106 | n | 106 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | |
107 | |||||
107 | alloy_instance = alloy_class(alloy_mass) | 108 | alloy_instance = alloy_class(alloy_mass) | ||
108 | self.materials_created_by_instance.append(alloy_instance) | 109 | self.materials_created_by_instance.append(alloy_instance) | ||
109 | Factory.all_created_materials.append(alloy_instance) | 110 | Factory.all_created_materials.append(alloy_instance) | ||
110 | 111 | ||||
111 | return alloy_instance | 112 | return alloy_instance | ||
112 | 113 | ||||
113 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | 114 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | ||
114 | """Dynamically create a class for an alloy.""" | 115 | """Dynamically create a class for an alloy.""" | ||
115 | alloy_class = type( | 116 | alloy_class = type( | ||
116 | alloy_name, | 117 | alloy_name, | ||
117 | (Material,), | 118 | (Material,), | ||
118 | { | 119 | { | ||
119 | '_DENSITY': alloy_density, | 120 | '_DENSITY': alloy_density, | ||
120 | '_base_materials': base_materials, | 121 | '_base_materials': base_materials, | ||
121 | } | 122 | } | ||
122 | ) | 123 | ) | ||
123 | 124 | ||||
124 | self._MATERIALS_CREATED[alloy_name] = alloy_class | 125 | self._MATERIALS_CREATED[alloy_name] = alloy_class | ||
125 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | 126 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | ||
126 | return alloy_class | 127 | return alloy_class | ||
127 | 128 | ||||
128 | def keyword_call(self, **kwargs): | 129 | def keyword_call(self, **kwargs): | ||
129 | """Handle creation of materials from keyword arguments.""" | 130 | """Handle creation of materials from keyword arguments.""" | ||
130 | material_instances = [] | 131 | material_instances = [] | ||
131 | for material, mass in kwargs.items(): | 132 | for material, mass in kwargs.items(): | ||
132 | if material not in self._MATERIALS_CREATED: | 133 | if material not in self._MATERIALS_CREATED: | ||
133 | raise ValueError('Not valid material found.') | 134 | raise ValueError('Not valid material found.') | ||
134 | 135 | ||||
135 | material_instance = self._MATERIALS_CREATED[material](mass) | 136 | material_instance = self._MATERIALS_CREATED[material](mass) | ||
136 | material_instances.append(material_instance) | 137 | material_instances.append(material_instance) | ||
n | n | 138 | self.materials_created_by_instance.append(material_instance) | ||
139 | self.all_created_materials.append(material_instance) | ||||
137 | 140 | ||||
138 | return tuple(material_instances) | 141 | return tuple(material_instances) | ||
139 | 142 | ||||
140 | def can_build(self, target): | 143 | def can_build(self, target): | ||
141 | """Check if the factory's materials can build a wall of target volume.""" | 144 | """Check if the factory's materials can build a wall of target volume.""" | ||
n | 142 | volume_sum = sum( | n | 145 | valid_materials = [ |
143 | material.volume for material in self.materials_created_by_instance | 146 | material for material in self.materials_created_by_instance if material._is_valid | ||
147 | ] | ||||
144 | ) | 148 | |||
149 | volume_sum = sum(material.volume for material in valid_materials) | ||||
145 | return volume_sum >= target | 150 | return volume_sum >= target | ||
146 | 151 | ||||
147 | @classmethod | 152 | @classmethod | ||
148 | def can_build_together(cls, target): | 153 | def can_build_together(cls, target): | ||
149 | """Check if all factories together can build a wall of target volume.""" | 154 | """Check if all factories together can build a wall of target volume.""" | ||
n | 150 | volume_sum = sum( | n | 155 | valid_materials = [ |
151 | material.volume for material in cls.all_created_materials | 156 | material for material in cls.all_created_materials if material._is_valid | ||
157 | ] | ||||
158 | |||||
159 | alloy_materials = set( | ||||
160 | material for material in cls.all_created_materials if not material._is_valid | ||||
152 | ) | 161 | ) | ||
t | t | 162 | |||
163 | final_valid_materials = [material for material in valid_materials if material not in alloy_materials] | ||||
164 | total_volume = sum(material.volume for material in final_valid_materials) | ||||
153 | return volume_sum >= target | 165 | return total_volume >= target |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | _MATERIALS_DENSITIES = { | f | 1 | _MATERIALS_DENSITIES = { |
2 | 'Concrete': 2500, | 2 | 'Concrete': 2500, | ||
3 | 'Brick': 2000, | 3 | 'Brick': 2000, | ||
4 | 'Stone': 1600, | 4 | 'Stone': 1600, | ||
5 | 'Wood': 600, | 5 | 'Wood': 600, | ||
6 | 'Steel': 7700, | 6 | 'Steel': 7700, | ||
7 | } | 7 | } | ||
8 | 8 | ||||
9 | class Material: | 9 | class Material: | ||
10 | """Base class for materials with mass and density.""" | 10 | """Base class for materials with mass and density.""" | ||
11 | 11 | ||||
12 | _DENSITY = 1 | 12 | _DENSITY = 1 | ||
13 | 13 | ||||
14 | def __init__(self, mass): | 14 | def __init__(self, mass): | ||
15 | """Initialize the material with a given mass.""" | 15 | """Initialize the material with a given mass.""" | ||
16 | self.mass = mass | 16 | self.mass = mass | ||
17 | self._is_valid = True | 17 | self._is_valid = True | ||
18 | 18 | ||||
19 | @property | 19 | @property | ||
20 | def volume(self): | 20 | def volume(self): | ||
21 | """Calculate the volume of the material.""" | 21 | """Calculate the volume of the material.""" | ||
22 | return self.mass / self._DENSITY | 22 | return self.mass / self._DENSITY | ||
23 | 23 | ||||
24 | def validate(self): | 24 | def validate(self): | ||
25 | """Check if the material is still valid for use.""" | 25 | """Check if the material is still valid for use.""" | ||
26 | if not self._is_valid: | 26 | if not self._is_valid: | ||
27 | raise AssertionError('Not valid material found.') | 27 | raise AssertionError('Not valid material found.') | ||
28 | 28 | ||||
29 | 29 | ||||
30 | class Concrete(Material): | 30 | class Concrete(Material): | ||
31 | """Concrete material with predefined density.""" | 31 | """Concrete material with predefined density.""" | ||
32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | 32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | ||
33 | 33 | ||||
34 | 34 | ||||
35 | class Brick(Material): | 35 | class Brick(Material): | ||
36 | """Brick material with predefined density.""" | 36 | """Brick material with predefined density.""" | ||
37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | 37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | ||
38 | 38 | ||||
39 | 39 | ||||
40 | class Stone(Material): | 40 | class Stone(Material): | ||
41 | """Stone material with predefined density.""" | 41 | """Stone material with predefined density.""" | ||
42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | 42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | ||
43 | 43 | ||||
44 | 44 | ||||
45 | class Wood(Material): | 45 | class Wood(Material): | ||
46 | """Wood material with predefined density.""" | 46 | """Wood material with predefined density.""" | ||
47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | 47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | ||
48 | 48 | ||||
49 | 49 | ||||
50 | class Steel(Material): | 50 | class Steel(Material): | ||
51 | """Steel material with predefined density.""" | 51 | """Steel material with predefined density.""" | ||
52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | 52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | ||
53 | 53 | ||||
54 | 54 | ||||
55 | class Factory: | 55 | class Factory: | ||
56 | """Create and manage materials and alloys.""" | 56 | """Create and manage materials and alloys.""" | ||
57 | 57 | ||||
58 | _MATERIALS_CREATED = { | 58 | _MATERIALS_CREATED = { | ||
59 | 'Concrete': Concrete, | 59 | 'Concrete': Concrete, | ||
60 | 'Brick': Brick, | 60 | 'Brick': Brick, | ||
61 | 'Stone': Stone, | 61 | 'Stone': Stone, | ||
62 | 'Wood': Wood, | 62 | 'Wood': Wood, | ||
63 | 'Steel': Steel, | 63 | 'Steel': Steel, | ||
64 | } | 64 | } | ||
65 | 65 | ||||
66 | all_created_materials = [] | 66 | all_created_materials = [] | ||
67 | 67 | ||||
68 | def __init__(self): | 68 | def __init__(self): | ||
69 | self.materials_created_by_instance = [] | 69 | self.materials_created_by_instance = [] | ||
70 | 70 | ||||
71 | def __call__(self, *args, **kwargs): | 71 | def __call__(self, *args, **kwargs): | ||
72 | """Enable the factory instance to be called.""" | 72 | """Enable the factory instance to be called.""" | ||
73 | if len(args) > 0 and len(kwargs) > 0: | 73 | if len(args) > 0 and len(kwargs) > 0: | ||
74 | raise ValueError('One type of arguments are allowed.') | 74 | raise ValueError('One type of arguments are allowed.') | ||
75 | elif (len(args), len(kwargs)) == (0, 0): | 75 | elif (len(args), len(kwargs)) == (0, 0): | ||
76 | raise ValueError('No arguments found.') | 76 | raise ValueError('No arguments found.') | ||
77 | 77 | ||||
78 | if len(args) > 0: | 78 | if len(args) > 0: | ||
79 | return self.positional_call(*args) | 79 | return self.positional_call(*args) | ||
80 | return self.keyword_call(**kwargs) | 80 | return self.keyword_call(**kwargs) | ||
81 | 81 | ||||
82 | def positional_call(self, *args): | 82 | def positional_call(self, *args): | ||
83 | """Handle creation of alloys from positional arguments.""" | 83 | """Handle creation of alloys from positional arguments.""" | ||
84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | 84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | ||
85 | for material in args: | 85 | for material in args: | ||
86 | material.validate() | 86 | material.validate() | ||
87 | material._is_valid = False | 87 | material._is_valid = False | ||
88 | 88 | ||||
89 | base_materials = [] | 89 | base_materials = [] | ||
90 | for material in args: | 90 | for material in args: | ||
91 | if hasattr(material, '_base_materials'): | 91 | if hasattr(material, '_base_materials'): | ||
92 | base_materials.extend(material._base_materials) | 92 | base_materials.extend(material._base_materials) | ||
93 | else: | 93 | else: | ||
94 | base_materials.append(type(material).__name__) | 94 | base_materials.append(type(material).__name__) | ||
95 | 95 | ||||
96 | unique_base_materials = sorted(set(base_materials)) | 96 | unique_base_materials = sorted(set(base_materials)) | ||
97 | 97 | ||||
98 | alloy_name = '_'.join(unique_base_materials) | 98 | alloy_name = '_'.join(unique_base_materials) | ||
99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | 99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | ||
100 | alloy_mass = sum(material.mass for material in args) | 100 | alloy_mass = sum(material.mass for material in args) | ||
101 | 101 | ||||
102 | if alloy_name in self._MATERIALS_CREATED: | 102 | if alloy_name in self._MATERIALS_CREATED: | ||
103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | 103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | ||
104 | else: | 104 | else: | ||
105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | 105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | ||
106 | 106 | ||||
107 | alloy_instance = alloy_class(alloy_mass) | 107 | alloy_instance = alloy_class(alloy_mass) | ||
108 | self.materials_created_by_instance.append(alloy_instance) | 108 | self.materials_created_by_instance.append(alloy_instance) | ||
109 | Factory.all_created_materials.append(alloy_instance) | 109 | Factory.all_created_materials.append(alloy_instance) | ||
110 | 110 | ||||
111 | return alloy_instance | 111 | return alloy_instance | ||
112 | 112 | ||||
113 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | 113 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | ||
114 | """Dynamically create a class for an alloy.""" | 114 | """Dynamically create a class for an alloy.""" | ||
115 | alloy_class = type( | 115 | alloy_class = type( | ||
116 | alloy_name, | 116 | alloy_name, | ||
117 | (Material,), | 117 | (Material,), | ||
118 | { | 118 | { | ||
119 | '_DENSITY': alloy_density, | 119 | '_DENSITY': alloy_density, | ||
120 | '_base_materials': base_materials, | 120 | '_base_materials': base_materials, | ||
121 | } | 121 | } | ||
122 | ) | 122 | ) | ||
123 | 123 | ||||
124 | self._MATERIALS_CREATED[alloy_name] = alloy_class | 124 | self._MATERIALS_CREATED[alloy_name] = alloy_class | ||
125 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | 125 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | ||
126 | return alloy_class | 126 | return alloy_class | ||
127 | 127 | ||||
128 | def keyword_call(self, **kwargs): | 128 | def keyword_call(self, **kwargs): | ||
129 | """Handle creation of materials from keyword arguments.""" | 129 | """Handle creation of materials from keyword arguments.""" | ||
130 | material_instances = [] | 130 | material_instances = [] | ||
131 | for material, mass in kwargs.items(): | 131 | for material, mass in kwargs.items(): | ||
132 | if material not in self._MATERIALS_CREATED: | 132 | if material not in self._MATERIALS_CREATED: | ||
133 | raise ValueError('Not valid material found.') | 133 | raise ValueError('Not valid material found.') | ||
134 | 134 | ||||
135 | material_instance = self._MATERIALS_CREATED[material](mass) | 135 | material_instance = self._MATERIALS_CREATED[material](mass) | ||
136 | material_instances.append(material_instance) | 136 | material_instances.append(material_instance) | ||
137 | 137 | ||||
138 | return tuple(material_instances) | 138 | return tuple(material_instances) | ||
139 | 139 | ||||
140 | def can_build(self, target): | 140 | def can_build(self, target): | ||
141 | """Check if the factory's materials can build a wall of target volume.""" | 141 | """Check if the factory's materials can build a wall of target volume.""" | ||
142 | volume_sum = sum( | 142 | volume_sum = sum( | ||
n | 143 | material.volume for material in self.materials_created_by_instance if material._is_valid | n | 143 | material.volume for material in self.materials_created_by_instance |
144 | ) | 144 | ) | ||
145 | return volume_sum >= target | 145 | return volume_sum >= target | ||
146 | 146 | ||||
147 | @classmethod | 147 | @classmethod | ||
148 | def can_build_together(cls, target): | 148 | def can_build_together(cls, target): | ||
149 | """Check if all factories together can build a wall of target volume.""" | 149 | """Check if all factories together can build a wall of target volume.""" | ||
150 | volume_sum = sum( | 150 | volume_sum = sum( | ||
t | 151 | material.volume for material in cls.all_created_materials if material._is_valid | t | 151 | material.volume for material in cls.all_created_materials |
152 | ) | 152 | ) | ||
153 | return volume_sum >= target | 153 | return volume_sum >= target |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | _MATERIALS_DENSITIES = { | f | 1 | _MATERIALS_DENSITIES = { |
2 | 'Concrete': 2500, | 2 | 'Concrete': 2500, | ||
3 | 'Brick': 2000, | 3 | 'Brick': 2000, | ||
4 | 'Stone': 1600, | 4 | 'Stone': 1600, | ||
5 | 'Wood': 600, | 5 | 'Wood': 600, | ||
6 | 'Steel': 7700, | 6 | 'Steel': 7700, | ||
7 | } | 7 | } | ||
8 | 8 | ||||
9 | class Material: | 9 | class Material: | ||
10 | """Base class for materials with mass and density.""" | 10 | """Base class for materials with mass and density.""" | ||
11 | 11 | ||||
12 | _DENSITY = 1 | 12 | _DENSITY = 1 | ||
13 | 13 | ||||
14 | def __init__(self, mass): | 14 | def __init__(self, mass): | ||
15 | """Initialize the material with a given mass.""" | 15 | """Initialize the material with a given mass.""" | ||
16 | self.mass = mass | 16 | self.mass = mass | ||
17 | self._is_valid = True | 17 | self._is_valid = True | ||
18 | 18 | ||||
19 | @property | 19 | @property | ||
20 | def volume(self): | 20 | def volume(self): | ||
21 | """Calculate the volume of the material.""" | 21 | """Calculate the volume of the material.""" | ||
22 | return self.mass / self._DENSITY | 22 | return self.mass / self._DENSITY | ||
23 | 23 | ||||
24 | def validate(self): | 24 | def validate(self): | ||
25 | """Check if the material is still valid for use.""" | 25 | """Check if the material is still valid for use.""" | ||
26 | if not self._is_valid: | 26 | if not self._is_valid: | ||
27 | raise AssertionError('Not valid material found.') | 27 | raise AssertionError('Not valid material found.') | ||
28 | 28 | ||||
29 | 29 | ||||
30 | class Concrete(Material): | 30 | class Concrete(Material): | ||
31 | """Concrete material with predefined density.""" | 31 | """Concrete material with predefined density.""" | ||
32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | 32 | _DENSITY = _MATERIALS_DENSITIES['Concrete'] | ||
33 | 33 | ||||
34 | 34 | ||||
35 | class Brick(Material): | 35 | class Brick(Material): | ||
36 | """Brick material with predefined density.""" | 36 | """Brick material with predefined density.""" | ||
37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | 37 | _DENSITY = _MATERIALS_DENSITIES['Brick'] | ||
38 | 38 | ||||
39 | 39 | ||||
40 | class Stone(Material): | 40 | class Stone(Material): | ||
41 | """Stone material with predefined density.""" | 41 | """Stone material with predefined density.""" | ||
42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | 42 | _DENSITY = _MATERIALS_DENSITIES['Stone'] | ||
43 | 43 | ||||
44 | 44 | ||||
45 | class Wood(Material): | 45 | class Wood(Material): | ||
46 | """Wood material with predefined density.""" | 46 | """Wood material with predefined density.""" | ||
47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | 47 | _DENSITY = _MATERIALS_DENSITIES['Wood'] | ||
48 | 48 | ||||
49 | 49 | ||||
50 | class Steel(Material): | 50 | class Steel(Material): | ||
51 | """Steel material with predefined density.""" | 51 | """Steel material with predefined density.""" | ||
52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | 52 | _DENSITY = _MATERIALS_DENSITIES['Steel'] | ||
53 | 53 | ||||
54 | 54 | ||||
55 | class Factory: | 55 | class Factory: | ||
56 | """Create and manage materials and alloys.""" | 56 | """Create and manage materials and alloys.""" | ||
57 | 57 | ||||
58 | _MATERIALS_CREATED = { | 58 | _MATERIALS_CREATED = { | ||
59 | 'Concrete': Concrete, | 59 | 'Concrete': Concrete, | ||
60 | 'Brick': Brick, | 60 | 'Brick': Brick, | ||
61 | 'Stone': Stone, | 61 | 'Stone': Stone, | ||
62 | 'Wood': Wood, | 62 | 'Wood': Wood, | ||
63 | 'Steel': Steel, | 63 | 'Steel': Steel, | ||
64 | } | 64 | } | ||
65 | 65 | ||||
66 | all_created_materials = [] | 66 | all_created_materials = [] | ||
67 | 67 | ||||
68 | def __init__(self): | 68 | def __init__(self): | ||
69 | self.materials_created_by_instance = [] | 69 | self.materials_created_by_instance = [] | ||
70 | 70 | ||||
71 | def __call__(self, *args, **kwargs): | 71 | def __call__(self, *args, **kwargs): | ||
72 | """Enable the factory instance to be called.""" | 72 | """Enable the factory instance to be called.""" | ||
73 | if len(args) > 0 and len(kwargs) > 0: | 73 | if len(args) > 0 and len(kwargs) > 0: | ||
74 | raise ValueError('One type of arguments are allowed.') | 74 | raise ValueError('One type of arguments are allowed.') | ||
75 | elif (len(args), len(kwargs)) == (0, 0): | 75 | elif (len(args), len(kwargs)) == (0, 0): | ||
76 | raise ValueError('No arguments found.') | 76 | raise ValueError('No arguments found.') | ||
77 | 77 | ||||
78 | if len(args) > 0: | 78 | if len(args) > 0: | ||
79 | return self.positional_call(*args) | 79 | return self.positional_call(*args) | ||
80 | return self.keyword_call(**kwargs) | 80 | return self.keyword_call(**kwargs) | ||
81 | 81 | ||||
82 | def positional_call(self, *args): | 82 | def positional_call(self, *args): | ||
83 | """Handle creation of alloys from positional arguments.""" | 83 | """Handle creation of alloys from positional arguments.""" | ||
84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | 84 | args = [arg[0] if isinstance(arg, tuple) else arg for arg in args] | ||
85 | for material in args: | 85 | for material in args: | ||
86 | material.validate() | 86 | material.validate() | ||
87 | material._is_valid = False | 87 | material._is_valid = False | ||
88 | 88 | ||||
89 | base_materials = [] | 89 | base_materials = [] | ||
90 | for material in args: | 90 | for material in args: | ||
91 | if hasattr(material, '_base_materials'): | 91 | if hasattr(material, '_base_materials'): | ||
92 | base_materials.extend(material._base_materials) | 92 | base_materials.extend(material._base_materials) | ||
93 | else: | 93 | else: | ||
94 | base_materials.append(type(material).__name__) | 94 | base_materials.append(type(material).__name__) | ||
95 | 95 | ||||
96 | unique_base_materials = sorted(set(base_materials)) | 96 | unique_base_materials = sorted(set(base_materials)) | ||
97 | 97 | ||||
98 | alloy_name = '_'.join(unique_base_materials) | 98 | alloy_name = '_'.join(unique_base_materials) | ||
99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | 99 | alloy_density = sum(_MATERIALS_DENSITIES[material] for material in unique_base_materials) / len(unique_base_materials) | ||
100 | alloy_mass = sum(material.mass for material in args) | 100 | alloy_mass = sum(material.mass for material in args) | ||
101 | 101 | ||||
102 | if alloy_name in self._MATERIALS_CREATED: | 102 | if alloy_name in self._MATERIALS_CREATED: | ||
103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | 103 | alloy_class = self._MATERIALS_CREATED[alloy_name] | ||
104 | else: | 104 | else: | ||
105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | 105 | alloy_class = self.create_alloy_class(alloy_name, alloy_density, unique_base_materials) | ||
106 | 106 | ||||
107 | alloy_instance = alloy_class(alloy_mass) | 107 | alloy_instance = alloy_class(alloy_mass) | ||
108 | self.materials_created_by_instance.append(alloy_instance) | 108 | self.materials_created_by_instance.append(alloy_instance) | ||
109 | Factory.all_created_materials.append(alloy_instance) | 109 | Factory.all_created_materials.append(alloy_instance) | ||
110 | 110 | ||||
111 | return alloy_instance | 111 | return alloy_instance | ||
112 | 112 | ||||
113 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | 113 | def create_alloy_class(self, alloy_name, alloy_density, base_materials): | ||
114 | """Dynamically create a class for an alloy.""" | 114 | """Dynamically create a class for an alloy.""" | ||
115 | alloy_class = type( | 115 | alloy_class = type( | ||
116 | alloy_name, | 116 | alloy_name, | ||
117 | (Material,), | 117 | (Material,), | ||
118 | { | 118 | { | ||
119 | '_DENSITY': alloy_density, | 119 | '_DENSITY': alloy_density, | ||
120 | '_base_materials': base_materials, | 120 | '_base_materials': base_materials, | ||
121 | } | 121 | } | ||
122 | ) | 122 | ) | ||
123 | 123 | ||||
124 | self._MATERIALS_CREATED[alloy_name] = alloy_class | 124 | self._MATERIALS_CREATED[alloy_name] = alloy_class | ||
125 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | 125 | _MATERIALS_DENSITIES[alloy_name] = alloy_density | ||
126 | return alloy_class | 126 | return alloy_class | ||
127 | 127 | ||||
128 | def keyword_call(self, **kwargs): | 128 | def keyword_call(self, **kwargs): | ||
129 | """Handle creation of materials from keyword arguments.""" | 129 | """Handle creation of materials from keyword arguments.""" | ||
130 | material_instances = [] | 130 | material_instances = [] | ||
131 | for material, mass in kwargs.items(): | 131 | for material, mass in kwargs.items(): | ||
132 | if material not in self._MATERIALS_CREATED: | 132 | if material not in self._MATERIALS_CREATED: | ||
133 | raise ValueError('Not valid material found.') | 133 | raise ValueError('Not valid material found.') | ||
134 | 134 | ||||
135 | material_instance = self._MATERIALS_CREATED[material](mass) | 135 | material_instance = self._MATERIALS_CREATED[material](mass) | ||
136 | material_instances.append(material_instance) | 136 | material_instances.append(material_instance) | ||
t | 137 | self.materials_created_by_instance.append(material_instance) | t | ||
138 | Factory.all_created_materials.append(material_instance) | ||||
139 | 137 | ||||
140 | return tuple(material_instances) | 138 | return tuple(material_instances) | ||
141 | 139 | ||||
142 | def can_build(self, target): | 140 | def can_build(self, target): | ||
143 | """Check if the factory's materials can build a wall of target volume.""" | 141 | """Check if the factory's materials can build a wall of target volume.""" | ||
144 | volume_sum = sum( | 142 | volume_sum = sum( | ||
145 | material.volume for material in self.materials_created_by_instance if material._is_valid | 143 | material.volume for material in self.materials_created_by_instance if material._is_valid | ||
146 | ) | 144 | ) | ||
147 | return volume_sum >= target | 145 | return volume_sum >= target | ||
148 | 146 | ||||
149 | @classmethod | 147 | @classmethod | ||
150 | def can_build_together(cls, target): | 148 | def can_build_together(cls, target): | ||
151 | """Check if all factories together can build a wall of target volume.""" | 149 | """Check if all factories together can build a wall of target volume.""" | ||
152 | volume_sum = sum( | 150 | volume_sum = sum( | ||
153 | material.volume for material in cls.all_created_materials if material._is_valid | 151 | material.volume for material in cls.all_created_materials if material._is_valid | ||
154 | ) | 152 | ) | ||
155 | return volume_sum >= target | 153 | return volume_sum >= target |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|