1import copy
2import math
3import ctypes
4from typing import Any
5
6class Effect:
7
8 def __init__(self,name,func):
9 self.func=func
10 self.name=name
11
12 self.intensity=1
13 self.has_been_used= False
14 self.is_part_of_bigger= False
15 self.has_teacher_used= False
16 self.molecular_mass=0
17
18
19 for ch in self.name:
20 self.molecular_mass+=ord(ch)
21
22 def __copy__(self):
23 new_effect=Effect(self.name,self.func)
24 new_effect.intensity=self.intensity
25 new_effect.has_been_used=self.has_been_used
26 return new_effect
27
28 def __call__(self,target):
29 if self.has_been_used:
30 raise TypeError("Effect is depleted.")
31 if self.has_teacher_used:
32 raise TypeError("Potion is depleted.")
33 if self.is_part_of_bigger:
34 raise TypeError("Potion is now part of something bigger than itself.")
35
36 for i in range(self.intensity):
37 self.func(target)
38
39 self.has_been_used= True
40
41
42class Potion:
43
44 def __init__(self, effects, duration):
45
46 self.is_part= False
47 self.has_teacher_used= False
48 self.effects={}
49 self.duration= duration
50 for effect,func in effects.items():
51 new_effect=Effect(effect,func)
52 setattr(self,effect,new_effect)
53 self.effects[effect]=new_effect
54
55
56 def add_effect(self, name, new_effect):
57 setattr(self,name,new_effect)
58 self.effects[name]=new_effect
59
60 def __add__(self,other):
61 if self.is_part or other.is_part:
62 raise TypeError("Potion is now part of something bigger than itself.")
63 if self.has_teacher_used or other.has_teacher_used:
64 raise TypeError("Potion is depleted.")
65
66 new_duration= max(self.duration, other.duration)
67 new_potion=Potion({}, new_duration)
68
69 for name,effect in self.effects.items():
70 new_potion.add_effect(name,copy.copy(effect))
71 effect.is_part_of_bigger=True
72
73 for name,effect in other.effects.items():
74 if name in new_potion.effects:
75 new_potion.effects[name].intensity+=effect.intensity
76 else:
77 new_potion.add_effect(name,copy.copy(effect))
78 effect.is_part_of_bigger=True
79
80 self.is_part= True
81 other.is_part= True
82 return new_potion
83
84
85 def __mul__(self,number):
86 if self.is_part:
87 raise TypeError("Potion is now part of something bigger than itself.")
88 if self.has_teacher_used:
89 raise TypeError("Potion is depleted.")
90
91 new_potion= self+Potion({},0)
92 for name,effect in new_potion.effects.items():
93 effect.intensity*=number
94 if effect.intensity-math.floor(effect.intensity)<=0.5:
95 effect.intensity=math.floor(effect.intensity)
96 else:
97 effect.intensity=math.ceil(effect.intensity)
98
99 self.is_part= True
100 return new_potion
101
102
103 def __sub__(self,other):
104 if self.is_part or other.is_part:
105 raise TypeError("Potion is now part of something bigger than itself.")
106 if self.has_teacher_used or other.has_teacher_used:
107 raise TypeError("Potion is depleted.")
108
109 for name,effect in other.effects.items():
110 if effect.has_been_used:
111 continue
112 if (name not in self.effects)or(self.effects[name].has_been_used):
113 raise TypeError(f"Invalid effect: {name}")
114 effect.is_part_of_bigger=True
115
116 new_potion=Potion({},self.duration)
117
118 for name, effect in self.effects.items():
119 current_effect= copy.copy(effect)
120 if name in other.effects:
121 if effect.intensity-other.effects[name].intensity<=0:
122 continue
123 if not other.effects[name].has_been_used:
124 current_effect.intensity-=other.effects[name].intensity
125 new_potion.add_effect(name,current_effect)
126 effect.is_part_of_bigger=True
127
128 self.is_part= True
129 other.is_part= True
130 return new_potion
131
132
133 def __truediv__(self,number):
134 if self.is_part:
135 raise TypeError("Potion is now part of something bigger than itself.")
136 if self.has_teacher_used:
137 raise TypeError("Potion is depleted.")
138
139 result= []
140 for i in range(number):
141 result.append(self*(1/number))
142 self.is_part=False
143 self.is_part=True
144 return tuple(result)
145
146
147 def __eq__(self,other):
148 if self.is_part or other.is_part:
149 raise TypeError("Potion is now part of something bigger than itself.")
150 if self.has_teacher_used or other.has_teacher_used:
151 raise TypeError("Potion is depleted.")
152
153 if set(self.effects.keys()) != set(other.effects.keys()):
154 return False
155
156 for name,effect in self.effects.items():
157 if effect.has_been_used != other.effects[name].has_been_used:
158 return False
159 if effect.intensity != other.effects[name].intensity:
160 return False
161 return True
162
163
164 def get_effects_sum(self):
165 result=0
166
167 for name, effect in self.effects.items():
168 if not effect.has_been_used:
169 result += effect.intensity
170 return result
171
172
173 def __lt__(self,other):
174 if self.is_part or other.is_part:
175 raise TypeError("Potion is now part of something bigger than itself.")
176 if self.has_teacher_used or other.has_teacher_used:
177 raise TypeError("Potion is depleted.")
178
179 return self.get_effects_sum()< other.get_effects_sum()
180
181
182 def __gt__(self,other):
183 return other < self
184
185
186class ГоспожатаПоХимия:
187
188 def __init__(self):
189 #self.values_container= {}
190 self.ticks_counter=0
191
192 def apply(self,target, potion):
193 if potion.is_part:
194 raise TypeError("Potion is now part of something bigger than itself.")
195 if potion.has_teacher_used:
196 raise TypeError("Potion is depleted.")
197 if potion.duration == 0:
198 return
199
200 potion.has_teacher_used= True
201
202 result= list(potion.effects.values())
203 sorted_result= sorted_effects = sorted(result, key=lambda effect: effect.molecular_mass, reverse=True)
204
205 target_id= id(target)
206
207 # if target_id not in self.values_container:
208 # self.values_container[target_id] = [copy.deepcopy(target),[copy.deepcopy(potion)], target]
209 # else:
210 # self.values_container[target_id][1].append(copy.deepcopy(potion))
211
212 for effect in sorted_result:
213 if not effect.has_been_used:
214 effect.func(target)
215 effect.has_been_used= True
216 effect.has_teacher_used= True
217 self.values_container[target_id].pop()
218 self.values_container[target_id].append(target)
219
220
221 def tick(self):
222 pass
223 # self.ticks_counter+=1
224
225 # for current_id,values in self.values_container.items():
226 # values[2]=values[0]
227 # for potion in values[1]:
228 # if potion.duration<=self.ticks_counter:
229 # values[1].remove(potion)
230 # for potion in values[1]:
231 # result= list(potion.effects.values())
232 # sorted_result= sorted_effects = sorted(result, key=lambda effect: effect.molecular_mass, reverse=True)
233 # for effect in sorted_result:
234 # if not effect.has_been_used:
235 # effect.func(values[2])
236
237
.......F....EEEEEEEE
======================================================================
ERROR: test_applying_depleted_potion (test.TestГоспожатаПоХимия)
Test applying a depleted potion or a potion that was used in a reaction.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 379, in test_applying_depleted_potion
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
ERROR: test_applying_normal_case (test.TestГоспожатаПоХимия)
Test applying a normal potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 350, in test_applying_normal_case
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
ERROR: test_applying_order (test.TestГоспожатаПоХимия)
Test applying order of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 404, in test_applying_order
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
ERROR: test_applying_part_of_potion (test.TestГоспожатаПоХимия)
Test applying only a part of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 365, in test_applying_part_of_potion
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
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 424, in test_ticking_immutable
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
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 454, in test_ticking_multiple_potions
self._dimitrichka.apply(self._target, potion1)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
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 485, in test_ticking_multiple_targets
self._dimitrichka.apply(target1, potion1)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
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 438, in test_ticking_mutable
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 217, in apply
self.values_container[target_id].pop()
AttributeError: 'ГоспожатаПоХимия' object has no attribute 'values_container'
======================================================================
FAIL: test_deprecation (test.TestPotionOperations)
Test deprecation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 270, in test_deprecation
with self.assertRaisesRegex(TypeError, 'Potion is now part of something bigger than itself\.'):
AssertionError: TypeError not raised
----------------------------------------------------------------------
Ran 20 tests in 0.002s
FAILED (failures=1, errors=8)
05.12.2023 18:48
05.12.2023 18:49
05.12.2023 18:49
05.12.2023 18:49