1import math
2
3class Potion:
4 def __init__(self, effects, duration):
5 self.effects = effects
6 self.duration = duration
7 self.intensities = {}
8 self.used_effects = set()
9 self.used = False
10 self.depleted = False
11
12 for name in effects.keys():
13 self.intensities[name] = self.intensities.get(name, 0) + 1
14
15 def __getattr__(self, name):
16 if name not in self.effects.keys():
17 raise AttributeError("Attribute not found.")
18 if self.used:
19 raise TypeError("Potion is now part of something bigger than itself.")
20 if self.depleted:
21 raise TypeError("Potion is depleted.")
22 if name in self.used_effects:
23 raise TypeError("Effect is depleted.")
24
25 def execute_n_times(func):
26 def wrapper(target):
27 for _ in range(int(self.intensities.get(name))):
28 func(target)
29 return wrapper
30 self.used_effects.add(name)
31 return execute_n_times(self.effects.get(name))
32
33 def __add__(self, other):
34 validate(self)
35 validate(other)
36
37 new_duration = max(self.duration, other.duration)
38 combined_effects = {}
39 intensities = {}
40 used_effects = set()
41
42 for name, usage in self.effects.items():
43 combined_effects[name] = usage
44 intensities[name] = intensities.get(name) + 1 if name in intensities else self.intensities.get(name, 0)
45 used_effects = used_effects.union(self.used_effects)
46
47 for name, usage in other.effects.items():
48 combined_effects[name] = usage
49 intensities[name] = intensities.get(name) + 1 if name in intensities else other.intensities.get(name, 0)
50 used_effects = used_effects.union(other.used_effects)
51
52 self.used = True
53 other.used = True
54 potion = Potion(combined_effects, new_duration)
55 potion.intensities = intensities
56 potion.used_effects = used_effects
57 if len(potion.used_effects) == len(potion.effects):
58 potion.depleted = True
59 return potion
60
61 def __mul__(self, other):
62 validate(self)
63
64 if isinstance(other, (int, float)):
65 potion = Potion(self.effects.copy(), self.duration)
66 intensities = {}
67
68 for name, value in self.intensities.items():
69 intensities[name] = value * other
70 if 0 < other < 1:
71 intensities[name] = self._round_value(intensities[name])
72
73 potion.intensities = intensities
74 potion.used_effects = self.used_effects.copy()
75 if len(potion.used_effects) == len(potion.effects):
76 potion.depleted = True
77 self.used = True
78 return potion
79
80 def __sub__(self, other):
81 validate(self)
82 validate(other)
83
84 new_duration = other.duration
85 purified_effects = {}
86 intensities = {}
87 used_effects = set()
88
89 for name, usage in other.effects.items():
90 if name not in self.effects:
91 raise TypeError("Cannot purify potion.")
92 if other.intensities.get(name) >= self.intensities.get(name):
93 continue
94 else:
95 purified_effects[name] = usage
96 intensities[name] = self.intensities.get(name) - other.intensities.get(name)
97 if name in other.used_effects or name in self.used_effects:
98 used_effects.add(name)
99
100 for name, usage in self.effects.items():
101 if name not in other.effects.keys():
102 purified_effects[name] = usage
103 intensities[name] = self.intensities.get(name)
104 if name in self.used_effects:
105 used_effects.add(name)
106
107 self.used = True
108 other.used = True
109 potion = Potion(purified_effects, new_duration)
110 potion.intensities = intensities
111 potion.used_effects = used_effects
112 if len(potion.used_effects) == len(potion.effects):
113 potion.depleted = True
114 return potion
115
116 def __truediv__(self, other):
117 validate(self)
118
119 if isinstance(other, (int, float)):
120 intensities = {}
121
122 for name, intensity in self.intensities.items():
123 intensities[name] = self._round_value(intensity / other)
124
125 result = tuple(Potion(self.effects.copy(), self.duration) for _ in range(other))
126 for potion in result:
127 potion.intensities = intensities.copy()
128 potion.used_effects = self.used_effects.copy()
129 if len(potion.used_effects) == len(potion.effects):
130 potion.depleted = True
131 self.used = True
132 return result
133
134
135 def __eq__(self, other):
136 validate(self)
137 validate(other)
138
139 if not isinstance(other, Potion):
140 return False
141
142 if len(self.effects) != len(other.effects):
143 return False
144
145 for name in self.effects.keys():
146 if name not in other.effects:
147 return False
148 if self.intensities.get(name) != other.intensities.get(name):
149 if name in self.used_effects and name in other.used_effects:
150 continue
151 if (name in self.used_effects and other.intensities.get(name) == 0 or
152 name in other.used_effects and self.intensities.get(name) == 0):
153 continue
154 return False
155 return True
156
157 def __lt__(self, other):
158 validate(self)
159 validate(other)
160
161 if not isinstance(other, Potion):
162 return False
163
164 first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects])
165 second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects])
166 return first_sum < second_sum
167
168 def __gt__(self, other):
169 validate(self)
170 validate(other)
171
172 if not isinstance(other, Potion):
173 return False
174
175 first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects])
176 second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects])
177 return first_sum > second_sum
178
179 def __hash__(self):
180 return super().__hash__()
181
182 def _round_value(self, value):
183 if value % 1 > 0.5:
184 return int(math.ceil(value))
185 return int(math.floor(value))
186
187def validate(potion):
188 if potion.depleted:
189 raise TypeError("Potion is depleted.")
190 if potion.used:
191 raise TypeError("Potion is now part of something bigger than itself.")
192
193def ascii_sum(string):
194 return sum(ord(char) for char in string)
195
196class ГоспожатаПоХимия:
197 # {
198 # target: { initial_state },
199 # target2: { initial_state }
200 # }
201 _target_states = {}
202
203 # {
204 # target: [potion1, potion2],
205 # target2: [potion3]
206 # }
207 _target_potions = {}
208
209 # {
210 # target: {
211 # potion1: time1,
212 # potion2: time2
213 # },
214 # target2: {
215 # potion3: time3
216 # }
217 # }
218 _times = {}
219
220 def apply(self, target, potion):
221 validate(potion)
222
223 if target not in self._target_states:
224 self.save_initial_state(target)
225 if target not in self._times.keys():
226 self._times[target] = {}
227 if target not in self._target_potions.keys():
228 self._target_potions[target] = []
229
230 self._times[target][potion] = potion.duration
231 self._target_potions[target].append(potion)
232 sorted_effects = sorted(list(potion.effects), key=ascii_sum, reverse=True)
233 for effect in sorted_effects:
234 try:
235 getattr(potion, effect)(target)
236 except TypeError:
237 continue
238 potion.depleted = True
239 if potion.duration == 0:
240 self.reset_target(target)
241
242 def _apply_all(self, target):
243 for potion in self._target_potions[target]:
244 if potion.duration <= 0:
245 continue
246 for effect in sorted(list(potion.effects), key=ascii_sum, reverse=True):
247 potion.effects[effect](target)
248
249 def tick(self):
250 for target, potions in self._times.items():
251 for potion, time in potions.items():
252 self._times[target][potion] = time - 1
253
254 for target, potions in (self._times.copy()).items():
255 for potion, time in (potions.copy()).items():
256 if time <= 0:
257 self._times[target].pop(potion, None)
258 self._target_potions[target].remove(potion)
259 if len(self._times[target]) == 0:
260 self._times.pop(target, None)
261 self.reset_target(target)
262 if target not in self._times:
263 self._target_potions.pop(target, None)
264 self._target_states.pop(target, None)
265
266 def save_initial_state(self, target):
267 self._target_states[target] = {attr: getattr(target, attr) for attr in dir(target) if not attr.startswith('_')}
268
269 def reset_target(self, target):
270 for attr, initial_value in self._target_states[target].items():
271 setattr(target, attr, initial_value)
272 for attr in dir(target):
273 if not attr.startswith('_') and attr not in self._target_states[target].keys():
274 try:
275 delattr(target, attr)
276 except AttributeError:
277 continue
278
279 self._apply_all(target)
...................F
======================================================================
FAIL: test_ticking_mutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 446, in test_ticking_mutable
self.assertEqual(self._target.list_attr, [1, 2, 3])
AssertionError: Lists differ: [1, 2, 3, 4] != [1, 2, 3]
First list contains 1 additional elements.
First extra element 3:
4
- [1, 2, 3, 4]
? ---
+ [1, 2, 3]
----------------------------------------------------------------------
Ran 20 tests in 0.002s
FAILED (failures=1)
Георги Кунчев
04.12.2023 11:24Доста чисто решение. Имах някакви дребни коментари, но цялостният стил е супер.
|
| f | 1 | import math | f | 1 | import math |
| 2 | 2 | ||||
| 3 | class Potion: | 3 | class Potion: | ||
| 4 | def __init__(self, effects, duration): | 4 | def __init__(self, effects, duration): | ||
| 5 | self.effects = effects | 5 | self.effects = effects | ||
| 6 | self.duration = duration | 6 | self.duration = duration | ||
| 7 | self.intensities = {} | 7 | self.intensities = {} | ||
| 8 | self.used_effects = set() | 8 | self.used_effects = set() | ||
| 9 | self.used = False | 9 | self.used = False | ||
| 10 | self.depleted = False | 10 | self.depleted = False | ||
| 11 | 11 | ||||
| 12 | for name in effects.keys(): | 12 | for name in effects.keys(): | ||
| 13 | self.intensities[name] = self.intensities.get(name, 0) + 1 | 13 | self.intensities[name] = self.intensities.get(name, 0) + 1 | ||
| 14 | 14 | ||||
| 15 | def __getattr__(self, name): | 15 | def __getattr__(self, name): | ||
| 16 | if name not in self.effects.keys(): | 16 | if name not in self.effects.keys(): | ||
| 17 | raise AttributeError("Attribute not found.") | 17 | raise AttributeError("Attribute not found.") | ||
| 18 | if self.used: | 18 | if self.used: | ||
| 19 | raise TypeError("Potion is now part of something bigger than itself.") | 19 | raise TypeError("Potion is now part of something bigger than itself.") | ||
| n | n | 20 | if self.depleted: | ||
| 21 | raise TypeError("Potion is depleted.") | ||||
| 20 | if name in self.used_effects: | 22 | if name in self.used_effects: | ||
| 21 | raise TypeError("Effect is depleted.") | 23 | raise TypeError("Effect is depleted.") | ||
| 22 | 24 | ||||
| 23 | def execute_n_times(func): | 25 | def execute_n_times(func): | ||
| 24 | def wrapper(target): | 26 | def wrapper(target): | ||
| 25 | for _ in range(int(self.intensities.get(name))): | 27 | for _ in range(int(self.intensities.get(name))): | ||
| 26 | func(target) | 28 | func(target) | ||
| 27 | return wrapper | 29 | return wrapper | ||
| 28 | self.used_effects.add(name) | 30 | self.used_effects.add(name) | ||
| n | 29 | if len(self.used_effects) == len(self.effects): | n | ||
| 30 | self.depleted = True | ||||
| 31 | return execute_n_times(self.effects.get(name)) | 31 | return execute_n_times(self.effects.get(name)) | ||
| 32 | 32 | ||||
| 33 | def __add__(self, other): | 33 | def __add__(self, other): | ||
| 34 | validate(self) | 34 | validate(self) | ||
| 35 | validate(other) | 35 | validate(other) | ||
| 36 | 36 | ||||
| 37 | new_duration = max(self.duration, other.duration) | 37 | new_duration = max(self.duration, other.duration) | ||
| 38 | combined_effects = {} | 38 | combined_effects = {} | ||
| 39 | intensities = {} | 39 | intensities = {} | ||
| 40 | used_effects = set() | 40 | used_effects = set() | ||
| 41 | 41 | ||||
| 42 | for name, usage in self.effects.items(): | 42 | for name, usage in self.effects.items(): | ||
| 43 | combined_effects[name] = usage | 43 | combined_effects[name] = usage | ||
| 44 | intensities[name] = intensities.get(name) + 1 if name in intensities else self.intensities.get(name, 0) | 44 | intensities[name] = intensities.get(name) + 1 if name in intensities else self.intensities.get(name, 0) | ||
| 45 | used_effects = used_effects.union(self.used_effects) | 45 | used_effects = used_effects.union(self.used_effects) | ||
| 46 | 46 | ||||
| 47 | for name, usage in other.effects.items(): | 47 | for name, usage in other.effects.items(): | ||
| 48 | combined_effects[name] = usage | 48 | combined_effects[name] = usage | ||
| 49 | intensities[name] = intensities.get(name) + 1 if name in intensities else other.intensities.get(name, 0) | 49 | intensities[name] = intensities.get(name) + 1 if name in intensities else other.intensities.get(name, 0) | ||
| 50 | used_effects = used_effects.union(other.used_effects) | 50 | used_effects = used_effects.union(other.used_effects) | ||
| 51 | 51 | ||||
| 52 | self.used = True | 52 | self.used = True | ||
| 53 | other.used = True | 53 | other.used = True | ||
| 54 | potion = Potion(combined_effects, new_duration) | 54 | potion = Potion(combined_effects, new_duration) | ||
| 55 | potion.intensities = intensities | 55 | potion.intensities = intensities | ||
| 56 | potion.used_effects = used_effects | 56 | potion.used_effects = used_effects | ||
| 57 | if len(potion.used_effects) == len(potion.effects): | 57 | if len(potion.used_effects) == len(potion.effects): | ||
| 58 | potion.depleted = True | 58 | potion.depleted = True | ||
| 59 | return potion | 59 | return potion | ||
| 60 | 60 | ||||
| 61 | def __mul__(self, other): | 61 | def __mul__(self, other): | ||
| 62 | validate(self) | 62 | validate(self) | ||
| 63 | 63 | ||||
| 64 | if isinstance(other, (int, float)): | 64 | if isinstance(other, (int, float)): | ||
| 65 | potion = Potion(self.effects.copy(), self.duration) | 65 | potion = Potion(self.effects.copy(), self.duration) | ||
| 66 | intensities = {} | 66 | intensities = {} | ||
| 67 | 67 | ||||
| 68 | for name, value in self.intensities.items(): | 68 | for name, value in self.intensities.items(): | ||
| 69 | intensities[name] = value * other | 69 | intensities[name] = value * other | ||
| 70 | if 0 < other < 1: | 70 | if 0 < other < 1: | ||
| 71 | intensities[name] = self._round_value(intensities[name]) | 71 | intensities[name] = self._round_value(intensities[name]) | ||
| 72 | 72 | ||||
| 73 | potion.intensities = intensities | 73 | potion.intensities = intensities | ||
| 74 | potion.used_effects = self.used_effects.copy() | 74 | potion.used_effects = self.used_effects.copy() | ||
| 75 | if len(potion.used_effects) == len(potion.effects): | 75 | if len(potion.used_effects) == len(potion.effects): | ||
| 76 | potion.depleted = True | 76 | potion.depleted = True | ||
| 77 | self.used = True | 77 | self.used = True | ||
| 78 | return potion | 78 | return potion | ||
| 79 | 79 | ||||
| 80 | def __sub__(self, other): | 80 | def __sub__(self, other): | ||
| 81 | validate(self) | 81 | validate(self) | ||
| 82 | validate(other) | 82 | validate(other) | ||
| 83 | 83 | ||||
| 84 | new_duration = other.duration | 84 | new_duration = other.duration | ||
| 85 | purified_effects = {} | 85 | purified_effects = {} | ||
| 86 | intensities = {} | 86 | intensities = {} | ||
| 87 | used_effects = set() | 87 | used_effects = set() | ||
| 88 | 88 | ||||
| 89 | for name, usage in other.effects.items(): | 89 | for name, usage in other.effects.items(): | ||
| 90 | if name not in self.effects: | 90 | if name not in self.effects: | ||
| 91 | raise TypeError("Cannot purify potion.") | 91 | raise TypeError("Cannot purify potion.") | ||
| 92 | if other.intensities.get(name) >= self.intensities.get(name): | 92 | if other.intensities.get(name) >= self.intensities.get(name): | ||
| 93 | continue | 93 | continue | ||
| 94 | else: | 94 | else: | ||
| 95 | purified_effects[name] = usage | 95 | purified_effects[name] = usage | ||
| 96 | intensities[name] = self.intensities.get(name) - other.intensities.get(name) | 96 | intensities[name] = self.intensities.get(name) - other.intensities.get(name) | ||
| n | 97 | if name in other.used_effects: | n | 97 | if name in other.used_effects or name in self.used_effects: |
| 98 | used_effects.add(name) | 98 | used_effects.add(name) | ||
| 99 | 99 | ||||
| 100 | for name, usage in self.effects.items(): | 100 | for name, usage in self.effects.items(): | ||
| 101 | if name not in other.effects.keys(): | 101 | if name not in other.effects.keys(): | ||
| 102 | purified_effects[name] = usage | 102 | purified_effects[name] = usage | ||
| 103 | intensities[name] = self.intensities.get(name) | 103 | intensities[name] = self.intensities.get(name) | ||
| 104 | if name in self.used_effects: | 104 | if name in self.used_effects: | ||
| 105 | used_effects.add(name) | 105 | used_effects.add(name) | ||
| 106 | 106 | ||||
| 107 | self.used = True | 107 | self.used = True | ||
| 108 | other.used = True | 108 | other.used = True | ||
| 109 | potion = Potion(purified_effects, new_duration) | 109 | potion = Potion(purified_effects, new_duration) | ||
| 110 | potion.intensities = intensities | 110 | potion.intensities = intensities | ||
| 111 | potion.used_effects = used_effects | 111 | potion.used_effects = used_effects | ||
| 112 | if len(potion.used_effects) == len(potion.effects): | 112 | if len(potion.used_effects) == len(potion.effects): | ||
| n | 113 | potion.depleted = True | n | 113 | potion.depleted = True |
| 114 | return potion | 114 | return potion | ||
| 115 | 115 | ||||
| 116 | def __truediv__(self, other): | 116 | def __truediv__(self, other): | ||
| 117 | validate(self) | 117 | validate(self) | ||
| 118 | 118 | ||||
| 119 | if isinstance(other, (int, float)): | 119 | if isinstance(other, (int, float)): | ||
| 120 | intensities = {} | 120 | intensities = {} | ||
| 121 | 121 | ||||
| 122 | for name, intensity in self.intensities.items(): | 122 | for name, intensity in self.intensities.items(): | ||
| 123 | intensities[name] = self._round_value(intensity / other) | 123 | intensities[name] = self._round_value(intensity / other) | ||
| 124 | 124 | ||||
| 125 | result = tuple(Potion(self.effects.copy(), self.duration) for _ in range(other)) | 125 | result = tuple(Potion(self.effects.copy(), self.duration) for _ in range(other)) | ||
| 126 | for potion in result: | 126 | for potion in result: | ||
| 127 | potion.intensities = intensities.copy() | 127 | potion.intensities = intensities.copy() | ||
| 128 | potion.used_effects = self.used_effects.copy() | 128 | potion.used_effects = self.used_effects.copy() | ||
| 129 | if len(potion.used_effects) == len(potion.effects): | 129 | if len(potion.used_effects) == len(potion.effects): | ||
| 130 | potion.depleted = True | 130 | potion.depleted = True | ||
| 131 | self.used = True | 131 | self.used = True | ||
| 132 | return result | 132 | return result | ||
| 133 | 133 | ||||
| 134 | 134 | ||||
| 135 | def __eq__(self, other): | 135 | def __eq__(self, other): | ||
| 136 | validate(self) | 136 | validate(self) | ||
| 137 | validate(other) | 137 | validate(other) | ||
| 138 | 138 | ||||
| 139 | if not isinstance(other, Potion): | 139 | if not isinstance(other, Potion): | ||
| 140 | return False | 140 | return False | ||
| 141 | 141 | ||||
| 142 | if len(self.effects) != len(other.effects): | 142 | if len(self.effects) != len(other.effects): | ||
| 143 | return False | 143 | return False | ||
| 144 | 144 | ||||
| 145 | for name in self.effects.keys(): | 145 | for name in self.effects.keys(): | ||
| 146 | if name not in other.effects: | 146 | if name not in other.effects: | ||
| 147 | return False | 147 | return False | ||
| 148 | if self.intensities.get(name) != other.intensities.get(name): | 148 | if self.intensities.get(name) != other.intensities.get(name): | ||
| n | n | 149 | if name in self.used_effects and name in other.used_effects: | ||
| 150 | continue | ||||
| 151 | if (name in self.used_effects and other.intensities.get(name) == 0 or | ||||
| 152 | name in other.used_effects and self.intensities.get(name) == 0): | ||||
| 153 | continue | ||||
| 149 | return False | 154 | return False | ||
| 150 | return True | 155 | return True | ||
| 151 | 156 | ||||
| 152 | def __lt__(self, other): | 157 | def __lt__(self, other): | ||
| 153 | validate(self) | 158 | validate(self) | ||
| 154 | validate(other) | 159 | validate(other) | ||
| 155 | 160 | ||||
| 156 | if not isinstance(other, Potion): | 161 | if not isinstance(other, Potion): | ||
| 157 | return False | 162 | return False | ||
| 158 | 163 | ||||
| 159 | first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects]) | 164 | first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects]) | ||
| 160 | second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects]) | 165 | second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects]) | ||
| 161 | return first_sum < second_sum | 166 | return first_sum < second_sum | ||
| 162 | 167 | ||||
| 163 | def __gt__(self, other): | 168 | def __gt__(self, other): | ||
| 164 | validate(self) | 169 | validate(self) | ||
| 165 | validate(other) | 170 | validate(other) | ||
| 166 | 171 | ||||
| 167 | if not isinstance(other, Potion): | 172 | if not isinstance(other, Potion): | ||
| 168 | return False | 173 | return False | ||
| 169 | 174 | ||||
| 170 | first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects]) | 175 | first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects]) | ||
| 171 | second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects]) | 176 | second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects]) | ||
| 172 | return first_sum > second_sum | 177 | return first_sum > second_sum | ||
| 173 | 178 | ||||
| 174 | def __hash__(self): | 179 | def __hash__(self): | ||
| 175 | return super().__hash__() | 180 | return super().__hash__() | ||
| 176 | 181 | ||||
| 177 | def _round_value(self, value): | 182 | def _round_value(self, value): | ||
| 178 | if value % 1 > 0.5: | 183 | if value % 1 > 0.5: | ||
| 179 | return int(math.ceil(value)) | 184 | return int(math.ceil(value)) | ||
| 180 | return int(math.floor(value)) | 185 | return int(math.floor(value)) | ||
| 181 | 186 | ||||
| 182 | def validate(potion): | 187 | def validate(potion): | ||
| 183 | if potion.depleted: | 188 | if potion.depleted: | ||
| 184 | raise TypeError("Potion is depleted.") | 189 | raise TypeError("Potion is depleted.") | ||
| 185 | if potion.used: | 190 | if potion.used: | ||
| 186 | raise TypeError("Potion is now part of something bigger than itself.") | 191 | raise TypeError("Potion is now part of something bigger than itself.") | ||
| n | n | 192 | |||
| 193 | def ascii_sum(string): | ||||
| 194 | return sum(ord(char) for char in string) | ||||
| 187 | 195 | ||||
| 188 | class ГоспожатаПоХимия: | 196 | class ГоспожатаПоХимия: | ||
| 189 | # { | 197 | # { | ||
| 190 | # target: { initial_state }, | 198 | # target: { initial_state }, | ||
| 191 | # target2: { initial_state } | 199 | # target2: { initial_state } | ||
| 192 | # } | 200 | # } | ||
| 193 | _target_states = {} | 201 | _target_states = {} | ||
| 194 | 202 | ||||
| 195 | # { | 203 | # { | ||
| 196 | # target: [potion1, potion2], | 204 | # target: [potion1, potion2], | ||
| 197 | # target2: [potion3] | 205 | # target2: [potion3] | ||
| 198 | # } | 206 | # } | ||
| 199 | _target_potions = {} | 207 | _target_potions = {} | ||
| 200 | 208 | ||||
| 201 | # { | 209 | # { | ||
| 202 | # target: { | 210 | # target: { | ||
| 203 | # potion1: time1, | 211 | # potion1: time1, | ||
| 204 | # potion2: time2 | 212 | # potion2: time2 | ||
| 205 | # }, | 213 | # }, | ||
| 206 | # target2: { | 214 | # target2: { | ||
| 207 | # potion3: time3 | 215 | # potion3: time3 | ||
| 208 | # } | 216 | # } | ||
| 209 | # } | 217 | # } | ||
| 210 | _times = {} | 218 | _times = {} | ||
| 211 | 219 | ||||
| 212 | def apply(self, target, potion): | 220 | def apply(self, target, potion): | ||
| 213 | validate(potion) | 221 | validate(potion) | ||
| 214 | 222 | ||||
| 215 | if target not in self._target_states: | 223 | if target not in self._target_states: | ||
| 216 | self.save_initial_state(target) | 224 | self.save_initial_state(target) | ||
| 217 | if target not in self._times.keys(): | 225 | if target not in self._times.keys(): | ||
| 218 | self._times[target] = {} | 226 | self._times[target] = {} | ||
| 219 | if target not in self._target_potions.keys(): | 227 | if target not in self._target_potions.keys(): | ||
| 220 | self._target_potions[target] = [] | 228 | self._target_potions[target] = [] | ||
| 221 | 229 | ||||
| 222 | self._times[target][potion] = potion.duration | 230 | self._times[target][potion] = potion.duration | ||
| 223 | self._target_potions[target].append(potion) | 231 | self._target_potions[target].append(potion) | ||
| n | 224 | sorted_effects = list(sorted(potion.effects)) | n | 232 | sorted_effects = sorted(list(potion.effects), key=ascii_sum, reverse=True) |
| 225 | for effect in sorted_effects: | 233 | for effect in sorted_effects: | ||
| 226 | try: | 234 | try: | ||
| 227 | getattr(potion, effect)(target) | 235 | getattr(potion, effect)(target) | ||
| 228 | except TypeError: | 236 | except TypeError: | ||
| 229 | continue | 237 | continue | ||
| n | n | 238 | potion.depleted = True | ||
| 239 | if potion.duration == 0: | ||||
| 240 | self.reset_target(target) | ||||
| 230 | 241 | ||||
| 231 | def _apply_all(self, target): | 242 | def _apply_all(self, target): | ||
| 232 | for potion in self._target_potions[target]: | 243 | for potion in self._target_potions[target]: | ||
| n | 233 | for effect in list(sorted(potion.effects)): | n | 244 | if potion.duration <= 0: |
| 245 | continue | ||||
| 246 | for effect in sorted(list(potion.effects), key=ascii_sum, reverse=True): | ||||
| 234 | potion.effects[effect](target) | 247 | potion.effects[effect](target) | ||
| 235 | 248 | ||||
| 236 | def tick(self): | 249 | def tick(self): | ||
| 237 | for target, potions in self._times.items(): | 250 | for target, potions in self._times.items(): | ||
| 238 | for potion, time in potions.items(): | 251 | for potion, time in potions.items(): | ||
| 239 | self._times[target][potion] = time - 1 | 252 | self._times[target][potion] = time - 1 | ||
| 240 | 253 | ||||
| 241 | for target, potions in (self._times.copy()).items(): | 254 | for target, potions in (self._times.copy()).items(): | ||
| 242 | for potion, time in (potions.copy()).items(): | 255 | for potion, time in (potions.copy()).items(): | ||
| n | 243 | if time == 0: | n | 256 | if time <= 0: |
| 244 | self._times[target].pop(potion, None) | 257 | self._times[target].pop(potion, None) | ||
| 245 | self._target_potions[target].remove(potion) | 258 | self._target_potions[target].remove(potion) | ||
| 246 | if len(self._times[target]) == 0: | 259 | if len(self._times[target]) == 0: | ||
| 247 | self._times.pop(target, None) | 260 | self._times.pop(target, None) | ||
| 248 | self.reset_target(target) | 261 | self.reset_target(target) | ||
| 249 | if target not in self._times: | 262 | if target not in self._times: | ||
| 250 | self._target_potions.pop(target, None) | 263 | self._target_potions.pop(target, None) | ||
| 251 | self._target_states.pop(target, None) | 264 | self._target_states.pop(target, None) | ||
| 252 | 265 | ||||
| 253 | def save_initial_state(self, target): | 266 | def save_initial_state(self, target): | ||
| 254 | self._target_states[target] = {attr: getattr(target, attr) for attr in dir(target) if not attr.startswith('_')} | 267 | self._target_states[target] = {attr: getattr(target, attr) for attr in dir(target) if not attr.startswith('_')} | ||
| 255 | 268 | ||||
| 256 | def reset_target(self, target): | 269 | def reset_target(self, target): | ||
| 257 | for attr, initial_value in self._target_states[target].items(): | 270 | for attr, initial_value in self._target_states[target].items(): | ||
| 258 | setattr(target, attr, initial_value) | 271 | setattr(target, attr, initial_value) | ||
| 259 | for attr in dir(target): | 272 | for attr in dir(target): | ||
| 260 | if not attr.startswith('_') and attr not in self._target_states[target].keys(): | 273 | if not attr.startswith('_') and attr not in self._target_states[target].keys(): | ||
| 261 | try: | 274 | try: | ||
| 262 | delattr(target, attr) | 275 | delattr(target, attr) | ||
| 263 | except AttributeError: | 276 | except AttributeError: | ||
| 264 | continue | 277 | continue | ||
| 265 | 278 | ||||
| 266 | self._apply_all(target) | 279 | self._apply_all(target) | ||
| t | 267 | t | |||
| 268 |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import math | f | 1 | import math |
| 2 | 2 | ||||
| 3 | class Potion: | 3 | class Potion: | ||
| 4 | def __init__(self, effects, duration): | 4 | def __init__(self, effects, duration): | ||
| 5 | self.effects = effects | 5 | self.effects = effects | ||
| 6 | self.duration = duration | 6 | self.duration = duration | ||
| 7 | self.intensities = {} | 7 | self.intensities = {} | ||
| 8 | self.used_effects = set() | 8 | self.used_effects = set() | ||
| 9 | self.used = False | 9 | self.used = False | ||
| 10 | self.depleted = False | 10 | self.depleted = False | ||
| 11 | 11 | ||||
| 12 | for name in effects.keys(): | 12 | for name in effects.keys(): | ||
| 13 | self.intensities[name] = self.intensities.get(name, 0) + 1 | 13 | self.intensities[name] = self.intensities.get(name, 0) + 1 | ||
| n | 14 | n | 14 | ||
| 15 | def __getattr__(self, name): | 15 | def __getattr__(self, name): | ||
| n | n | 16 | if name not in self.effects.keys(): | ||
| 17 | raise AttributeError("Attribute not found.") | ||||
| 16 | if self.used: | 18 | if self.used: | ||
| 17 | raise TypeError("Potion is now part of something bigger than itself.") | 19 | raise TypeError("Potion is now part of something bigger than itself.") | ||
| n | 18 | elif name in self.used_effects: | n | 20 | if name in self.used_effects: |
| 19 | raise TypeError("Effect is depleted.") | 21 | raise TypeError("Effect is depleted.") | ||
| n | 20 | elif name in self.effects.keys(): | n | 22 | |
| 21 | def execute_n_times(func): | 23 | def execute_n_times(func): | ||
| 22 | def wrapper(target): | 24 | def wrapper(target): | ||
| 23 | for _ in range(self.intensities.get(name)): | 25 | for _ in range(int(self.intensities.get(name))): | ||
| 24 | func(target) | 26 | func(target) | ||
| 25 | return wrapper | 27 | return wrapper | ||
| 26 | self.used_effects.add(name) | 28 | self.used_effects.add(name) | ||
| 27 | if len(self.used_effects) == len(self.effects): | 29 | if len(self.used_effects) == len(self.effects): | ||
| 28 | self.depleted = True | 30 | self.depleted = True | ||
| 29 | return execute_n_times(self.effects.get(name)) | 31 | return execute_n_times(self.effects.get(name)) | ||
| 30 | else: | 32 | |||
| 31 | raise AttributeError("Attribute not found") | ||||
| 32 | |||||
| 33 | def __add__(self, other): | 33 | def __add__(self, other): | ||
| n | 34 | if self.depleted: | n | 34 | validate(self) |
| 35 | raise TypeError("Potion is depleted.") | 35 | validate(other) | ||
| 36 | if self.used or other.used: | ||||
| 37 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
| 38 | 36 | ||||
| n | 39 | new_duration = other.duration if other.duration > self.duration else self.duration | n | 37 | new_duration = max(self.duration, other.duration) |
| 40 | combined_effects = {} | 38 | combined_effects = {} | ||
| 41 | intensities = {} | 39 | intensities = {} | ||
| 42 | used_effects = set() | 40 | used_effects = set() | ||
| 43 | 41 | ||||
| 44 | for name, usage in self.effects.items(): | 42 | for name, usage in self.effects.items(): | ||
| 45 | combined_effects[name] = usage | 43 | combined_effects[name] = usage | ||
| 46 | intensities[name] = intensities.get(name) + 1 if name in intensities else self.intensities.get(name, 0) | 44 | intensities[name] = intensities.get(name) + 1 if name in intensities else self.intensities.get(name, 0) | ||
| 47 | used_effects = used_effects.union(self.used_effects) | 45 | used_effects = used_effects.union(self.used_effects) | ||
| 48 | 46 | ||||
| 49 | for name, usage in other.effects.items(): | 47 | for name, usage in other.effects.items(): | ||
| 50 | combined_effects[name] = usage | 48 | combined_effects[name] = usage | ||
| 51 | intensities[name] = intensities.get(name) + 1 if name in intensities else other.intensities.get(name, 0) | 49 | intensities[name] = intensities.get(name) + 1 if name in intensities else other.intensities.get(name, 0) | ||
| n | 52 | used_effects = used_effects.union(self.used_effects) | n | 50 | used_effects = used_effects.union(other.used_effects) |
| 53 | 51 | ||||
| 54 | self.used = True | 52 | self.used = True | ||
| 55 | other.used = True | 53 | other.used = True | ||
| 56 | potion = Potion(combined_effects, new_duration) | 54 | potion = Potion(combined_effects, new_duration) | ||
| 57 | potion.intensities = intensities | 55 | potion.intensities = intensities | ||
| 58 | potion.used_effects = used_effects | 56 | potion.used_effects = used_effects | ||
| 59 | if len(potion.used_effects) == len(potion.effects): | 57 | if len(potion.used_effects) == len(potion.effects): | ||
| n | n | 58 | potion.depleted = True | ||
| 59 | return potion | ||||
| 60 | |||||
| 61 | def __mul__(self, other): | ||||
| 62 | validate(self) | ||||
| 63 | |||||
| 64 | if isinstance(other, (int, float)): | ||||
| 65 | potion = Potion(self.effects.copy(), self.duration) | ||||
| 66 | intensities = {} | ||||
| 67 | |||||
| 68 | for name, value in self.intensities.items(): | ||||
| 69 | intensities[name] = value * other | ||||
| 70 | if 0 < other < 1: | ||||
| 71 | intensities[name] = self._round_value(intensities[name]) | ||||
| 72 | |||||
| 73 | potion.intensities = intensities | ||||
| 74 | potion.used_effects = self.used_effects.copy() | ||||
| 75 | if len(potion.used_effects) == len(potion.effects): | ||||
| 60 | potion.depleted = True | 76 | potion.depleted = True | ||
| n | 61 | return potion | n | ||
| 62 | |||||
| 63 | def __mul__(self, other): | ||||
| 64 | if self.depleted: | ||||
| 65 | raise TypeError("Potion is depleted.") | ||||
| 66 | if self.used: | ||||
| 67 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
| 68 | |||||
| 69 | potion = Potion(self.effects, self.duration) | ||||
| 70 | intensities = {} | ||||
| 71 | |||||
| 72 | if isinstance(other, (int, float)): | ||||
| 73 | for name, value in self.intensities.items(): | ||||
| 74 | intensities[name] = value * other | ||||
| 75 | if other > 0 and other < 1: | ||||
| 76 | if intensities[name] % 1 > 0.5: | ||||
| 77 | intensities[name]= int(math.ceil(intensities[name])) | ||||
| 78 | else: | ||||
| 79 | intensities[name] = int(math.floor(intensities[name])) | ||||
| 80 | |||||
| 81 | potion.intensities = intensities | ||||
| 82 | potion.used_effects = self.used_effects.copy() | ||||
| 83 | if len(potion.used_effects) == len(potion.effects): | ||||
| 84 | potion.depleted = True | ||||
| 85 | self.used = True | 77 | self.used = True | ||
| 86 | return potion | 78 | return potion | ||
| 87 | 79 | ||||
| 88 | def __sub__(self, other): | 80 | def __sub__(self, other): | ||
| n | 89 | if self.depleted: | n | 81 | validate(self) |
| 90 | raise TypeError("Potion is depleted.") | 82 | validate(other) | ||
| 91 | if self.used or other.used: | ||||
| 92 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
| 93 | 83 | ||||
| 94 | new_duration = other.duration | 84 | new_duration = other.duration | ||
| n | 95 | combined_effects = {} | n | 85 | purified_effects = {} |
| 96 | intensities = {} | 86 | intensities = {} | ||
| 97 | used_effects = set() | 87 | used_effects = set() | ||
| 98 | 88 | ||||
| 99 | for name, usage in other.effects.items(): | 89 | for name, usage in other.effects.items(): | ||
| 100 | if name not in self.effects: | 90 | if name not in self.effects: | ||
| n | 101 | raise TypeError("Cannot subtract") | n | 91 | raise TypeError("Cannot purify potion.") |
| 102 | if other.intensities.get(name) >= self.intensities.get(name): | 92 | if other.intensities.get(name) >= self.intensities.get(name): | ||
| 103 | continue | 93 | continue | ||
| 104 | else: | 94 | else: | ||
| n | 105 | combined_effects[name] = usage | n | 95 | purified_effects[name] = usage |
| 106 | intensities[name] = self.intensities.get(name) - other.intensities.get(name) | 96 | intensities[name] = self.intensities.get(name) - other.intensities.get(name) | ||
| n | 107 | used_effects = used_effects.union(other.used_effects) | n | 97 | if name in other.used_effects: |
| 98 | used_effects.add(name) | ||||
| 108 | 99 | ||||
| 109 | for name, usage in self.effects.items(): | 100 | for name, usage in self.effects.items(): | ||
| 110 | if name not in other.effects.keys(): | 101 | if name not in other.effects.keys(): | ||
| n | 111 | combined_effects[name] = usage | n | 102 | purified_effects[name] = usage |
| 112 | intensities[name] = self.intensities.get(name) | 103 | intensities[name] = self.intensities.get(name) | ||
| n | 113 | used_effects = used_effects.union(self.used_effects) | n | 104 | if name in self.used_effects: |
| 105 | used_effects.add(name) | ||||
| 114 | 106 | ||||
| 115 | self.used = True | 107 | self.used = True | ||
| 116 | other.used = True | 108 | other.used = True | ||
| n | 117 | potion = Potion(combined_effects, new_duration) | n | 109 | potion = Potion(purified_effects, new_duration) |
| 118 | potion.intensities = intensities | 110 | potion.intensities = intensities | ||
| 119 | potion.used_effects = used_effects | 111 | potion.used_effects = used_effects | ||
| 120 | if len(potion.used_effects) == len(potion.effects): | 112 | if len(potion.used_effects) == len(potion.effects): | ||
| 121 | potion.depleted = True | 113 | potion.depleted = True | ||
| 122 | return potion | 114 | return potion | ||
| n | 123 | n | 115 | ||
| 124 | def __truediv__(self, other): | 116 | def __truediv__(self, other): | ||
| n | 125 | if self.depleted: | n | 117 | validate(self) |
| 126 | raise TypeError("Potion is depleted.") | ||||
| 127 | if self.used: | ||||
| 128 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
| 129 | 118 | ||||
| 130 | if isinstance(other, (int, float)): | 119 | if isinstance(other, (int, float)): | ||
| 131 | intensities = {} | 120 | intensities = {} | ||
| 132 | 121 | ||||
| 133 | for name, intensity in self.intensities.items(): | 122 | for name, intensity in self.intensities.items(): | ||
| n | 134 | new_intensity = intensity / other | n | ||
| 135 | if other > 0 and other < 1: | ||||
| 136 | if new_intensity % 1 > 0.5: | ||||
| 137 | new_intensity = math.ceil(new_intensity) | ||||
| 138 | else: | ||||
| 139 | new_intensity = math.floor(new_intensity) | ||||
| 140 | intensities[name] = int(new_intensity) | 123 | intensities[name] = self._round_value(intensity / other) | ||
| 141 | 124 | ||||
| 142 | result = tuple(Potion(self.effects.copy(), self.duration) for _ in range(other)) | 125 | result = tuple(Potion(self.effects.copy(), self.duration) for _ in range(other)) | ||
| 143 | for potion in result: | 126 | for potion in result: | ||
| 144 | potion.intensities = intensities.copy() | 127 | potion.intensities = intensities.copy() | ||
| 145 | potion.used_effects = self.used_effects.copy() | 128 | potion.used_effects = self.used_effects.copy() | ||
| 146 | if len(potion.used_effects) == len(potion.effects): | 129 | if len(potion.used_effects) == len(potion.effects): | ||
| 147 | potion.depleted = True | 130 | potion.depleted = True | ||
| n | n | 131 | self.used = True | ||
| 148 | return result | 132 | return result | ||
| 149 | 133 | ||||
| 150 | 134 | ||||
| 151 | def __eq__(self, other): | 135 | def __eq__(self, other): | ||
| n | n | 136 | validate(self) | ||
| 137 | validate(other) | ||||
| 138 | |||||
| 152 | if not isinstance(other, Potion): | 139 | if not isinstance(other, Potion): | ||
| 153 | return False | 140 | return False | ||
| 154 | 141 | ||||
| 155 | if len(self.effects) != len(other.effects): | 142 | if len(self.effects) != len(other.effects): | ||
| 156 | return False | 143 | return False | ||
| 157 | 144 | ||||
| 158 | for name in self.effects.keys(): | 145 | for name in self.effects.keys(): | ||
| 159 | if name not in other.effects: | 146 | if name not in other.effects: | ||
| 160 | return False | 147 | return False | ||
| 161 | if self.intensities.get(name) != other.intensities.get(name): | 148 | if self.intensities.get(name) != other.intensities.get(name): | ||
| 162 | return False | 149 | return False | ||
| 163 | return True | 150 | return True | ||
| 164 | 151 | ||||
| 165 | def __lt__(self, other): | 152 | def __lt__(self, other): | ||
| n | n | 153 | validate(self) | ||
| 154 | validate(other) | ||||
| 155 | |||||
| 156 | if not isinstance(other, Potion): | ||||
| 157 | return False | ||||
| 158 | |||||
| 166 | first_sum = sum([intensity for intensity in self.intensities.values()]) | 159 | first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects]) | ||
| 167 | second_sum = sum([intensity for intensity in other.intensities.values()]) | 160 | second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects]) | ||
| 168 | return first_sum < second_sum | 161 | return first_sum < second_sum | ||
| 169 | 162 | ||||
| 170 | def __gt__(self, other): | 163 | def __gt__(self, other): | ||
| n | n | 164 | validate(self) | ||
| 165 | validate(other) | ||||
| 166 | |||||
| 167 | if not isinstance(other, Potion): | ||||
| 168 | return False | ||||
| 169 | |||||
| 171 | first_sum = sum([intensity for intensity in self.intensities.values()]) | 170 | first_sum = sum([intensity for name, intensity in self.intensities.items() if name not in self.used_effects]) | ||
| 172 | second_sum = sum([intensity for intensity in other.intensities.values()]) | 171 | second_sum = sum([intensity for name, intensity in other.intensities.items() if name not in other.used_effects]) | ||
| 173 | return first_sum > second_sum | 172 | return first_sum > second_sum | ||
| 174 | 173 | ||||
| 175 | def __hash__(self): | 174 | def __hash__(self): | ||
| 176 | return super().__hash__() | 175 | return super().__hash__() | ||
| n | n | 176 | |||
| 177 | def _round_value(self, value): | ||||
| 178 | if value % 1 > 0.5: | ||||
| 179 | return int(math.ceil(value)) | ||||
| 180 | return int(math.floor(value)) | ||||
| 177 | 181 | ||||
| n | n | 182 | def validate(potion): | ||
| 183 | if potion.depleted: | ||||
| 184 | raise TypeError("Potion is depleted.") | ||||
| 185 | if potion.used: | ||||
| 186 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
| 178 | 187 | ||||
| 179 | class ГоспожатаПоХимия: | 188 | class ГоспожатаПоХимия: | ||
| 180 | # { | 189 | # { | ||
| 181 | # target: { initial_state }, | 190 | # target: { initial_state }, | ||
| 182 | # target2: { initial_state } | 191 | # target2: { initial_state } | ||
| 183 | # } | 192 | # } | ||
| 184 | _target_states = {} | 193 | _target_states = {} | ||
| 185 | 194 | ||||
| 186 | # { | 195 | # { | ||
| 187 | # target: [potion1, potion2], | 196 | # target: [potion1, potion2], | ||
| 188 | # target2: [potion3] | 197 | # target2: [potion3] | ||
| 189 | # } | 198 | # } | ||
| 190 | _target_potions = {} | 199 | _target_potions = {} | ||
| 191 | 200 | ||||
| 192 | # { | 201 | # { | ||
| 193 | # target: { | 202 | # target: { | ||
| 194 | # potion1: time1, | 203 | # potion1: time1, | ||
| 195 | # potion2: time2 | 204 | # potion2: time2 | ||
| 196 | # }, | 205 | # }, | ||
| 197 | # target2: { | 206 | # target2: { | ||
| 198 | # potion3: time3 | 207 | # potion3: time3 | ||
| 199 | # } | 208 | # } | ||
| 200 | # } | 209 | # } | ||
| 201 | _times = {} | 210 | _times = {} | ||
| 202 | 211 | ||||
| 203 | def apply(self, target, potion): | 212 | def apply(self, target, potion): | ||
| n | 204 | if potion.depleted: | n | 213 | validate(potion) |
| 205 | raise TypeError("Potion is depleted.") | ||||
| 206 | 214 | ||||
| 207 | if target not in self._target_states: | 215 | if target not in self._target_states: | ||
| 208 | self.save_initial_state(target) | 216 | self.save_initial_state(target) | ||
| 209 | if target not in self._times.keys(): | 217 | if target not in self._times.keys(): | ||
| 210 | self._times[target] = {} | 218 | self._times[target] = {} | ||
| 211 | if target not in self._target_potions.keys(): | 219 | if target not in self._target_potions.keys(): | ||
| 212 | self._target_potions[target] = [] | 220 | self._target_potions[target] = [] | ||
| 213 | 221 | ||||
| 214 | self._times[target][potion] = potion.duration | 222 | self._times[target][potion] = potion.duration | ||
| 215 | self._target_potions[target].append(potion) | 223 | self._target_potions[target].append(potion) | ||
| 216 | sorted_effects = list(sorted(potion.effects)) | 224 | sorted_effects = list(sorted(potion.effects)) | ||
| 217 | for effect in sorted_effects: | 225 | for effect in sorted_effects: | ||
| 218 | try: | 226 | try: | ||
| 219 | getattr(potion, effect)(target) | 227 | getattr(potion, effect)(target) | ||
| 220 | except TypeError: | 228 | except TypeError: | ||
| n | 221 | pass | n | 229 | continue |
| 222 | 230 | ||||
| 223 | def _apply_all(self, target): | 231 | def _apply_all(self, target): | ||
| 224 | for potion in self._target_potions[target]: | 232 | for potion in self._target_potions[target]: | ||
| 225 | for effect in list(sorted(potion.effects)): | 233 | for effect in list(sorted(potion.effects)): | ||
| n | 226 | potion.effects[effect](target) | n | 234 | potion.effects[effect](target) |
| 227 | 235 | ||||
| 228 | def tick(self): | 236 | def tick(self): | ||
| 229 | for target, potions in self._times.items(): | 237 | for target, potions in self._times.items(): | ||
| 230 | for potion, time in potions.items(): | 238 | for potion, time in potions.items(): | ||
| 231 | self._times[target][potion] = time - 1 | 239 | self._times[target][potion] = time - 1 | ||
| 232 | 240 | ||||
| 233 | for target, potions in (self._times.copy()).items(): | 241 | for target, potions in (self._times.copy()).items(): | ||
| 234 | for potion, time in (potions.copy()).items(): | 242 | for potion, time in (potions.copy()).items(): | ||
| 235 | if time == 0: | 243 | if time == 0: | ||
| 236 | self._times[target].pop(potion, None) | 244 | self._times[target].pop(potion, None) | ||
| 237 | self._target_potions[target].remove(potion) | 245 | self._target_potions[target].remove(potion) | ||
| 238 | if len(self._times[target]) == 0: | 246 | if len(self._times[target]) == 0: | ||
| 239 | self._times.pop(target, None) | 247 | self._times.pop(target, None) | ||
| 240 | self.reset_target(target) | 248 | self.reset_target(target) | ||
| 241 | if target not in self._times: | 249 | if target not in self._times: | ||
| 242 | self._target_potions.pop(target, None) | 250 | self._target_potions.pop(target, None) | ||
| n | 243 | n | 251 | self._target_states.pop(target, None) | |
| 244 | 252 | ||||
| 245 | def save_initial_state(self, target): | 253 | def save_initial_state(self, target): | ||
| 246 | self._target_states[target] = {attr: getattr(target, attr) for attr in dir(target) if not attr.startswith('_')} | 254 | self._target_states[target] = {attr: getattr(target, attr) for attr in dir(target) if not attr.startswith('_')} | ||
| 247 | 255 | ||||
| 248 | def reset_target(self, target): | 256 | def reset_target(self, target): | ||
| 249 | for attr, initial_value in self._target_states[target].items(): | 257 | for attr, initial_value in self._target_states[target].items(): | ||
| 250 | setattr(target, attr, initial_value) | 258 | setattr(target, attr, initial_value) | ||
| n | n | 259 | for attr in dir(target): | ||
| 260 | if not attr.startswith('_') and attr not in self._target_states[target].keys(): | ||||
| 261 | try: | ||||
| 262 | delattr(target, attr) | ||||
| 263 | except AttributeError: | ||||
| 264 | continue | ||||
| 265 | |||||
| 251 | self._apply_all(target) | 266 | self._apply_all(target) | ||
| 252 | 267 | ||||
| t | t | 268 |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||