1import math
2import copy
3
4def check_states(*potions):
5
6 for potion in potions:
7 if potion.mixed:
8 raise TypeError("Potion is now part of something bigger than itself.")
9
10 if potion.applied:
11 raise TypeError("Potion is depleted.")
12
13def set_is_part_true(effect):
14
15 for name in effect.effect_dict.keys():
16 effect.effect_dict[name].is_part_of_smth = True
17
18class Effect:
19
20 def __init__(self, name, function):
21 self.name = name
22 self.function = function
23 self.intensity = 1
24 self.used = False
25 self.is_part_of_smth = False
26 self.masa = sum(ord(char) for char in name)
27 self.applied = False
28
29 def __call__(self, args):
30 if self.applied:
31 raise TypeError("Potion is depleted.")
32 elif self.used:
33 raise TypeError("Effect is depleted.")
34 elif self.is_part_of_smth:
35 raise TypeError("Potion is now part of something bigger than itself.")
36 for times in range(self.intensity):
37 self.function(args)
38 self.used = True
39
40
41class Potion:
42
43 def __init__(self, effects, duration):
44 self.effect_dict = {}
45 for name, func in effects.items():
46 new_effect = Effect(name, func)
47 self.effect_dict[name] = new_effect
48 setattr(self, name, new_effect)
49 self.duration = duration
50 self.mixed = False
51 self.applied = False
52
53 def __eq__(self, other_potion):
54
55 check_states(self, other_potion)
56
57 if self.effect_dict.keys() != other_potion.effect_dict.keys():
58 return False
59 for name in self.effect_dict.keys():
60 if (self.effect_dict[name].intensity != other_potion.effect_dict[name].intensity) and ((self.effect_dict[name].used and other_potion.effect_dict[name].used) or ((not self.effect_dict[name].used) and (not other_potion.effect_dict[name].used))):
61 return False
62
63 return True
64
65 def __gt__(self, other_potion):
66
67 sum1 = sum(self.effect_dict[name].intensity for name in self.effect_dict if not self.effect_dict[name].used)
68 sum2 = sum(other_potion.effect_dict[name].intensity for name in other_potion.effect_dict if not other_potion.effect_dict[name].used)
69
70 return sum1 > sum2
71
72 def __lt__(self, other_potion):
73
74 check_states(self, other_potion)
75
76 sum1 = sum(self.effect_dict[name].intensity for name in self.effect_dict if not self.effect_dict[name].used)
77 sum2 = sum(other_potion.effect_dict[name].intensity for name in other_potion.effect_dict if not other_potion.effect_dict[name].used)
78
79 return sum1 < sum2
80
81 def __truediv__(self, num):
82 list_of_potions = []
83 for i in range(num):
84 list_of_potions.append(self*(1/num))
85 self.mixed = False
86 self.mixed = True
87 return tuple(list_of_potions)
88
89 def __mul__(self, num):
90
91 check_states(self)
92 new_potion = copy.deepcopy(self)
93 for effect in new_potion.effect_dict.values():
94 effect.intensity *= num
95 if isinstance(effect.intensity, float):
96 if effect.intensity - int(effect.intensity) <= 0.5:
97 effect.intensity = math.floor(effect.intensity)
98 else:
99 effect.intensity = math.ceil(effect.intensity)
100 set_is_part_true(self)
101
102 self.mixed = True
103 return new_potion
104
105 def __sub__(self, other_potion):
106
107 for name, func in other_potion.effect_dict.items():
108 if (name not in self.effect_dict) or (name in self.effect_dict and self.effect_dict[name].used):
109 raise TypeError("There is no such effect on the left side")
110
111 check_states(self, other_potion)
112
113 new_effects = {}
114 new_pot = Potion(new_effects, self.duration)
115 for name, effect in self.effect_dict.items():
116 if name not in other_potion.effect_dict:
117 curr_effect = Effect(name, effect.function)
118 curr_effect.intensity = effect.intensity
119 curr_effect.used = effect.used
120 new_pot.effect_dict[name] = curr_effect
121 setattr(new_pot, name, curr_effect)
122 elif name in other_potion.effect_dict and not other_potion.effect_dict[name].used:
123 curr_effect = Effect(name, effect.function)
124 curr_effect.intensity = effect.intensity - other_potion.effect_dict[name].intensity
125 if curr_effect.intensity <= 0:
126 curr_effect.used = True
127 else:
128 curr_effect.used = effect.used
129 new_pot.effect_dict[name] = curr_effect
130 setattr(new_pot, name, curr_effect)
131
132 set_is_part_true(self)
133 set_is_part_true(other_potion)
134
135 self.mixed = True
136 other_potion.mixed = True
137 return new_pot
138
139 def __add__(self, other_potion):
140
141 check_states(self, other_potion)
142
143 new_effects = {}
144 max_duration = max(self.duration, other_potion.duration)
145 new_potion = Potion(new_effects, max_duration)
146 for name, func in self.effect_dict.items():
147 new_effect = Effect(name, func.function)
148 new_effect.intensity = func.intensity
149 new_effect.used = func.used
150 new_potion.effect_dict[name] = new_effect
151 setattr(new_potion, name, new_effect)
152
153 for key, value in other_potion.effect_dict.items():
154 if key in self.effect_dict:
155 new_potion.effect_dict[key].intensity += value.intensity
156 else:
157 new_effect = Effect(key, value.function)
158 new_effect.intensity = value.intensity
159 new_effect.used = value.used
160 new_potion.effect_dict[key] = new_effect
161 setattr(new_potion, key, new_effect)
162
163 set_is_part_true(self)
164 set_is_part_true(other_potion)
165
166 self.mixed = True
167 other_potion.mixed = True
168 return new_potion
169
170
171class ГоспожатаПоХимия:
172
173 def __init__(self):
174 self.counterDuration = 0
175 self.list_of_targets = []
176
177 def apply_potion(self, target, potion):
178 for effect in potion.effect_dict.values():
179 effect.function(target)
180
181 def tick(self):
182 self.counterDuration += 1
183 for potion_in_list in self.list_of_targets:
184 print(potion_in_list[2].duration)
185 print(potion_in_list[1].size)
186 print(potion_in_list[0].size)
187 if potion_in_list[2].duration == self.counterDuration:
188 potion_in_list[1].__dict__ = potion_in_list[0].__dict__
189 self.list_of_targets.remove(potion_in_list)
190 for curr_list in self.list_of_targets:
191 if id(curr_list[1]) == id(potion_in_list[1]):
192 self.apply_potion(curr_list[1], curr_list[2])
193
194
195 def apply(self, target, potion):
196
197 if potion.duration == 0:
198 return
199
200 check_states(potion)
201 target_before_apply = copy.deepcopy(target)
202
203 potion.applied = True
204 items_list = [(key, value) for key, value in potion.effect_dict.items()]
205 sorted_list = sorted(items_list, key=lambda item: item[1].masa, reverse=True)
206 for effect in sorted_list:
207 if not effect[1].used:
208 for times in range(effect[1].intensity):
209 effect[1].function(target)
210 effect[1].used = True
211 effect[1].applied = True
212
213 self.list_of_targets.append([target_before_apply, target, potion])
214 self.list_of_targets = sorted(self.list_of_targets, key=lambda x: x[2].duration)
..........EE....E
Stdout:
2
E
Stdout:
1
E
Stdout:
1
E
Stdout:
1
======================================================================
ERROR: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 169, in test_purification
potion.int_attr_fun(self._target)
File "/tmp/solution.py", line 33, in __call__
raise TypeError("Effect is depleted.")
TypeError: Effect is depleted.
======================================================================
ERROR: test_separation (test.TestPotionOperations)
Test separation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 218, in test_separation
potion2.int_attr_fun(self._target)
File "/tmp/solution.py", line 35, in __call__
raise TypeError("Potion is now part of something bigger than itself.")
TypeError: Potion is now part of something bigger than itself.
======================================================================
ERROR: test_ticking_immutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with immutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 426, in test_ticking_immutable
self._dimitrichka.tick()
File "/tmp/solution.py", line 185, in tick
print(potion_in_list[1].size)
AttributeError: 'Target' object has no attribute 'size'
Stdout:
2
======================================================================
ERROR: test_ticking_multiple_potions (test.TestГоспожатаПоХимия)
Test ticking after applying multiple potions which affect the same attribute.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 457, in test_ticking_multiple_potions
self._dimitrichka.tick()
File "/tmp/solution.py", line 185, in tick
print(potion_in_list[1].size)
AttributeError: 'Target' object has no attribute 'size'
Stdout:
1
======================================================================
ERROR: test_ticking_multiple_targets (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 489, in test_ticking_multiple_targets
self._dimitrichka.tick()
File "/tmp/solution.py", line 185, in tick
print(potion_in_list[1].size)
AttributeError: 'Target' object has no attribute 'size'
Stdout:
1
======================================================================
ERROR: test_ticking_mutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 443, in test_ticking_mutable
self._dimitrichka.tick()
File "/tmp/solution.py", line 185, in tick
print(potion_in_list[1].size)
AttributeError: 'Target' object has no attribute 'size'
Stdout:
1
----------------------------------------------------------------------
Ran 20 tests in 0.003s
FAILED (errors=6)
08.12.2023 13:53
08.12.2023 13:54