1import math
2import re
3from copy import deepcopy
4
5
6class Potion:
7 def __init__(self, effects, duration):
8 self._effects = effects
9 self._duration = duration
10 self._intensities = {key: 1 for key in effects}
11 self._depleted_effects = set()
12 self._has_been_used = False
13 self._has_been_applied = False
14
15 def __getattribute__(self, item):
16 if object.__getattribute__(self, '_has_been_applied'):
17 raise TypeError('Potion is depleted.')
18 if object.__getattribute__(self, '_has_been_used'):
19 raise TypeError('Potion is now part of something bigger than itself.')
20
21 return object.__getattribute__(self, item)
22
23 def __getattr__(self, item):
24 if self._has_been_applied:
25 raise TypeError('Potion is depleted.')
26
27 if item not in self._effects:
28 raise AttributeError('No such effect.')
29
30 if item in self._depleted_effects:
31 raise TypeError('Effect is depleted.')
32
33 effect = self._intensify_effect(self._intensities[item])(self._effects[item])
34
35 self._depleted_effects.add(item)
36
37 return effect
38
39 @staticmethod
40 def _intensify_effect(times):
41 def intensifying_decorator(function):
42 def intensifying_wrapper(*args, **kwargs):
43 for _ in range(times):
44 function(*args, **kwargs)
45
46 return intensifying_wrapper
47
48 return intensifying_decorator
49
50 @property
51 def has_been_used(self):
52 return self._has_been_used
53
54 @has_been_used.setter
55 def has_been_used(self, value):
56 self._has_been_used = value
57
58 @property
59 def has_been_applied(self):
60 return self._has_been_applied
61
62 @has_been_applied.setter
63 def has_been_applied(self, value):
64 self._has_been_applied = value
65
66 @property
67 def duration(self):
68 return self._duration
69
70 @duration.setter
71 def duration(self, value):
72 self._duration = value
73
74 @property
75 def intensities(self):
76 return self._intensities
77
78 @intensities.setter
79 def intensities(self, value):
80 self._intensities = value
81
82 @property
83 def effects(self):
84 return self._effects
85
86 @effects.setter
87 def effects(self, value):
88 self._effects = value
89
90 def __add__(self, other):
91 new_effects = self._combine_effects(other)
92 new_intensities = self._combine_intensities(other)
93
94 new_potion = Potion(new_effects, max(self._duration, other.duration))
95 new_potion._intensities = new_intensities
96
97 self.has_been_used = True
98 other.has_been_used = True
99
100 return new_potion
101
102 def _combine_effects(self, other):
103 new_effects = {}
104
105 for key, value in self.effects.items():
106 new_effects[key] = value
107
108 for key, value in other.effects.items():
109 new_effects[key] = value
110
111 return new_effects
112
113 def _combine_intensities(self, other):
114 new_intensities = {}
115
116 for key, value in self._intensities.items():
117 new_intensities[key] = value
118
119 for key, value in other.intensities.items():
120 if key in new_intensities:
121 new_intensities[key] += value
122 else:
123 new_intensities[key] = value
124
125 return new_intensities
126
127 def __mul__(self, other):
128 updated_intensities = {}
129
130 if isinstance(other, int):
131 updated_intensities = {key: value * other for key, value in self._intensities.items()}
132 elif isinstance(other, float) and 0 <= other <= 1:
133 updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()}
134
135 new_potion = Potion(self._effects, self._duration)
136 new_potion._intensities = updated_intensities
137
138 self.has_been_used = True
139
140 return new_potion
141
142 @staticmethod
143 def _round_to_whole(real):
144 fraction = real - math.floor(real)
145
146 return math.floor(real) if fraction <= 0.5 else math.ceil(real)
147
148 def __sub__(self, other):
149 if set(other.effects.keys()) - set(self._effects.keys()):
150 raise TypeError('съдържанието няма значение')
151
152 new_effects = {}
153 new_intensities = {}
154
155 for name, intensity in self._intensities.items():
156 if name not in other.intensities:
157 new_effects[name] = self._effects[name]
158 new_intensities[name] = intensity
159 else:
160 difference = intensity - other.intensities[name]
161 if difference > 0:
162 new_effects[name] = self._effects[name]
163 new_intensities[name] = difference
164
165 new_potion = Potion(new_effects, self._duration)
166 new_potion._intensities = new_intensities
167
168 self.has_been_used = True
169 other.has_been_used = True
170
171 return new_potion
172
173 def __truediv__(self, other):
174 updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()}
175
176 new_potion = Potion(self._effects, self._duration)
177 new_potion._intensities = updated_intensities
178
179 self.has_been_used = True
180
181 return tuple(deepcopy(new_potion) for _ in range(other))
182
183 # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation
184 def __deepcopy__(self, memodict={}):
185 cls = self.__class__
186 new_object = cls.__new__(cls)
187 memodict[id(self)] = new_object
188 for key, value in self.__dict__.items():
189 setattr(new_object, key, deepcopy(value, memodict))
190 return new_object
191
192 def __eq__(self, other):
193 return self._effects == other.effects and self.get_comparable_effects() == other.get_comparable_effects()
194
195 def __gt__(self, other):
196 return sum(self.get_comparable_effects().values()) > sum(other.get_comparable_effects().values()) and not self.__eq__(other)
197
198 def __lt__(self, other):
199 return sum(self.get_comparable_effects().values()) < sum(other.get_comparable_effects().values()) and not self.__eq__(other)
200
201 def get_comparable_effects(self):
202 return {effect: intensity for effect, intensity in self._intensities.items() if effect not in self._depleted_effects}
203
204 def get_applied(self, target):
205 effects_map, masses = self._ordered_by_mass()
206
207 for mass in masses:
208 name = effects_map[mass]
209 effect = getattr(self, name)
210 effect(target)
211
212 self.has_been_applied = True
213
214 def _ordered_by_mass(self):
215 effects_map = {self._get_mass(key): key for key in self._effects}
216 masses = list(effects_map.keys())
217 masses.sort(reverse=True)
218
219 return effects_map, masses
220
221 @staticmethod
222 def _get_mass(effect_name):
223 return sum(map(ord, effect_name))
224
225 # Generated by IDE
226 def __hash__(self):
227 return super().__hash__()
228
229
230class ГоспожатаПоХимия:
231 def __init__(self):
232 self._durations = {}
233 self._states = {}
234 self._potions_on_targets = {}
235 self._original_potions = {}
236
237 def apply(self, target, potion):
238 self._durations[potion] = potion.duration
239
240 if target in self._potions_on_targets.values():
241 for key, value in self._potions_on_targets.items():
242 if value == target:
243 self._states[potion] = self._states[key]
244 break
245 else:
246 states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target))
247 self._states[potion] = {name: getattr(target, name) for name in states_names}
248
249 self._potions_on_targets[potion] = target
250 self._original_potions[potion] = deepcopy(potion)
251
252 potion.get_applied(target)
253
254 def tick(self):
255 for potion in self._durations:
256 self._durations[potion] -= 1
257
258 expired_potions = [key for key, value in self._durations.items() if value == 0]
259
260 used_targets = []
261 for potion in expired_potions:
262 for attribute, value in self._states[potion].items():
263 setattr(self._potions_on_targets[potion], attribute, value)
264
265 used_targets.append(self._potions_on_targets[potion])
266
267 del self._durations[potion]
268 del self._potions_on_targets[potion]
269 del self._states[potion]
270 del self._original_potions[potion]
271
272 for used_target in used_targets:
273 for potion, target in self._potions_on_targets.items():
274 if used_target == target:
275 self._original_potions[potion].get_applied(target)
...............E...F
======================================================================
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 252, in apply
potion.get_applied(target)
File "/tmp/solution.py", line 209, in get_applied
effect = getattr(self, name)
File "/tmp/solution.py", line 31, in __getattr__
raise TypeError('Effect is depleted.')
TypeError: Effect is depleted.
======================================================================
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.003s
FAILED (failures=1, errors=1)
Виктор Бечев
04.12.2023 19:23Дано. :grin:
|
Атанас Ников
04.12.2023 19:03Фикснах няколко дреболии, дано не съм счупил нещо meanwhile :DD
|
Виктор Бечев
04.12.2023 14:56Чудесно написан код, методите са малки (почти няма над 15 реда, а там където има в общия случай не си заслужава разбиване на две), с добре дефинирани отговорности, само тоя статичен `_apply` ми изглежда излишен, бивайки един ред...
|
| f | 1 | import math | f | 1 | import math |
| 2 | import re | 2 | import re | ||
| 3 | from copy import deepcopy | 3 | from copy import deepcopy | ||
| 4 | 4 | ||||
| 5 | 5 | ||||
| 6 | class Potion: | 6 | class Potion: | ||
| 7 | def __init__(self, effects, duration): | 7 | def __init__(self, effects, duration): | ||
| 8 | self._effects = effects | 8 | self._effects = effects | ||
| 9 | self._duration = duration | 9 | self._duration = duration | ||
| 10 | self._intensities = {key: 1 for key in effects} | 10 | self._intensities = {key: 1 for key in effects} | ||
| 11 | self._depleted_effects = set() | 11 | self._depleted_effects = set() | ||
| 12 | self._has_been_used = False | 12 | self._has_been_used = False | ||
| 13 | self._has_been_applied = False | 13 | self._has_been_applied = False | ||
| 14 | 14 | ||||
| 15 | def __getattribute__(self, item): | 15 | def __getattribute__(self, item): | ||
| 16 | if object.__getattribute__(self, '_has_been_applied'): | 16 | if object.__getattribute__(self, '_has_been_applied'): | ||
| n | 17 | raise TypeError('Potion is depleted') | n | 17 | raise TypeError('Potion is depleted.') |
| 18 | if object.__getattribute__(self, '_has_been_used'): | 18 | if object.__getattribute__(self, '_has_been_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.') | ||
| 20 | 20 | ||||
| 21 | return object.__getattribute__(self, item) | 21 | return object.__getattribute__(self, item) | ||
| 22 | 22 | ||||
| 23 | def __getattr__(self, item): | 23 | def __getattr__(self, item): | ||
| 24 | if self._has_been_applied: | 24 | if self._has_been_applied: | ||
| n | 25 | raise TypeError('Potion is depleted') | n | 25 | raise TypeError('Potion is depleted.') |
| 26 | 26 | ||||
| 27 | if item not in self._effects: | 27 | if item not in self._effects: | ||
| n | 28 | raise AttributeError('No such effect') | n | 28 | raise AttributeError('No such effect.') |
| 29 | 29 | ||||
| 30 | if item in self._depleted_effects: | 30 | if item in self._depleted_effects: | ||
| t | 31 | raise TypeError('Effect is depleted') | t | 31 | raise TypeError('Effect is depleted.') |
| 32 | 32 | ||||
| 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | ||
| 34 | 34 | ||||
| 35 | self._depleted_effects.add(item) | 35 | self._depleted_effects.add(item) | ||
| 36 | 36 | ||||
| 37 | return effect | 37 | return effect | ||
| 38 | 38 | ||||
| 39 | @staticmethod | 39 | @staticmethod | ||
| 40 | def _intensify_effect(times): | 40 | def _intensify_effect(times): | ||
| 41 | def intensifying_decorator(function): | 41 | def intensifying_decorator(function): | ||
| 42 | def intensifying_wrapper(*args, **kwargs): | 42 | def intensifying_wrapper(*args, **kwargs): | ||
| 43 | for _ in range(times): | 43 | for _ in range(times): | ||
| 44 | function(*args, **kwargs) | 44 | function(*args, **kwargs) | ||
| 45 | 45 | ||||
| 46 | return intensifying_wrapper | 46 | return intensifying_wrapper | ||
| 47 | 47 | ||||
| 48 | return intensifying_decorator | 48 | return intensifying_decorator | ||
| 49 | 49 | ||||
| 50 | @property | 50 | @property | ||
| 51 | def has_been_used(self): | 51 | def has_been_used(self): | ||
| 52 | return self._has_been_used | 52 | return self._has_been_used | ||
| 53 | 53 | ||||
| 54 | @has_been_used.setter | 54 | @has_been_used.setter | ||
| 55 | def has_been_used(self, value): | 55 | def has_been_used(self, value): | ||
| 56 | self._has_been_used = value | 56 | self._has_been_used = value | ||
| 57 | 57 | ||||
| 58 | @property | 58 | @property | ||
| 59 | def has_been_applied(self): | 59 | def has_been_applied(self): | ||
| 60 | return self._has_been_applied | 60 | return self._has_been_applied | ||
| 61 | 61 | ||||
| 62 | @has_been_applied.setter | 62 | @has_been_applied.setter | ||
| 63 | def has_been_applied(self, value): | 63 | def has_been_applied(self, value): | ||
| 64 | self._has_been_applied = value | 64 | self._has_been_applied = value | ||
| 65 | 65 | ||||
| 66 | @property | 66 | @property | ||
| 67 | def duration(self): | 67 | def duration(self): | ||
| 68 | return self._duration | 68 | return self._duration | ||
| 69 | 69 | ||||
| 70 | @duration.setter | 70 | @duration.setter | ||
| 71 | def duration(self, value): | 71 | def duration(self, value): | ||
| 72 | self._duration = value | 72 | self._duration = value | ||
| 73 | 73 | ||||
| 74 | @property | 74 | @property | ||
| 75 | def intensities(self): | 75 | def intensities(self): | ||
| 76 | return self._intensities | 76 | return self._intensities | ||
| 77 | 77 | ||||
| 78 | @intensities.setter | 78 | @intensities.setter | ||
| 79 | def intensities(self, value): | 79 | def intensities(self, value): | ||
| 80 | self._intensities = value | 80 | self._intensities = value | ||
| 81 | 81 | ||||
| 82 | @property | 82 | @property | ||
| 83 | def effects(self): | 83 | def effects(self): | ||
| 84 | return self._effects | 84 | return self._effects | ||
| 85 | 85 | ||||
| 86 | @effects.setter | 86 | @effects.setter | ||
| 87 | def effects(self, value): | 87 | def effects(self, value): | ||
| 88 | self._effects = value | 88 | self._effects = value | ||
| 89 | 89 | ||||
| 90 | def __add__(self, other): | 90 | def __add__(self, other): | ||
| 91 | new_effects = self._combine_effects(other) | 91 | new_effects = self._combine_effects(other) | ||
| 92 | new_intensities = self._combine_intensities(other) | 92 | new_intensities = self._combine_intensities(other) | ||
| 93 | 93 | ||||
| 94 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | 94 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | ||
| 95 | new_potion._intensities = new_intensities | 95 | new_potion._intensities = new_intensities | ||
| 96 | 96 | ||||
| 97 | self.has_been_used = True | 97 | self.has_been_used = True | ||
| 98 | other.has_been_used = True | 98 | other.has_been_used = True | ||
| 99 | 99 | ||||
| 100 | return new_potion | 100 | return new_potion | ||
| 101 | 101 | ||||
| 102 | def _combine_effects(self, other): | 102 | def _combine_effects(self, other): | ||
| 103 | new_effects = {} | 103 | new_effects = {} | ||
| 104 | 104 | ||||
| 105 | for key, value in self.effects.items(): | 105 | for key, value in self.effects.items(): | ||
| 106 | new_effects[key] = value | 106 | new_effects[key] = value | ||
| 107 | 107 | ||||
| 108 | for key, value in other.effects.items(): | 108 | for key, value in other.effects.items(): | ||
| 109 | new_effects[key] = value | 109 | new_effects[key] = value | ||
| 110 | 110 | ||||
| 111 | return new_effects | 111 | return new_effects | ||
| 112 | 112 | ||||
| 113 | def _combine_intensities(self, other): | 113 | def _combine_intensities(self, other): | ||
| 114 | new_intensities = {} | 114 | new_intensities = {} | ||
| 115 | 115 | ||||
| 116 | for key, value in self._intensities.items(): | 116 | for key, value in self._intensities.items(): | ||
| 117 | new_intensities[key] = value | 117 | new_intensities[key] = value | ||
| 118 | 118 | ||||
| 119 | for key, value in other.intensities.items(): | 119 | for key, value in other.intensities.items(): | ||
| 120 | if key in new_intensities: | 120 | if key in new_intensities: | ||
| 121 | new_intensities[key] += value | 121 | new_intensities[key] += value | ||
| 122 | else: | 122 | else: | ||
| 123 | new_intensities[key] = value | 123 | new_intensities[key] = value | ||
| 124 | 124 | ||||
| 125 | return new_intensities | 125 | return new_intensities | ||
| 126 | 126 | ||||
| 127 | def __mul__(self, other): | 127 | def __mul__(self, other): | ||
| 128 | updated_intensities = {} | 128 | updated_intensities = {} | ||
| 129 | 129 | ||||
| 130 | if isinstance(other, int): | 130 | if isinstance(other, int): | ||
| 131 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | 131 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | ||
| 132 | elif isinstance(other, float) and 0 <= other <= 1: | 132 | elif isinstance(other, float) and 0 <= other <= 1: | ||
| 133 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | 133 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | ||
| 134 | 134 | ||||
| 135 | new_potion = Potion(self._effects, self._duration) | 135 | new_potion = Potion(self._effects, self._duration) | ||
| 136 | new_potion._intensities = updated_intensities | 136 | new_potion._intensities = updated_intensities | ||
| 137 | 137 | ||||
| 138 | self.has_been_used = True | 138 | self.has_been_used = True | ||
| 139 | 139 | ||||
| 140 | return new_potion | 140 | return new_potion | ||
| 141 | 141 | ||||
| 142 | @staticmethod | 142 | @staticmethod | ||
| 143 | def _round_to_whole(real): | 143 | def _round_to_whole(real): | ||
| 144 | fraction = real - math.floor(real) | 144 | fraction = real - math.floor(real) | ||
| 145 | 145 | ||||
| 146 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | 146 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | ||
| 147 | 147 | ||||
| 148 | def __sub__(self, other): | 148 | def __sub__(self, other): | ||
| 149 | if set(other.effects.keys()) - set(self._effects.keys()): | 149 | if set(other.effects.keys()) - set(self._effects.keys()): | ||
| 150 | raise TypeError('съдържанието няма значение') | 150 | raise TypeError('съдържанието няма значение') | ||
| 151 | 151 | ||||
| 152 | new_effects = {} | 152 | new_effects = {} | ||
| 153 | new_intensities = {} | 153 | new_intensities = {} | ||
| 154 | 154 | ||||
| 155 | for name, intensity in self._intensities.items(): | 155 | for name, intensity in self._intensities.items(): | ||
| 156 | if name not in other.intensities: | 156 | if name not in other.intensities: | ||
| 157 | new_effects[name] = self._effects[name] | 157 | new_effects[name] = self._effects[name] | ||
| 158 | new_intensities[name] = intensity | 158 | new_intensities[name] = intensity | ||
| 159 | else: | 159 | else: | ||
| 160 | difference = intensity - other.intensities[name] | 160 | difference = intensity - other.intensities[name] | ||
| 161 | if difference > 0: | 161 | if difference > 0: | ||
| 162 | new_effects[name] = self._effects[name] | 162 | new_effects[name] = self._effects[name] | ||
| 163 | new_intensities[name] = difference | 163 | new_intensities[name] = difference | ||
| 164 | 164 | ||||
| 165 | new_potion = Potion(new_effects, self._duration) | 165 | new_potion = Potion(new_effects, self._duration) | ||
| 166 | new_potion._intensities = new_intensities | 166 | new_potion._intensities = new_intensities | ||
| 167 | 167 | ||||
| 168 | self.has_been_used = True | 168 | self.has_been_used = True | ||
| 169 | other.has_been_used = True | 169 | other.has_been_used = True | ||
| 170 | 170 | ||||
| 171 | return new_potion | 171 | return new_potion | ||
| 172 | 172 | ||||
| 173 | def __truediv__(self, other): | 173 | def __truediv__(self, other): | ||
| 174 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | 174 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | ||
| 175 | 175 | ||||
| 176 | new_potion = Potion(self._effects, self._duration) | 176 | new_potion = Potion(self._effects, self._duration) | ||
| 177 | new_potion._intensities = updated_intensities | 177 | new_potion._intensities = updated_intensities | ||
| 178 | 178 | ||||
| 179 | self.has_been_used = True | 179 | self.has_been_used = True | ||
| 180 | 180 | ||||
| 181 | return tuple(deepcopy(new_potion) for _ in range(other)) | 181 | return tuple(deepcopy(new_potion) for _ in range(other)) | ||
| 182 | 182 | ||||
| 183 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | 183 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | ||
| 184 | def __deepcopy__(self, memodict={}): | 184 | def __deepcopy__(self, memodict={}): | ||
| 185 | cls = self.__class__ | 185 | cls = self.__class__ | ||
| 186 | new_object = cls.__new__(cls) | 186 | new_object = cls.__new__(cls) | ||
| 187 | memodict[id(self)] = new_object | 187 | memodict[id(self)] = new_object | ||
| 188 | for key, value in self.__dict__.items(): | 188 | for key, value in self.__dict__.items(): | ||
| 189 | setattr(new_object, key, deepcopy(value, memodict)) | 189 | setattr(new_object, key, deepcopy(value, memodict)) | ||
| 190 | return new_object | 190 | return new_object | ||
| 191 | 191 | ||||
| 192 | def __eq__(self, other): | 192 | def __eq__(self, other): | ||
| 193 | return self._effects == other.effects and self.get_comparable_effects() == other.get_comparable_effects() | 193 | return self._effects == other.effects and self.get_comparable_effects() == other.get_comparable_effects() | ||
| 194 | 194 | ||||
| 195 | def __gt__(self, other): | 195 | def __gt__(self, other): | ||
| 196 | return sum(self.get_comparable_effects().values()) > sum(other.get_comparable_effects().values()) and not self.__eq__(other) | 196 | return sum(self.get_comparable_effects().values()) > sum(other.get_comparable_effects().values()) and not self.__eq__(other) | ||
| 197 | 197 | ||||
| 198 | def __lt__(self, other): | 198 | def __lt__(self, other): | ||
| 199 | return sum(self.get_comparable_effects().values()) < sum(other.get_comparable_effects().values()) and not self.__eq__(other) | 199 | return sum(self.get_comparable_effects().values()) < sum(other.get_comparable_effects().values()) and not self.__eq__(other) | ||
| 200 | 200 | ||||
| 201 | def get_comparable_effects(self): | 201 | def get_comparable_effects(self): | ||
| 202 | return {effect: intensity for effect, intensity in self._intensities.items() if effect not in self._depleted_effects} | 202 | return {effect: intensity for effect, intensity in self._intensities.items() if effect not in self._depleted_effects} | ||
| 203 | 203 | ||||
| 204 | def get_applied(self, target): | 204 | def get_applied(self, target): | ||
| 205 | effects_map, masses = self._ordered_by_mass() | 205 | effects_map, masses = self._ordered_by_mass() | ||
| 206 | 206 | ||||
| 207 | for mass in masses: | 207 | for mass in masses: | ||
| 208 | name = effects_map[mass] | 208 | name = effects_map[mass] | ||
| 209 | effect = getattr(self, name) | 209 | effect = getattr(self, name) | ||
| 210 | effect(target) | 210 | effect(target) | ||
| 211 | 211 | ||||
| 212 | self.has_been_applied = True | 212 | self.has_been_applied = True | ||
| 213 | 213 | ||||
| 214 | def _ordered_by_mass(self): | 214 | def _ordered_by_mass(self): | ||
| 215 | effects_map = {self._get_mass(key): key for key in self._effects} | 215 | effects_map = {self._get_mass(key): key for key in self._effects} | ||
| 216 | masses = list(effects_map.keys()) | 216 | masses = list(effects_map.keys()) | ||
| 217 | masses.sort(reverse=True) | 217 | masses.sort(reverse=True) | ||
| 218 | 218 | ||||
| 219 | return effects_map, masses | 219 | return effects_map, masses | ||
| 220 | 220 | ||||
| 221 | @staticmethod | 221 | @staticmethod | ||
| 222 | def _get_mass(effect_name): | 222 | def _get_mass(effect_name): | ||
| 223 | return sum(map(ord, effect_name)) | 223 | return sum(map(ord, effect_name)) | ||
| 224 | 224 | ||||
| 225 | # Generated by IDE | 225 | # Generated by IDE | ||
| 226 | def __hash__(self): | 226 | def __hash__(self): | ||
| 227 | return super().__hash__() | 227 | return super().__hash__() | ||
| 228 | 228 | ||||
| 229 | 229 | ||||
| 230 | class ГоспожатаПоХимия: | 230 | class ГоспожатаПоХимия: | ||
| 231 | def __init__(self): | 231 | def __init__(self): | ||
| 232 | self._durations = {} | 232 | self._durations = {} | ||
| 233 | self._states = {} | 233 | self._states = {} | ||
| 234 | self._potions_on_targets = {} | 234 | self._potions_on_targets = {} | ||
| 235 | self._original_potions = {} | 235 | self._original_potions = {} | ||
| 236 | 236 | ||||
| 237 | def apply(self, target, potion): | 237 | def apply(self, target, potion): | ||
| 238 | self._durations[potion] = potion.duration | 238 | self._durations[potion] = potion.duration | ||
| 239 | 239 | ||||
| 240 | if target in self._potions_on_targets.values(): | 240 | if target in self._potions_on_targets.values(): | ||
| 241 | for key, value in self._potions_on_targets.items(): | 241 | for key, value in self._potions_on_targets.items(): | ||
| 242 | if value == target: | 242 | if value == target: | ||
| 243 | self._states[potion] = self._states[key] | 243 | self._states[potion] = self._states[key] | ||
| 244 | break | 244 | break | ||
| 245 | else: | 245 | else: | ||
| 246 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | 246 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | ||
| 247 | self._states[potion] = {name: getattr(target, name) for name in states_names} | 247 | self._states[potion] = {name: getattr(target, name) for name in states_names} | ||
| 248 | 248 | ||||
| 249 | self._potions_on_targets[potion] = target | 249 | self._potions_on_targets[potion] = target | ||
| 250 | self._original_potions[potion] = deepcopy(potion) | 250 | self._original_potions[potion] = deepcopy(potion) | ||
| 251 | 251 | ||||
| 252 | potion.get_applied(target) | 252 | potion.get_applied(target) | ||
| 253 | 253 | ||||
| 254 | def tick(self): | 254 | def tick(self): | ||
| 255 | for potion in self._durations: | 255 | for potion in self._durations: | ||
| 256 | self._durations[potion] -= 1 | 256 | self._durations[potion] -= 1 | ||
| 257 | 257 | ||||
| 258 | expired_potions = [key for key, value in self._durations.items() if value == 0] | 258 | expired_potions = [key for key, value in self._durations.items() if value == 0] | ||
| 259 | 259 | ||||
| 260 | used_targets = [] | 260 | used_targets = [] | ||
| 261 | for potion in expired_potions: | 261 | for potion in expired_potions: | ||
| 262 | for attribute, value in self._states[potion].items(): | 262 | for attribute, value in self._states[potion].items(): | ||
| 263 | setattr(self._potions_on_targets[potion], attribute, value) | 263 | setattr(self._potions_on_targets[potion], attribute, value) | ||
| 264 | 264 | ||||
| 265 | used_targets.append(self._potions_on_targets[potion]) | 265 | used_targets.append(self._potions_on_targets[potion]) | ||
| 266 | 266 | ||||
| 267 | del self._durations[potion] | 267 | del self._durations[potion] | ||
| 268 | del self._potions_on_targets[potion] | 268 | del self._potions_on_targets[potion] | ||
| 269 | del self._states[potion] | 269 | del self._states[potion] | ||
| 270 | del self._original_potions[potion] | 270 | del self._original_potions[potion] | ||
| 271 | 271 | ||||
| 272 | for used_target in used_targets: | 272 | for used_target in used_targets: | ||
| 273 | for potion, target in self._potions_on_targets.items(): | 273 | for potion, target in self._potions_on_targets.items(): | ||
| 274 | if used_target == target: | 274 | if used_target == target: | ||
| 275 | self._original_potions[potion].get_applied(target) | 275 | self._original_potions[potion].get_applied(target) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import math | f | 1 | import math |
| 2 | import re | 2 | import re | ||
| 3 | from copy import deepcopy | 3 | from copy import deepcopy | ||
| 4 | 4 | ||||
| 5 | 5 | ||||
| 6 | class Potion: | 6 | class Potion: | ||
| 7 | def __init__(self, effects, duration): | 7 | def __init__(self, effects, duration): | ||
| 8 | self._effects = effects | 8 | self._effects = effects | ||
| 9 | self._duration = duration | 9 | self._duration = duration | ||
| 10 | self._intensities = {key: 1 for key in effects} | 10 | self._intensities = {key: 1 for key in effects} | ||
| 11 | self._depleted_effects = set() | 11 | self._depleted_effects = set() | ||
| 12 | self._has_been_used = False | 12 | self._has_been_used = False | ||
| 13 | self._has_been_applied = False | 13 | self._has_been_applied = False | ||
| 14 | 14 | ||||
| 15 | def __getattribute__(self, item): | 15 | def __getattribute__(self, item): | ||
| 16 | if object.__getattribute__(self, '_has_been_applied'): | 16 | if object.__getattribute__(self, '_has_been_applied'): | ||
| 17 | raise TypeError('Potion is depleted') | 17 | raise TypeError('Potion is depleted') | ||
| 18 | if object.__getattribute__(self, '_has_been_used'): | 18 | if object.__getattribute__(self, '_has_been_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.') | ||
| 20 | 20 | ||||
| 21 | return object.__getattribute__(self, item) | 21 | return object.__getattribute__(self, item) | ||
| 22 | 22 | ||||
| 23 | def __getattr__(self, item): | 23 | def __getattr__(self, item): | ||
| 24 | if self._has_been_applied: | 24 | if self._has_been_applied: | ||
| 25 | raise TypeError('Potion is depleted') | 25 | raise TypeError('Potion is depleted') | ||
| 26 | 26 | ||||
| 27 | if item not in self._effects: | 27 | if item not in self._effects: | ||
| 28 | raise AttributeError('No such effect') | 28 | raise AttributeError('No such effect') | ||
| 29 | 29 | ||||
| 30 | if item in self._depleted_effects: | 30 | if item in self._depleted_effects: | ||
| 31 | raise TypeError('Effect is depleted') | 31 | raise TypeError('Effect is depleted') | ||
| 32 | 32 | ||||
| 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | ||
| 34 | 34 | ||||
| 35 | self._depleted_effects.add(item) | 35 | self._depleted_effects.add(item) | ||
| 36 | 36 | ||||
| 37 | return effect | 37 | return effect | ||
| 38 | 38 | ||||
| 39 | @staticmethod | 39 | @staticmethod | ||
| 40 | def _intensify_effect(times): | 40 | def _intensify_effect(times): | ||
| 41 | def intensifying_decorator(function): | 41 | def intensifying_decorator(function): | ||
| 42 | def intensifying_wrapper(*args, **kwargs): | 42 | def intensifying_wrapper(*args, **kwargs): | ||
| 43 | for _ in range(times): | 43 | for _ in range(times): | ||
| 44 | function(*args, **kwargs) | 44 | function(*args, **kwargs) | ||
| 45 | 45 | ||||
| 46 | return intensifying_wrapper | 46 | return intensifying_wrapper | ||
| 47 | 47 | ||||
| 48 | return intensifying_decorator | 48 | return intensifying_decorator | ||
| 49 | 49 | ||||
| 50 | @property | 50 | @property | ||
| 51 | def has_been_used(self): | 51 | def has_been_used(self): | ||
| 52 | return self._has_been_used | 52 | return self._has_been_used | ||
| 53 | 53 | ||||
| 54 | @has_been_used.setter | 54 | @has_been_used.setter | ||
| 55 | def has_been_used(self, value): | 55 | def has_been_used(self, value): | ||
| 56 | self._has_been_used = value | 56 | self._has_been_used = value | ||
| 57 | 57 | ||||
| 58 | @property | 58 | @property | ||
| 59 | def has_been_applied(self): | 59 | def has_been_applied(self): | ||
| 60 | return self._has_been_applied | 60 | return self._has_been_applied | ||
| 61 | 61 | ||||
| 62 | @has_been_applied.setter | 62 | @has_been_applied.setter | ||
| 63 | def has_been_applied(self, value): | 63 | def has_been_applied(self, value): | ||
| 64 | self._has_been_applied = value | 64 | self._has_been_applied = value | ||
| 65 | 65 | ||||
| 66 | @property | 66 | @property | ||
| 67 | def duration(self): | 67 | def duration(self): | ||
| 68 | return self._duration | 68 | return self._duration | ||
| 69 | 69 | ||||
| 70 | @duration.setter | 70 | @duration.setter | ||
| 71 | def duration(self, value): | 71 | def duration(self, value): | ||
| 72 | self._duration = value | 72 | self._duration = value | ||
| 73 | 73 | ||||
| 74 | @property | 74 | @property | ||
| 75 | def intensities(self): | 75 | def intensities(self): | ||
| 76 | return self._intensities | 76 | return self._intensities | ||
| 77 | 77 | ||||
| 78 | @intensities.setter | 78 | @intensities.setter | ||
| 79 | def intensities(self, value): | 79 | def intensities(self, value): | ||
| 80 | self._intensities = value | 80 | self._intensities = value | ||
| 81 | 81 | ||||
| 82 | @property | 82 | @property | ||
| 83 | def effects(self): | 83 | def effects(self): | ||
| 84 | return self._effects | 84 | return self._effects | ||
| 85 | 85 | ||||
| 86 | @effects.setter | 86 | @effects.setter | ||
| 87 | def effects(self, value): | 87 | def effects(self, value): | ||
| 88 | self._effects = value | 88 | self._effects = value | ||
| 89 | 89 | ||||
| 90 | def __add__(self, other): | 90 | def __add__(self, other): | ||
| 91 | new_effects = self._combine_effects(other) | 91 | new_effects = self._combine_effects(other) | ||
| 92 | new_intensities = self._combine_intensities(other) | 92 | new_intensities = self._combine_intensities(other) | ||
| 93 | 93 | ||||
| 94 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | 94 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | ||
| 95 | new_potion._intensities = new_intensities | 95 | new_potion._intensities = new_intensities | ||
| 96 | 96 | ||||
| 97 | self.has_been_used = True | 97 | self.has_been_used = True | ||
| 98 | other.has_been_used = True | 98 | other.has_been_used = True | ||
| 99 | 99 | ||||
| 100 | return new_potion | 100 | return new_potion | ||
| 101 | 101 | ||||
| 102 | def _combine_effects(self, other): | 102 | def _combine_effects(self, other): | ||
| 103 | new_effects = {} | 103 | new_effects = {} | ||
| 104 | 104 | ||||
| 105 | for key, value in self.effects.items(): | 105 | for key, value in self.effects.items(): | ||
| 106 | new_effects[key] = value | 106 | new_effects[key] = value | ||
| 107 | 107 | ||||
| 108 | for key, value in other.effects.items(): | 108 | for key, value in other.effects.items(): | ||
| 109 | new_effects[key] = value | 109 | new_effects[key] = value | ||
| 110 | 110 | ||||
| 111 | return new_effects | 111 | return new_effects | ||
| 112 | 112 | ||||
| 113 | def _combine_intensities(self, other): | 113 | def _combine_intensities(self, other): | ||
| 114 | new_intensities = {} | 114 | new_intensities = {} | ||
| 115 | 115 | ||||
| 116 | for key, value in self._intensities.items(): | 116 | for key, value in self._intensities.items(): | ||
| 117 | new_intensities[key] = value | 117 | new_intensities[key] = value | ||
| 118 | 118 | ||||
| 119 | for key, value in other.intensities.items(): | 119 | for key, value in other.intensities.items(): | ||
| 120 | if key in new_intensities: | 120 | if key in new_intensities: | ||
| 121 | new_intensities[key] += value | 121 | new_intensities[key] += value | ||
| 122 | else: | 122 | else: | ||
| 123 | new_intensities[key] = value | 123 | new_intensities[key] = value | ||
| 124 | 124 | ||||
| 125 | return new_intensities | 125 | return new_intensities | ||
| 126 | 126 | ||||
| 127 | def __mul__(self, other): | 127 | def __mul__(self, other): | ||
| 128 | updated_intensities = {} | 128 | updated_intensities = {} | ||
| 129 | 129 | ||||
| 130 | if isinstance(other, int): | 130 | if isinstance(other, int): | ||
| 131 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | 131 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | ||
| 132 | elif isinstance(other, float) and 0 <= other <= 1: | 132 | elif isinstance(other, float) and 0 <= other <= 1: | ||
| 133 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | 133 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | ||
| 134 | 134 | ||||
| 135 | new_potion = Potion(self._effects, self._duration) | 135 | new_potion = Potion(self._effects, self._duration) | ||
| 136 | new_potion._intensities = updated_intensities | 136 | new_potion._intensities = updated_intensities | ||
| 137 | 137 | ||||
| 138 | self.has_been_used = True | 138 | self.has_been_used = True | ||
| 139 | 139 | ||||
| 140 | return new_potion | 140 | return new_potion | ||
| 141 | 141 | ||||
| 142 | @staticmethod | 142 | @staticmethod | ||
| 143 | def _round_to_whole(real): | 143 | def _round_to_whole(real): | ||
| 144 | fraction = real - math.floor(real) | 144 | fraction = real - math.floor(real) | ||
| 145 | 145 | ||||
| 146 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | 146 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | ||
| 147 | 147 | ||||
| 148 | def __sub__(self, other): | 148 | def __sub__(self, other): | ||
| 149 | if set(other.effects.keys()) - set(self._effects.keys()): | 149 | if set(other.effects.keys()) - set(self._effects.keys()): | ||
| 150 | raise TypeError('съдържанието няма значение') | 150 | raise TypeError('съдържанието няма значение') | ||
| 151 | 151 | ||||
| 152 | new_effects = {} | 152 | new_effects = {} | ||
| 153 | new_intensities = {} | 153 | new_intensities = {} | ||
| 154 | 154 | ||||
| 155 | for name, intensity in self._intensities.items(): | 155 | for name, intensity in self._intensities.items(): | ||
| 156 | if name not in other.intensities: | 156 | if name not in other.intensities: | ||
| 157 | new_effects[name] = self._effects[name] | 157 | new_effects[name] = self._effects[name] | ||
| 158 | new_intensities[name] = intensity | 158 | new_intensities[name] = intensity | ||
| 159 | else: | 159 | else: | ||
| 160 | difference = intensity - other.intensities[name] | 160 | difference = intensity - other.intensities[name] | ||
| 161 | if difference > 0: | 161 | if difference > 0: | ||
| 162 | new_effects[name] = self._effects[name] | 162 | new_effects[name] = self._effects[name] | ||
| 163 | new_intensities[name] = difference | 163 | new_intensities[name] = difference | ||
| 164 | 164 | ||||
| 165 | new_potion = Potion(new_effects, self._duration) | 165 | new_potion = Potion(new_effects, self._duration) | ||
| 166 | new_potion._intensities = new_intensities | 166 | new_potion._intensities = new_intensities | ||
| 167 | 167 | ||||
| 168 | self.has_been_used = True | 168 | self.has_been_used = True | ||
| 169 | other.has_been_used = True | 169 | other.has_been_used = True | ||
| 170 | 170 | ||||
| 171 | return new_potion | 171 | return new_potion | ||
| 172 | 172 | ||||
| 173 | def __truediv__(self, other): | 173 | def __truediv__(self, other): | ||
| 174 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | 174 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | ||
| 175 | 175 | ||||
| 176 | new_potion = Potion(self._effects, self._duration) | 176 | new_potion = Potion(self._effects, self._duration) | ||
| 177 | new_potion._intensities = updated_intensities | 177 | new_potion._intensities = updated_intensities | ||
| 178 | 178 | ||||
| 179 | self.has_been_used = True | 179 | self.has_been_used = True | ||
| 180 | 180 | ||||
| 181 | return tuple(deepcopy(new_potion) for _ in range(other)) | 181 | return tuple(deepcopy(new_potion) for _ in range(other)) | ||
| 182 | 182 | ||||
| 183 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | 183 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | ||
| 184 | def __deepcopy__(self, memodict={}): | 184 | def __deepcopy__(self, memodict={}): | ||
| 185 | cls = self.__class__ | 185 | cls = self.__class__ | ||
| 186 | new_object = cls.__new__(cls) | 186 | new_object = cls.__new__(cls) | ||
| 187 | memodict[id(self)] = new_object | 187 | memodict[id(self)] = new_object | ||
| 188 | for key, value in self.__dict__.items(): | 188 | for key, value in self.__dict__.items(): | ||
| 189 | setattr(new_object, key, deepcopy(value, memodict)) | 189 | setattr(new_object, key, deepcopy(value, memodict)) | ||
| 190 | return new_object | 190 | return new_object | ||
| 191 | 191 | ||||
| 192 | def __eq__(self, other): | 192 | def __eq__(self, other): | ||
| n | 193 | return self._effects == other.effects and self._intensities == other.intensities | n | 193 | return self._effects == other.effects and self.get_comparable_effects() == other.get_comparable_effects() |
| 194 | 194 | ||||
| 195 | def __gt__(self, other): | 195 | def __gt__(self, other): | ||
| n | 196 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | n | 196 | return sum(self.get_comparable_effects().values()) > sum(other.get_comparable_effects().values()) and not self.__eq__(other) |
| 197 | 197 | ||||
| 198 | def __lt__(self, other): | 198 | def __lt__(self, other): | ||
| n | 199 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | n | 199 | return sum(self.get_comparable_effects().values()) < sum(other.get_comparable_effects().values()) and not self.__eq__(other) |
| 200 | |||||
| 201 | def get_comparable_effects(self): | ||||
| 202 | return {effect: intensity for effect, intensity in self._intensities.items() if effect not in self._depleted_effects} | ||||
| 200 | 203 | ||||
| 201 | def get_applied(self, target): | 204 | def get_applied(self, target): | ||
| 202 | effects_map, masses = self._ordered_by_mass() | 205 | effects_map, masses = self._ordered_by_mass() | ||
| 203 | 206 | ||||
| 204 | for mass in masses: | 207 | for mass in masses: | ||
| 205 | name = effects_map[mass] | 208 | name = effects_map[mass] | ||
| t | 206 | if self._intensities[name] > 0: | t | ||
| 207 | effect = getattr(self, name) | 209 | effect = getattr(self, name) | ||
| 208 | effect(target) | 210 | effect(target) | ||
| 209 | 211 | ||||
| 210 | self.has_been_applied = True | 212 | self.has_been_applied = True | ||
| 211 | 213 | ||||
| 212 | def _ordered_by_mass(self): | 214 | def _ordered_by_mass(self): | ||
| 213 | effects_map = {self._get_mass(key): key for key in self._effects} | 215 | effects_map = {self._get_mass(key): key for key in self._effects} | ||
| 214 | masses = list(effects_map.keys()) | 216 | masses = list(effects_map.keys()) | ||
| 215 | masses.sort(reverse=True) | 217 | masses.sort(reverse=True) | ||
| 216 | 218 | ||||
| 217 | return effects_map, masses | 219 | return effects_map, masses | ||
| 218 | 220 | ||||
| 219 | @staticmethod | 221 | @staticmethod | ||
| 220 | def _get_mass(effect_name): | 222 | def _get_mass(effect_name): | ||
| 221 | return sum(map(ord, effect_name)) | 223 | return sum(map(ord, effect_name)) | ||
| 222 | 224 | ||||
| 223 | # Generated by IDE | 225 | # Generated by IDE | ||
| 224 | def __hash__(self): | 226 | def __hash__(self): | ||
| 225 | return super().__hash__() | 227 | return super().__hash__() | ||
| 226 | 228 | ||||
| 227 | 229 | ||||
| 228 | class ГоспожатаПоХимия: | 230 | class ГоспожатаПоХимия: | ||
| 229 | def __init__(self): | 231 | def __init__(self): | ||
| 230 | self._durations = {} | 232 | self._durations = {} | ||
| 231 | self._states = {} | 233 | self._states = {} | ||
| 232 | self._potions_on_targets = {} | 234 | self._potions_on_targets = {} | ||
| 233 | self._original_potions = {} | 235 | self._original_potions = {} | ||
| 234 | 236 | ||||
| 235 | def apply(self, target, potion): | 237 | def apply(self, target, potion): | ||
| 236 | self._durations[potion] = potion.duration | 238 | self._durations[potion] = potion.duration | ||
| 237 | 239 | ||||
| 238 | if target in self._potions_on_targets.values(): | 240 | if target in self._potions_on_targets.values(): | ||
| 239 | for key, value in self._potions_on_targets.items(): | 241 | for key, value in self._potions_on_targets.items(): | ||
| 240 | if value == target: | 242 | if value == target: | ||
| 241 | self._states[potion] = self._states[key] | 243 | self._states[potion] = self._states[key] | ||
| 242 | break | 244 | break | ||
| 243 | else: | 245 | else: | ||
| 244 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | 246 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | ||
| 245 | self._states[potion] = {name: getattr(target, name) for name in states_names} | 247 | self._states[potion] = {name: getattr(target, name) for name in states_names} | ||
| 246 | 248 | ||||
| 247 | self._potions_on_targets[potion] = target | 249 | self._potions_on_targets[potion] = target | ||
| 248 | self._original_potions[potion] = deepcopy(potion) | 250 | self._original_potions[potion] = deepcopy(potion) | ||
| 249 | 251 | ||||
| 250 | potion.get_applied(target) | 252 | potion.get_applied(target) | ||
| 251 | 253 | ||||
| 252 | def tick(self): | 254 | def tick(self): | ||
| 253 | for potion in self._durations: | 255 | for potion in self._durations: | ||
| 254 | self._durations[potion] -= 1 | 256 | self._durations[potion] -= 1 | ||
| 255 | 257 | ||||
| 256 | expired_potions = [key for key, value in self._durations.items() if value == 0] | 258 | expired_potions = [key for key, value in self._durations.items() if value == 0] | ||
| 257 | 259 | ||||
| 258 | used_targets = [] | 260 | used_targets = [] | ||
| 259 | for potion in expired_potions: | 261 | for potion in expired_potions: | ||
| 260 | for attribute, value in self._states[potion].items(): | 262 | for attribute, value in self._states[potion].items(): | ||
| 261 | setattr(self._potions_on_targets[potion], attribute, value) | 263 | setattr(self._potions_on_targets[potion], attribute, value) | ||
| 262 | 264 | ||||
| 263 | used_targets.append(self._potions_on_targets[potion]) | 265 | used_targets.append(self._potions_on_targets[potion]) | ||
| 264 | 266 | ||||
| 265 | del self._durations[potion] | 267 | del self._durations[potion] | ||
| 266 | del self._potions_on_targets[potion] | 268 | del self._potions_on_targets[potion] | ||
| 267 | del self._states[potion] | 269 | del self._states[potion] | ||
| 268 | del self._original_potions[potion] | 270 | del self._original_potions[potion] | ||
| 269 | 271 | ||||
| 270 | for used_target in used_targets: | 272 | for used_target in used_targets: | ||
| 271 | for potion, target in self._potions_on_targets.items(): | 273 | for potion, target in self._potions_on_targets.items(): | ||
| 272 | if used_target == target: | 274 | if used_target == target: | ||
| 273 | self._original_potions[potion].get_applied(target) | 275 | self._original_potions[potion].get_applied(target) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import math | f | 1 | import math |
| 2 | import re | 2 | import re | ||
| 3 | from copy import deepcopy | 3 | from copy import deepcopy | ||
| 4 | 4 | ||||
| 5 | 5 | ||||
| 6 | class Potion: | 6 | class Potion: | ||
| 7 | def __init__(self, effects, duration): | 7 | def __init__(self, effects, duration): | ||
| 8 | self._effects = effects | 8 | self._effects = effects | ||
| 9 | self._duration = duration | 9 | self._duration = duration | ||
| 10 | self._intensities = {key: 1 for key in effects} | 10 | self._intensities = {key: 1 for key in effects} | ||
| n | n | 11 | self._depleted_effects = set() | ||
| 11 | self._has_been_used = False | 12 | self._has_been_used = False | ||
| 12 | self._has_been_applied = False | 13 | self._has_been_applied = False | ||
| 13 | 14 | ||||
| 14 | def __getattribute__(self, item): | 15 | def __getattribute__(self, item): | ||
| 15 | if object.__getattribute__(self, '_has_been_applied'): | 16 | if object.__getattribute__(self, '_has_been_applied'): | ||
| 16 | raise TypeError('Potion is depleted') | 17 | raise TypeError('Potion is depleted') | ||
| 17 | if object.__getattribute__(self, '_has_been_used'): | 18 | if object.__getattribute__(self, '_has_been_used'): | ||
| 18 | raise TypeError('Potion is now part of something bigger than itself.') | 19 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 19 | 20 | ||||
| 20 | return object.__getattribute__(self, item) | 21 | return object.__getattribute__(self, item) | ||
| 21 | 22 | ||||
| 22 | def __getattr__(self, item): | 23 | def __getattr__(self, item): | ||
| 23 | if self._has_been_applied: | 24 | if self._has_been_applied: | ||
| 24 | raise TypeError('Potion is depleted') | 25 | raise TypeError('Potion is depleted') | ||
| 25 | 26 | ||||
| 26 | if item not in self._effects: | 27 | if item not in self._effects: | ||
| 27 | raise AttributeError('No such effect') | 28 | raise AttributeError('No such effect') | ||
| 28 | 29 | ||||
| n | 29 | if self._intensities[item] == 0: | n | 30 | if item in self._depleted_effects: |
| 30 | raise TypeError('Effect is depleted') | 31 | raise TypeError('Effect is depleted') | ||
| 31 | 32 | ||||
| 32 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | ||
| n | 33 | self._intensities[item] = 0 | n | 34 | |
| 35 | self._depleted_effects.add(item) | ||||
| 34 | 36 | ||||
| 35 | return effect | 37 | return effect | ||
| 36 | 38 | ||||
| 37 | @staticmethod | 39 | @staticmethod | ||
| 38 | def _intensify_effect(times): | 40 | def _intensify_effect(times): | ||
| 39 | def intensifying_decorator(function): | 41 | def intensifying_decorator(function): | ||
| 40 | def intensifying_wrapper(*args, **kwargs): | 42 | def intensifying_wrapper(*args, **kwargs): | ||
| 41 | for _ in range(times): | 43 | for _ in range(times): | ||
| 42 | function(*args, **kwargs) | 44 | function(*args, **kwargs) | ||
| 43 | 45 | ||||
| 44 | return intensifying_wrapper | 46 | return intensifying_wrapper | ||
| 45 | 47 | ||||
| 46 | return intensifying_decorator | 48 | return intensifying_decorator | ||
| 47 | 49 | ||||
| 48 | @property | 50 | @property | ||
| 49 | def has_been_used(self): | 51 | def has_been_used(self): | ||
| 50 | return self._has_been_used | 52 | return self._has_been_used | ||
| 51 | 53 | ||||
| 52 | @has_been_used.setter | 54 | @has_been_used.setter | ||
| 53 | def has_been_used(self, value): | 55 | def has_been_used(self, value): | ||
| 54 | self._has_been_used = value | 56 | self._has_been_used = value | ||
| 55 | 57 | ||||
| 56 | @property | 58 | @property | ||
| 57 | def has_been_applied(self): | 59 | def has_been_applied(self): | ||
| 58 | return self._has_been_applied | 60 | return self._has_been_applied | ||
| 59 | 61 | ||||
| 60 | @has_been_applied.setter | 62 | @has_been_applied.setter | ||
| 61 | def has_been_applied(self, value): | 63 | def has_been_applied(self, value): | ||
| 62 | self._has_been_applied = value | 64 | self._has_been_applied = value | ||
| 63 | 65 | ||||
| 64 | @property | 66 | @property | ||
| 65 | def duration(self): | 67 | def duration(self): | ||
| 66 | return self._duration | 68 | return self._duration | ||
| 67 | 69 | ||||
| 68 | @duration.setter | 70 | @duration.setter | ||
| 69 | def duration(self, value): | 71 | def duration(self, value): | ||
| 70 | self._duration = value | 72 | self._duration = value | ||
| 71 | 73 | ||||
| 72 | @property | 74 | @property | ||
| 73 | def intensities(self): | 75 | def intensities(self): | ||
| 74 | return self._intensities | 76 | return self._intensities | ||
| 75 | 77 | ||||
| 76 | @intensities.setter | 78 | @intensities.setter | ||
| 77 | def intensities(self, value): | 79 | def intensities(self, value): | ||
| 78 | self._intensities = value | 80 | self._intensities = value | ||
| 79 | 81 | ||||
| 80 | @property | 82 | @property | ||
| 81 | def effects(self): | 83 | def effects(self): | ||
| 82 | return self._effects | 84 | return self._effects | ||
| 83 | 85 | ||||
| 84 | @effects.setter | 86 | @effects.setter | ||
| 85 | def effects(self, value): | 87 | def effects(self, value): | ||
| 86 | self._effects = value | 88 | self._effects = value | ||
| 87 | 89 | ||||
| 88 | def __add__(self, other): | 90 | def __add__(self, other): | ||
| 89 | new_effects = self._combine_effects(other) | 91 | new_effects = self._combine_effects(other) | ||
| 90 | new_intensities = self._combine_intensities(other) | 92 | new_intensities = self._combine_intensities(other) | ||
| 91 | 93 | ||||
| 92 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | 94 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | ||
| 93 | new_potion._intensities = new_intensities | 95 | new_potion._intensities = new_intensities | ||
| 94 | 96 | ||||
| 95 | self.has_been_used = True | 97 | self.has_been_used = True | ||
| 96 | other.has_been_used = True | 98 | other.has_been_used = True | ||
| 97 | 99 | ||||
| 98 | return new_potion | 100 | return new_potion | ||
| 99 | 101 | ||||
| 100 | def _combine_effects(self, other): | 102 | def _combine_effects(self, other): | ||
| 101 | new_effects = {} | 103 | new_effects = {} | ||
| 102 | 104 | ||||
| 103 | for key, value in self.effects.items(): | 105 | for key, value in self.effects.items(): | ||
| 104 | new_effects[key] = value | 106 | new_effects[key] = value | ||
| 105 | 107 | ||||
| 106 | for key, value in other.effects.items(): | 108 | for key, value in other.effects.items(): | ||
| 107 | new_effects[key] = value | 109 | new_effects[key] = value | ||
| 108 | 110 | ||||
| 109 | return new_effects | 111 | return new_effects | ||
| 110 | 112 | ||||
| 111 | def _combine_intensities(self, other): | 113 | def _combine_intensities(self, other): | ||
| 112 | new_intensities = {} | 114 | new_intensities = {} | ||
| 113 | 115 | ||||
| 114 | for key, value in self._intensities.items(): | 116 | for key, value in self._intensities.items(): | ||
| 115 | new_intensities[key] = value | 117 | new_intensities[key] = value | ||
| 116 | 118 | ||||
| 117 | for key, value in other.intensities.items(): | 119 | for key, value in other.intensities.items(): | ||
| 118 | if key in new_intensities: | 120 | if key in new_intensities: | ||
| 119 | new_intensities[key] += value | 121 | new_intensities[key] += value | ||
| 120 | else: | 122 | else: | ||
| 121 | new_intensities[key] = value | 123 | new_intensities[key] = value | ||
| 122 | 124 | ||||
| 123 | return new_intensities | 125 | return new_intensities | ||
| 124 | 126 | ||||
| 125 | def __mul__(self, other): | 127 | def __mul__(self, other): | ||
| 126 | updated_intensities = {} | 128 | updated_intensities = {} | ||
| 127 | 129 | ||||
| 128 | if isinstance(other, int): | 130 | if isinstance(other, int): | ||
| 129 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | 131 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | ||
| 130 | elif isinstance(other, float) and 0 <= other <= 1: | 132 | elif isinstance(other, float) and 0 <= other <= 1: | ||
| 131 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | 133 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | ||
| 132 | 134 | ||||
| 133 | new_potion = Potion(self._effects, self._duration) | 135 | new_potion = Potion(self._effects, self._duration) | ||
| 134 | new_potion._intensities = updated_intensities | 136 | new_potion._intensities = updated_intensities | ||
| 135 | 137 | ||||
| 136 | self.has_been_used = True | 138 | self.has_been_used = True | ||
| 137 | 139 | ||||
| 138 | return new_potion | 140 | return new_potion | ||
| 139 | 141 | ||||
| 140 | @staticmethod | 142 | @staticmethod | ||
| 141 | def _round_to_whole(real): | 143 | def _round_to_whole(real): | ||
| 142 | fraction = real - math.floor(real) | 144 | fraction = real - math.floor(real) | ||
| 143 | 145 | ||||
| 144 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | 146 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | ||
| 145 | 147 | ||||
| 146 | def __sub__(self, other): | 148 | def __sub__(self, other): | ||
| 147 | if set(other.effects.keys()) - set(self._effects.keys()): | 149 | if set(other.effects.keys()) - set(self._effects.keys()): | ||
| 148 | raise TypeError('съдържанието няма значение') | 150 | raise TypeError('съдържанието няма значение') | ||
| 149 | 151 | ||||
| 150 | new_effects = {} | 152 | new_effects = {} | ||
| 151 | new_intensities = {} | 153 | new_intensities = {} | ||
| 152 | 154 | ||||
| 153 | for name, intensity in self._intensities.items(): | 155 | for name, intensity in self._intensities.items(): | ||
| 154 | if name not in other.intensities: | 156 | if name not in other.intensities: | ||
| 155 | new_effects[name] = self._effects[name] | 157 | new_effects[name] = self._effects[name] | ||
| 156 | new_intensities[name] = intensity | 158 | new_intensities[name] = intensity | ||
| 157 | else: | 159 | else: | ||
| 158 | difference = intensity - other.intensities[name] | 160 | difference = intensity - other.intensities[name] | ||
| 159 | if difference > 0: | 161 | if difference > 0: | ||
| 160 | new_effects[name] = self._effects[name] | 162 | new_effects[name] = self._effects[name] | ||
| 161 | new_intensities[name] = difference | 163 | new_intensities[name] = difference | ||
| 162 | 164 | ||||
| 163 | new_potion = Potion(new_effects, self._duration) | 165 | new_potion = Potion(new_effects, self._duration) | ||
| 164 | new_potion._intensities = new_intensities | 166 | new_potion._intensities = new_intensities | ||
| 165 | 167 | ||||
| 166 | self.has_been_used = True | 168 | self.has_been_used = True | ||
| 167 | other.has_been_used = True | 169 | other.has_been_used = True | ||
| 168 | 170 | ||||
| 169 | return new_potion | 171 | return new_potion | ||
| 170 | 172 | ||||
| 171 | def __truediv__(self, other): | 173 | def __truediv__(self, other): | ||
| 172 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | 174 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | ||
| 173 | 175 | ||||
| 174 | new_potion = Potion(self._effects, self._duration) | 176 | new_potion = Potion(self._effects, self._duration) | ||
| 175 | new_potion._intensities = updated_intensities | 177 | new_potion._intensities = updated_intensities | ||
| 176 | 178 | ||||
| 177 | self.has_been_used = True | 179 | self.has_been_used = True | ||
| 178 | 180 | ||||
| 179 | return tuple(deepcopy(new_potion) for _ in range(other)) | 181 | return tuple(deepcopy(new_potion) for _ in range(other)) | ||
| 180 | 182 | ||||
| 181 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | 183 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | ||
| 182 | def __deepcopy__(self, memodict={}): | 184 | def __deepcopy__(self, memodict={}): | ||
| 183 | cls = self.__class__ | 185 | cls = self.__class__ | ||
| 184 | new_object = cls.__new__(cls) | 186 | new_object = cls.__new__(cls) | ||
| 185 | memodict[id(self)] = new_object | 187 | memodict[id(self)] = new_object | ||
| 186 | for key, value in self.__dict__.items(): | 188 | for key, value in self.__dict__.items(): | ||
| 187 | setattr(new_object, key, deepcopy(value, memodict)) | 189 | setattr(new_object, key, deepcopy(value, memodict)) | ||
| 188 | return new_object | 190 | return new_object | ||
| 189 | 191 | ||||
| 190 | def __eq__(self, other): | 192 | def __eq__(self, other): | ||
| 191 | return self._effects == other.effects and self._intensities == other.intensities | 193 | return self._effects == other.effects and self._intensities == other.intensities | ||
| 192 | 194 | ||||
| 193 | def __gt__(self, other): | 195 | def __gt__(self, other): | ||
| 194 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | 196 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | ||
| 195 | 197 | ||||
| 196 | def __lt__(self, other): | 198 | def __lt__(self, other): | ||
| 197 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | 199 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | ||
| 198 | 200 | ||||
| 199 | def get_applied(self, target): | 201 | def get_applied(self, target): | ||
| 200 | effects_map, masses = self._ordered_by_mass() | 202 | effects_map, masses = self._ordered_by_mass() | ||
| 201 | 203 | ||||
| 202 | for mass in masses: | 204 | for mass in masses: | ||
| 203 | name = effects_map[mass] | 205 | name = effects_map[mass] | ||
| 204 | if self._intensities[name] > 0: | 206 | if self._intensities[name] > 0: | ||
| 205 | effect = getattr(self, name) | 207 | effect = getattr(self, name) | ||
| 206 | effect(target) | 208 | effect(target) | ||
| 207 | 209 | ||||
| 208 | self.has_been_applied = True | 210 | self.has_been_applied = True | ||
| 209 | 211 | ||||
| 210 | def _ordered_by_mass(self): | 212 | def _ordered_by_mass(self): | ||
| 211 | effects_map = {self._get_mass(key): key for key in self._effects} | 213 | effects_map = {self._get_mass(key): key for key in self._effects} | ||
| 212 | masses = list(effects_map.keys()) | 214 | masses = list(effects_map.keys()) | ||
| 213 | masses.sort(reverse=True) | 215 | masses.sort(reverse=True) | ||
| 214 | 216 | ||||
| 215 | return effects_map, masses | 217 | return effects_map, masses | ||
| 216 | 218 | ||||
| 217 | @staticmethod | 219 | @staticmethod | ||
| 218 | def _get_mass(effect_name): | 220 | def _get_mass(effect_name): | ||
| 219 | return sum(map(ord, effect_name)) | 221 | return sum(map(ord, effect_name)) | ||
| 220 | 222 | ||||
| 221 | # Generated by IDE | 223 | # Generated by IDE | ||
| 222 | def __hash__(self): | 224 | def __hash__(self): | ||
| 223 | return super().__hash__() | 225 | return super().__hash__() | ||
| 224 | 226 | ||||
| 225 | 227 | ||||
| 226 | class ГоспожатаПоХимия: | 228 | class ГоспожатаПоХимия: | ||
| 227 | def __init__(self): | 229 | def __init__(self): | ||
| 228 | self._durations = {} | 230 | self._durations = {} | ||
| 229 | self._states = {} | 231 | self._states = {} | ||
| 230 | self._potions_on_targets = {} | 232 | self._potions_on_targets = {} | ||
| 231 | self._original_potions = {} | 233 | self._original_potions = {} | ||
| 232 | 234 | ||||
| 233 | def apply(self, target, potion): | 235 | def apply(self, target, potion): | ||
| 234 | self._durations[potion] = potion.duration | 236 | self._durations[potion] = potion.duration | ||
| 235 | 237 | ||||
| 236 | if target in self._potions_on_targets.values(): | 238 | if target in self._potions_on_targets.values(): | ||
| 237 | for key, value in self._potions_on_targets.items(): | 239 | for key, value in self._potions_on_targets.items(): | ||
| 238 | if value == target: | 240 | if value == target: | ||
| 239 | self._states[potion] = self._states[key] | 241 | self._states[potion] = self._states[key] | ||
| 240 | break | 242 | break | ||
| 241 | else: | 243 | else: | ||
| 242 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | 244 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | ||
| 243 | self._states[potion] = {name: getattr(target, name) for name in states_names} | 245 | self._states[potion] = {name: getattr(target, name) for name in states_names} | ||
| 244 | 246 | ||||
| 245 | self._potions_on_targets[potion] = target | 247 | self._potions_on_targets[potion] = target | ||
| 246 | self._original_potions[potion] = deepcopy(potion) | 248 | self._original_potions[potion] = deepcopy(potion) | ||
| 247 | 249 | ||||
| n | 248 | self._apply(target, potion) | n | ||
| 249 | |||||
| 250 | @staticmethod | ||||
| 251 | def _apply(target, potion): | ||||
| 252 | potion.get_applied(target) | 250 | potion.get_applied(target) | ||
| 253 | 251 | ||||
| 254 | def tick(self): | 252 | def tick(self): | ||
| 255 | for potion in self._durations: | 253 | for potion in self._durations: | ||
| 256 | self._durations[potion] -= 1 | 254 | self._durations[potion] -= 1 | ||
| 257 | 255 | ||||
| 258 | expired_potions = [key for key, value in self._durations.items() if value == 0] | 256 | expired_potions = [key for key, value in self._durations.items() if value == 0] | ||
| 259 | 257 | ||||
| 260 | used_targets = [] | 258 | used_targets = [] | ||
| 261 | for potion in expired_potions: | 259 | for potion in expired_potions: | ||
| 262 | for attribute, value in self._states[potion].items(): | 260 | for attribute, value in self._states[potion].items(): | ||
| 263 | setattr(self._potions_on_targets[potion], attribute, value) | 261 | setattr(self._potions_on_targets[potion], attribute, value) | ||
| 264 | 262 | ||||
| 265 | used_targets.append(self._potions_on_targets[potion]) | 263 | used_targets.append(self._potions_on_targets[potion]) | ||
| 266 | 264 | ||||
| 267 | del self._durations[potion] | 265 | del self._durations[potion] | ||
| 268 | del self._potions_on_targets[potion] | 266 | del self._potions_on_targets[potion] | ||
| 269 | del self._states[potion] | 267 | del self._states[potion] | ||
| 270 | del self._original_potions[potion] | 268 | del self._original_potions[potion] | ||
| 271 | 269 | ||||
| 272 | for used_target in used_targets: | 270 | for used_target in used_targets: | ||
| 273 | for potion, target in self._potions_on_targets.items(): | 271 | for potion, target in self._potions_on_targets.items(): | ||
| 274 | if used_target == target: | 272 | if used_target == target: | ||
| t | 275 | self._apply(target, self._original_potions[potion]) | t | 273 | self._original_potions[potion].get_applied(target) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| n | 1 | import copy | n | ||
| 2 | import math | 1 | import math | ||
| 3 | import re | 2 | import re | ||
| 4 | from copy import deepcopy | 3 | from copy import deepcopy | ||
| 5 | 4 | ||||
| 6 | 5 | ||||
| 7 | class Potion: | 6 | class Potion: | ||
| 8 | def __init__(self, effects, duration): | 7 | def __init__(self, effects, duration): | ||
| 9 | self._effects = effects | 8 | self._effects = effects | ||
| 10 | self._duration = duration | 9 | self._duration = duration | ||
| 11 | self._intensities = {key: 1 for key in effects} | 10 | self._intensities = {key: 1 for key in effects} | ||
| 12 | self._has_been_used = False | 11 | self._has_been_used = False | ||
| 13 | self._has_been_applied = False | 12 | self._has_been_applied = False | ||
| 14 | 13 | ||||
| 15 | def __getattribute__(self, item): | 14 | def __getattribute__(self, item): | ||
| 16 | if object.__getattribute__(self, '_has_been_applied'): | 15 | if object.__getattribute__(self, '_has_been_applied'): | ||
| 17 | raise TypeError('Potion is depleted') | 16 | raise TypeError('Potion is depleted') | ||
| 18 | if object.__getattribute__(self, '_has_been_used'): | 17 | if object.__getattribute__(self, '_has_been_used'): | ||
| 19 | raise TypeError('Potion is now part of something bigger than itself.') | 18 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 20 | 19 | ||||
| 21 | return object.__getattribute__(self, item) | 20 | return object.__getattribute__(self, item) | ||
| 22 | 21 | ||||
| 23 | def __getattr__(self, item): | 22 | def __getattr__(self, item): | ||
| 24 | if self._has_been_applied: | 23 | if self._has_been_applied: | ||
| 25 | raise TypeError('Potion is depleted') | 24 | raise TypeError('Potion is depleted') | ||
| 26 | 25 | ||||
| 27 | if item not in self._effects: | 26 | if item not in self._effects: | ||
| 28 | raise AttributeError('No such effect') | 27 | raise AttributeError('No such effect') | ||
| 29 | 28 | ||||
| 30 | if self._intensities[item] == 0: | 29 | if self._intensities[item] == 0: | ||
| 31 | raise TypeError('Effect is depleted') | 30 | raise TypeError('Effect is depleted') | ||
| 32 | 31 | ||||
| 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | 32 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | ||
| 34 | self._intensities[item] = 0 | 33 | self._intensities[item] = 0 | ||
| 35 | 34 | ||||
| 36 | return effect | 35 | return effect | ||
| 37 | 36 | ||||
| 38 | @staticmethod | 37 | @staticmethod | ||
| 39 | def _intensify_effect(times): | 38 | def _intensify_effect(times): | ||
| 40 | def intensifying_decorator(function): | 39 | def intensifying_decorator(function): | ||
| 41 | def intensifying_wrapper(*args, **kwargs): | 40 | def intensifying_wrapper(*args, **kwargs): | ||
| 42 | for _ in range(times): | 41 | for _ in range(times): | ||
| 43 | function(*args, **kwargs) | 42 | function(*args, **kwargs) | ||
| 44 | 43 | ||||
| 45 | return intensifying_wrapper | 44 | return intensifying_wrapper | ||
| 46 | 45 | ||||
| 47 | return intensifying_decorator | 46 | return intensifying_decorator | ||
| 48 | 47 | ||||
| 49 | @property | 48 | @property | ||
| 50 | def has_been_used(self): | 49 | def has_been_used(self): | ||
| 51 | return self._has_been_used | 50 | return self._has_been_used | ||
| 52 | 51 | ||||
| 53 | @has_been_used.setter | 52 | @has_been_used.setter | ||
| 54 | def has_been_used(self, value): | 53 | def has_been_used(self, value): | ||
| 55 | self._has_been_used = value | 54 | self._has_been_used = value | ||
| 56 | 55 | ||||
| 57 | @property | 56 | @property | ||
| 58 | def has_been_applied(self): | 57 | def has_been_applied(self): | ||
| 59 | return self._has_been_applied | 58 | return self._has_been_applied | ||
| 60 | 59 | ||||
| 61 | @has_been_applied.setter | 60 | @has_been_applied.setter | ||
| 62 | def has_been_applied(self, value): | 61 | def has_been_applied(self, value): | ||
| 63 | self._has_been_applied = value | 62 | self._has_been_applied = value | ||
| 64 | 63 | ||||
| 65 | @property | 64 | @property | ||
| 66 | def duration(self): | 65 | def duration(self): | ||
| 67 | return self._duration | 66 | return self._duration | ||
| 68 | 67 | ||||
| 69 | @duration.setter | 68 | @duration.setter | ||
| 70 | def duration(self, value): | 69 | def duration(self, value): | ||
| 71 | self._duration = value | 70 | self._duration = value | ||
| 72 | 71 | ||||
| 73 | @property | 72 | @property | ||
| 74 | def intensities(self): | 73 | def intensities(self): | ||
| 75 | return self._intensities | 74 | return self._intensities | ||
| 76 | 75 | ||||
| 77 | @intensities.setter | 76 | @intensities.setter | ||
| 78 | def intensities(self, value): | 77 | def intensities(self, value): | ||
| 79 | self._intensities = value | 78 | self._intensities = value | ||
| 80 | 79 | ||||
| 81 | @property | 80 | @property | ||
| 82 | def effects(self): | 81 | def effects(self): | ||
| 83 | return self._effects | 82 | return self._effects | ||
| 84 | 83 | ||||
| 85 | @effects.setter | 84 | @effects.setter | ||
| 86 | def effects(self, value): | 85 | def effects(self, value): | ||
| 87 | self._effects = value | 86 | self._effects = value | ||
| 88 | 87 | ||||
| 89 | def __add__(self, other): | 88 | def __add__(self, other): | ||
| 90 | new_effects = self._combine_effects(other) | 89 | new_effects = self._combine_effects(other) | ||
| 91 | new_intensities = self._combine_intensities(other) | 90 | new_intensities = self._combine_intensities(other) | ||
| 92 | 91 | ||||
| 93 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | 92 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | ||
| 94 | new_potion._intensities = new_intensities | 93 | new_potion._intensities = new_intensities | ||
| 95 | 94 | ||||
| 96 | self.has_been_used = True | 95 | self.has_been_used = True | ||
| 97 | other.has_been_used = True | 96 | other.has_been_used = True | ||
| 98 | 97 | ||||
| 99 | return new_potion | 98 | return new_potion | ||
| 100 | 99 | ||||
| 101 | def _combine_effects(self, other): | 100 | def _combine_effects(self, other): | ||
| 102 | new_effects = {} | 101 | new_effects = {} | ||
| 103 | 102 | ||||
| 104 | for key, value in self.effects.items(): | 103 | for key, value in self.effects.items(): | ||
| 105 | new_effects[key] = value | 104 | new_effects[key] = value | ||
| 106 | 105 | ||||
| 107 | for key, value in other.effects.items(): | 106 | for key, value in other.effects.items(): | ||
| 108 | new_effects[key] = value | 107 | new_effects[key] = value | ||
| 109 | 108 | ||||
| 110 | return new_effects | 109 | return new_effects | ||
| 111 | 110 | ||||
| 112 | def _combine_intensities(self, other): | 111 | def _combine_intensities(self, other): | ||
| 113 | new_intensities = {} | 112 | new_intensities = {} | ||
| 114 | 113 | ||||
| 115 | for key, value in self._intensities.items(): | 114 | for key, value in self._intensities.items(): | ||
| 116 | new_intensities[key] = value | 115 | new_intensities[key] = value | ||
| 117 | 116 | ||||
| 118 | for key, value in other.intensities.items(): | 117 | for key, value in other.intensities.items(): | ||
| 119 | if key in new_intensities: | 118 | if key in new_intensities: | ||
| 120 | new_intensities[key] += value | 119 | new_intensities[key] += value | ||
| 121 | else: | 120 | else: | ||
| 122 | new_intensities[key] = value | 121 | new_intensities[key] = value | ||
| 123 | 122 | ||||
| 124 | return new_intensities | 123 | return new_intensities | ||
| 125 | 124 | ||||
| 126 | def __mul__(self, other): | 125 | def __mul__(self, other): | ||
| 127 | updated_intensities = {} | 126 | updated_intensities = {} | ||
| 128 | 127 | ||||
| 129 | if isinstance(other, int): | 128 | if isinstance(other, int): | ||
| 130 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | 129 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | ||
| 131 | elif isinstance(other, float) and 0 <= other <= 1: | 130 | elif isinstance(other, float) and 0 <= other <= 1: | ||
| 132 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | 131 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | ||
| 133 | 132 | ||||
| 134 | new_potion = Potion(self._effects, self._duration) | 133 | new_potion = Potion(self._effects, self._duration) | ||
| 135 | new_potion._intensities = updated_intensities | 134 | new_potion._intensities = updated_intensities | ||
| 136 | 135 | ||||
| 137 | self.has_been_used = True | 136 | self.has_been_used = True | ||
| 138 | 137 | ||||
| 139 | return new_potion | 138 | return new_potion | ||
| 140 | 139 | ||||
| 141 | @staticmethod | 140 | @staticmethod | ||
| 142 | def _round_to_whole(real): | 141 | def _round_to_whole(real): | ||
| 143 | fraction = real - math.floor(real) | 142 | fraction = real - math.floor(real) | ||
| 144 | 143 | ||||
| 145 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | 144 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | ||
| 146 | 145 | ||||
| 147 | def __sub__(self, other): | 146 | def __sub__(self, other): | ||
| 148 | if set(other.effects.keys()) - set(self._effects.keys()): | 147 | if set(other.effects.keys()) - set(self._effects.keys()): | ||
| 149 | raise TypeError('съдържанието няма значение') | 148 | raise TypeError('съдържанието няма значение') | ||
| 150 | 149 | ||||
| 151 | new_effects = {} | 150 | new_effects = {} | ||
| 152 | new_intensities = {} | 151 | new_intensities = {} | ||
| 153 | 152 | ||||
| 154 | for name, intensity in self._intensities.items(): | 153 | for name, intensity in self._intensities.items(): | ||
| 155 | if name not in other.intensities: | 154 | if name not in other.intensities: | ||
| 156 | new_effects[name] = self._effects[name] | 155 | new_effects[name] = self._effects[name] | ||
| 157 | new_intensities[name] = intensity | 156 | new_intensities[name] = intensity | ||
| 158 | else: | 157 | else: | ||
| 159 | difference = intensity - other.intensities[name] | 158 | difference = intensity - other.intensities[name] | ||
| 160 | if difference > 0: | 159 | if difference > 0: | ||
| 161 | new_effects[name] = self._effects[name] | 160 | new_effects[name] = self._effects[name] | ||
| 162 | new_intensities[name] = difference | 161 | new_intensities[name] = difference | ||
| 163 | 162 | ||||
| 164 | new_potion = Potion(new_effects, self._duration) | 163 | new_potion = Potion(new_effects, self._duration) | ||
| 165 | new_potion._intensities = new_intensities | 164 | new_potion._intensities = new_intensities | ||
| 166 | 165 | ||||
| 167 | self.has_been_used = True | 166 | self.has_been_used = True | ||
| 168 | other.has_been_used = True | 167 | other.has_been_used = True | ||
| 169 | 168 | ||||
| 170 | return new_potion | 169 | return new_potion | ||
| 171 | 170 | ||||
| 172 | def __truediv__(self, other): | 171 | def __truediv__(self, other): | ||
| 173 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | 172 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | ||
| 174 | 173 | ||||
| 175 | new_potion = Potion(self._effects, self._duration) | 174 | new_potion = Potion(self._effects, self._duration) | ||
| 176 | new_potion._intensities = updated_intensities | 175 | new_potion._intensities = updated_intensities | ||
| 177 | 176 | ||||
| 178 | self.has_been_used = True | 177 | self.has_been_used = True | ||
| 179 | 178 | ||||
| 180 | return tuple(deepcopy(new_potion) for _ in range(other)) | 179 | return tuple(deepcopy(new_potion) for _ in range(other)) | ||
| 181 | 180 | ||||
| 182 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | 181 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | ||
| 183 | def __deepcopy__(self, memodict={}): | 182 | def __deepcopy__(self, memodict={}): | ||
| 184 | cls = self.__class__ | 183 | cls = self.__class__ | ||
| 185 | new_object = cls.__new__(cls) | 184 | new_object = cls.__new__(cls) | ||
| 186 | memodict[id(self)] = new_object | 185 | memodict[id(self)] = new_object | ||
| 187 | for key, value in self.__dict__.items(): | 186 | for key, value in self.__dict__.items(): | ||
| 188 | setattr(new_object, key, deepcopy(value, memodict)) | 187 | setattr(new_object, key, deepcopy(value, memodict)) | ||
| 189 | return new_object | 188 | return new_object | ||
| 190 | 189 | ||||
| 191 | def __eq__(self, other): | 190 | def __eq__(self, other): | ||
| 192 | return self._effects == other.effects and self._intensities == other.intensities | 191 | return self._effects == other.effects and self._intensities == other.intensities | ||
| 193 | 192 | ||||
| 194 | def __gt__(self, other): | 193 | def __gt__(self, other): | ||
| 195 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | 194 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | ||
| 196 | 195 | ||||
| 197 | def __lt__(self, other): | 196 | def __lt__(self, other): | ||
| 198 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | 197 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | ||
| 199 | 198 | ||||
| 200 | def get_applied(self, target): | 199 | def get_applied(self, target): | ||
| 201 | effects_map, masses = self._ordered_by_mass() | 200 | effects_map, masses = self._ordered_by_mass() | ||
| 202 | 201 | ||||
| 203 | for mass in masses: | 202 | for mass in masses: | ||
| 204 | name = effects_map[mass] | 203 | name = effects_map[mass] | ||
| 205 | if self._intensities[name] > 0: | 204 | if self._intensities[name] > 0: | ||
| 206 | effect = getattr(self, name) | 205 | effect = getattr(self, name) | ||
| 207 | effect(target) | 206 | effect(target) | ||
| 208 | 207 | ||||
| 209 | self.has_been_applied = True | 208 | self.has_been_applied = True | ||
| 210 | 209 | ||||
| 211 | def _ordered_by_mass(self): | 210 | def _ordered_by_mass(self): | ||
| 212 | effects_map = {self._get_mass(key): key for key in self._effects} | 211 | effects_map = {self._get_mass(key): key for key in self._effects} | ||
| 213 | masses = list(effects_map.keys()) | 212 | masses = list(effects_map.keys()) | ||
| 214 | masses.sort(reverse=True) | 213 | masses.sort(reverse=True) | ||
| 215 | 214 | ||||
| 216 | return effects_map, masses | 215 | return effects_map, masses | ||
| 217 | 216 | ||||
| 218 | @staticmethod | 217 | @staticmethod | ||
| 219 | def _get_mass(effect_name): | 218 | def _get_mass(effect_name): | ||
| 220 | return sum(map(ord, effect_name)) | 219 | return sum(map(ord, effect_name)) | ||
| 221 | 220 | ||||
| 222 | # Generated by IDE | 221 | # Generated by IDE | ||
| 223 | def __hash__(self): | 222 | def __hash__(self): | ||
| 224 | return super().__hash__() | 223 | return super().__hash__() | ||
| 225 | 224 | ||||
| 226 | 225 | ||||
| 227 | class ГоспожатаПоХимия: | 226 | class ГоспожатаПоХимия: | ||
| 228 | def __init__(self): | 227 | def __init__(self): | ||
| 229 | self._durations = {} | 228 | self._durations = {} | ||
| 230 | self._states = {} | 229 | self._states = {} | ||
| 231 | self._potions_on_targets = {} | 230 | self._potions_on_targets = {} | ||
| 232 | self._original_potions = {} | 231 | self._original_potions = {} | ||
| 233 | 232 | ||||
| 234 | def apply(self, target, potion): | 233 | def apply(self, target, potion): | ||
| 235 | self._durations[potion] = potion.duration | 234 | self._durations[potion] = potion.duration | ||
| 236 | 235 | ||||
| 237 | if target in self._potions_on_targets.values(): | 236 | if target in self._potions_on_targets.values(): | ||
| 238 | for key, value in self._potions_on_targets.items(): | 237 | for key, value in self._potions_on_targets.items(): | ||
| 239 | if value == target: | 238 | if value == target: | ||
| 240 | self._states[potion] = self._states[key] | 239 | self._states[potion] = self._states[key] | ||
| 241 | break | 240 | break | ||
| 242 | else: | 241 | else: | ||
| 243 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | 242 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | ||
| 244 | self._states[potion] = {name: getattr(target, name) for name in states_names} | 243 | self._states[potion] = {name: getattr(target, name) for name in states_names} | ||
| 245 | 244 | ||||
| 246 | self._potions_on_targets[potion] = target | 245 | self._potions_on_targets[potion] = target | ||
| t | 247 | self._original_potions[potion] = copy.deepcopy(potion) | t | 246 | self._original_potions[potion] = deepcopy(potion) |
| 248 | 247 | ||||
| 249 | self._apply(target, potion) | 248 | self._apply(target, potion) | ||
| 250 | 249 | ||||
| 251 | @staticmethod | 250 | @staticmethod | ||
| 252 | def _apply(target, potion): | 251 | def _apply(target, potion): | ||
| 253 | potion.get_applied(target) | 252 | potion.get_applied(target) | ||
| 254 | 253 | ||||
| 255 | def tick(self): | 254 | def tick(self): | ||
| 256 | for potion in self._durations: | 255 | for potion in self._durations: | ||
| 257 | self._durations[potion] -= 1 | 256 | self._durations[potion] -= 1 | ||
| 258 | 257 | ||||
| 259 | expired_potions = [key for key, value in self._durations.items() if value == 0] | 258 | expired_potions = [key for key, value in self._durations.items() if value == 0] | ||
| 260 | 259 | ||||
| 261 | used_targets = [] | 260 | used_targets = [] | ||
| 262 | for potion in expired_potions: | 261 | for potion in expired_potions: | ||
| 263 | for attribute, value in self._states[potion].items(): | 262 | for attribute, value in self._states[potion].items(): | ||
| 264 | setattr(self._potions_on_targets[potion], attribute, value) | 263 | setattr(self._potions_on_targets[potion], attribute, value) | ||
| 265 | 264 | ||||
| 266 | used_targets.append(self._potions_on_targets[potion]) | 265 | used_targets.append(self._potions_on_targets[potion]) | ||
| 267 | 266 | ||||
| 268 | del self._durations[potion] | 267 | del self._durations[potion] | ||
| 269 | del self._potions_on_targets[potion] | 268 | del self._potions_on_targets[potion] | ||
| 270 | del self._states[potion] | 269 | del self._states[potion] | ||
| 271 | del self._original_potions[potion] | 270 | del self._original_potions[potion] | ||
| 272 | 271 | ||||
| 273 | for used_target in used_targets: | 272 | for used_target in used_targets: | ||
| 274 | for potion, target in self._potions_on_targets.items(): | 273 | for potion, target in self._potions_on_targets.items(): | ||
| 275 | if used_target == target: | 274 | if used_target == target: | ||
| 276 | self._apply(target, self._original_potions[potion]) | 275 | self._apply(target, self._original_potions[potion]) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import copy | f | 1 | import copy |
| 2 | import math | 2 | import math | ||
| 3 | import re | 3 | import re | ||
| 4 | from copy import deepcopy | 4 | from copy import deepcopy | ||
| 5 | 5 | ||||
| 6 | 6 | ||||
| 7 | class Potion: | 7 | class Potion: | ||
| n | 8 | def __init__(self, _effects, duration): | n | 8 | def __init__(self, effects, duration): |
| 9 | self._effects = _effects | 9 | self._effects = effects | ||
| 10 | self._duration = duration | 10 | self._duration = duration | ||
| t | 11 | self._intensities = {key: 1 for key in _effects} | t | 11 | self._intensities = {key: 1 for key in effects} |
| 12 | self._has_been_used = False | 12 | self._has_been_used = False | ||
| 13 | self._has_been_applied = False | 13 | self._has_been_applied = False | ||
| 14 | 14 | ||||
| 15 | def __getattribute__(self, item): | 15 | def __getattribute__(self, item): | ||
| 16 | if object.__getattribute__(self, '_has_been_applied'): | 16 | if object.__getattribute__(self, '_has_been_applied'): | ||
| 17 | raise TypeError('Potion is depleted') | 17 | raise TypeError('Potion is depleted') | ||
| 18 | if object.__getattribute__(self, '_has_been_used'): | 18 | if object.__getattribute__(self, '_has_been_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.') | ||
| 20 | 20 | ||||
| 21 | return object.__getattribute__(self, item) | 21 | return object.__getattribute__(self, item) | ||
| 22 | 22 | ||||
| 23 | def __getattr__(self, item): | 23 | def __getattr__(self, item): | ||
| 24 | if self._has_been_applied: | 24 | if self._has_been_applied: | ||
| 25 | raise TypeError('Potion is depleted') | 25 | raise TypeError('Potion is depleted') | ||
| 26 | 26 | ||||
| 27 | if item not in self._effects: | 27 | if item not in self._effects: | ||
| 28 | raise AttributeError('No such effect') | 28 | raise AttributeError('No such effect') | ||
| 29 | 29 | ||||
| 30 | if self._intensities[item] == 0: | 30 | if self._intensities[item] == 0: | ||
| 31 | raise TypeError('Effect is depleted') | 31 | raise TypeError('Effect is depleted') | ||
| 32 | 32 | ||||
| 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | ||
| 34 | self._intensities[item] = 0 | 34 | self._intensities[item] = 0 | ||
| 35 | 35 | ||||
| 36 | return effect | 36 | return effect | ||
| 37 | 37 | ||||
| 38 | @staticmethod | 38 | @staticmethod | ||
| 39 | def _intensify_effect(times): | 39 | def _intensify_effect(times): | ||
| 40 | def intensifying_decorator(function): | 40 | def intensifying_decorator(function): | ||
| 41 | def intensifying_wrapper(*args, **kwargs): | 41 | def intensifying_wrapper(*args, **kwargs): | ||
| 42 | for _ in range(times): | 42 | for _ in range(times): | ||
| 43 | function(*args, **kwargs) | 43 | function(*args, **kwargs) | ||
| 44 | 44 | ||||
| 45 | return intensifying_wrapper | 45 | return intensifying_wrapper | ||
| 46 | 46 | ||||
| 47 | return intensifying_decorator | 47 | return intensifying_decorator | ||
| 48 | 48 | ||||
| 49 | @property | 49 | @property | ||
| 50 | def has_been_used(self): | 50 | def has_been_used(self): | ||
| 51 | return self._has_been_used | 51 | return self._has_been_used | ||
| 52 | 52 | ||||
| 53 | @has_been_used.setter | 53 | @has_been_used.setter | ||
| 54 | def has_been_used(self, value): | 54 | def has_been_used(self, value): | ||
| 55 | self._has_been_used = value | 55 | self._has_been_used = value | ||
| 56 | 56 | ||||
| 57 | @property | 57 | @property | ||
| 58 | def has_been_applied(self): | 58 | def has_been_applied(self): | ||
| 59 | return self._has_been_applied | 59 | return self._has_been_applied | ||
| 60 | 60 | ||||
| 61 | @has_been_applied.setter | 61 | @has_been_applied.setter | ||
| 62 | def has_been_applied(self, value): | 62 | def has_been_applied(self, value): | ||
| 63 | self._has_been_applied = value | 63 | self._has_been_applied = value | ||
| 64 | 64 | ||||
| 65 | @property | 65 | @property | ||
| 66 | def duration(self): | 66 | def duration(self): | ||
| 67 | return self._duration | 67 | return self._duration | ||
| 68 | 68 | ||||
| 69 | @duration.setter | 69 | @duration.setter | ||
| 70 | def duration(self, value): | 70 | def duration(self, value): | ||
| 71 | self._duration = value | 71 | self._duration = value | ||
| 72 | 72 | ||||
| 73 | @property | 73 | @property | ||
| 74 | def intensities(self): | 74 | def intensities(self): | ||
| 75 | return self._intensities | 75 | return self._intensities | ||
| 76 | 76 | ||||
| 77 | @intensities.setter | 77 | @intensities.setter | ||
| 78 | def intensities(self, value): | 78 | def intensities(self, value): | ||
| 79 | self._intensities = value | 79 | self._intensities = value | ||
| 80 | 80 | ||||
| 81 | @property | 81 | @property | ||
| 82 | def effects(self): | 82 | def effects(self): | ||
| 83 | return self._effects | 83 | return self._effects | ||
| 84 | 84 | ||||
| 85 | @effects.setter | 85 | @effects.setter | ||
| 86 | def effects(self, value): | 86 | def effects(self, value): | ||
| 87 | self._effects = value | 87 | self._effects = value | ||
| 88 | 88 | ||||
| 89 | def __add__(self, other): | 89 | def __add__(self, other): | ||
| 90 | new_effects = self._combine_effects(other) | 90 | new_effects = self._combine_effects(other) | ||
| 91 | new_intensities = self._combine_intensities(other) | 91 | new_intensities = self._combine_intensities(other) | ||
| 92 | 92 | ||||
| 93 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | 93 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | ||
| 94 | new_potion._intensities = new_intensities | 94 | new_potion._intensities = new_intensities | ||
| 95 | 95 | ||||
| 96 | self.has_been_used = True | 96 | self.has_been_used = True | ||
| 97 | other.has_been_used = True | 97 | other.has_been_used = True | ||
| 98 | 98 | ||||
| 99 | return new_potion | 99 | return new_potion | ||
| 100 | 100 | ||||
| 101 | def _combine_effects(self, other): | 101 | def _combine_effects(self, other): | ||
| 102 | new_effects = {} | 102 | new_effects = {} | ||
| 103 | 103 | ||||
| 104 | for key, value in self.effects.items(): | 104 | for key, value in self.effects.items(): | ||
| 105 | new_effects[key] = value | 105 | new_effects[key] = value | ||
| 106 | 106 | ||||
| 107 | for key, value in other.effects.items(): | 107 | for key, value in other.effects.items(): | ||
| 108 | new_effects[key] = value | 108 | new_effects[key] = value | ||
| 109 | 109 | ||||
| 110 | return new_effects | 110 | return new_effects | ||
| 111 | 111 | ||||
| 112 | def _combine_intensities(self, other): | 112 | def _combine_intensities(self, other): | ||
| 113 | new_intensities = {} | 113 | new_intensities = {} | ||
| 114 | 114 | ||||
| 115 | for key, value in self._intensities.items(): | 115 | for key, value in self._intensities.items(): | ||
| 116 | new_intensities[key] = value | 116 | new_intensities[key] = value | ||
| 117 | 117 | ||||
| 118 | for key, value in other.intensities.items(): | 118 | for key, value in other.intensities.items(): | ||
| 119 | if key in new_intensities: | 119 | if key in new_intensities: | ||
| 120 | new_intensities[key] += value | 120 | new_intensities[key] += value | ||
| 121 | else: | 121 | else: | ||
| 122 | new_intensities[key] = value | 122 | new_intensities[key] = value | ||
| 123 | 123 | ||||
| 124 | return new_intensities | 124 | return new_intensities | ||
| 125 | 125 | ||||
| 126 | def __mul__(self, other): | 126 | def __mul__(self, other): | ||
| 127 | updated_intensities = {} | 127 | updated_intensities = {} | ||
| 128 | 128 | ||||
| 129 | if isinstance(other, int): | 129 | if isinstance(other, int): | ||
| 130 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | 130 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | ||
| 131 | elif isinstance(other, float) and 0 <= other <= 1: | 131 | elif isinstance(other, float) and 0 <= other <= 1: | ||
| 132 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | 132 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | ||
| 133 | 133 | ||||
| 134 | new_potion = Potion(self._effects, self._duration) | 134 | new_potion = Potion(self._effects, self._duration) | ||
| 135 | new_potion._intensities = updated_intensities | 135 | new_potion._intensities = updated_intensities | ||
| 136 | 136 | ||||
| 137 | self.has_been_used = True | 137 | self.has_been_used = True | ||
| 138 | 138 | ||||
| 139 | return new_potion | 139 | return new_potion | ||
| 140 | 140 | ||||
| 141 | @staticmethod | 141 | @staticmethod | ||
| 142 | def _round_to_whole(real): | 142 | def _round_to_whole(real): | ||
| 143 | fraction = real - math.floor(real) | 143 | fraction = real - math.floor(real) | ||
| 144 | 144 | ||||
| 145 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | 145 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | ||
| 146 | 146 | ||||
| 147 | def __sub__(self, other): | 147 | def __sub__(self, other): | ||
| 148 | if set(other.effects.keys()) - set(self._effects.keys()): | 148 | if set(other.effects.keys()) - set(self._effects.keys()): | ||
| 149 | raise TypeError('съдържанието няма значение') | 149 | raise TypeError('съдържанието няма значение') | ||
| 150 | 150 | ||||
| 151 | new_effects = {} | 151 | new_effects = {} | ||
| 152 | new_intensities = {} | 152 | new_intensities = {} | ||
| 153 | 153 | ||||
| 154 | for name, intensity in self._intensities.items(): | 154 | for name, intensity in self._intensities.items(): | ||
| 155 | if name not in other.intensities: | 155 | if name not in other.intensities: | ||
| 156 | new_effects[name] = self._effects[name] | 156 | new_effects[name] = self._effects[name] | ||
| 157 | new_intensities[name] = intensity | 157 | new_intensities[name] = intensity | ||
| 158 | else: | 158 | else: | ||
| 159 | difference = intensity - other.intensities[name] | 159 | difference = intensity - other.intensities[name] | ||
| 160 | if difference > 0: | 160 | if difference > 0: | ||
| 161 | new_effects[name] = self._effects[name] | 161 | new_effects[name] = self._effects[name] | ||
| 162 | new_intensities[name] = difference | 162 | new_intensities[name] = difference | ||
| 163 | 163 | ||||
| 164 | new_potion = Potion(new_effects, self._duration) | 164 | new_potion = Potion(new_effects, self._duration) | ||
| 165 | new_potion._intensities = new_intensities | 165 | new_potion._intensities = new_intensities | ||
| 166 | 166 | ||||
| 167 | self.has_been_used = True | 167 | self.has_been_used = True | ||
| 168 | other.has_been_used = True | 168 | other.has_been_used = True | ||
| 169 | 169 | ||||
| 170 | return new_potion | 170 | return new_potion | ||
| 171 | 171 | ||||
| 172 | def __truediv__(self, other): | 172 | def __truediv__(self, other): | ||
| 173 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | 173 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | ||
| 174 | 174 | ||||
| 175 | new_potion = Potion(self._effects, self._duration) | 175 | new_potion = Potion(self._effects, self._duration) | ||
| 176 | new_potion._intensities = updated_intensities | 176 | new_potion._intensities = updated_intensities | ||
| 177 | 177 | ||||
| 178 | self.has_been_used = True | 178 | self.has_been_used = True | ||
| 179 | 179 | ||||
| 180 | return tuple(deepcopy(new_potion) for _ in range(other)) | 180 | return tuple(deepcopy(new_potion) for _ in range(other)) | ||
| 181 | 181 | ||||
| 182 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | 182 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation | ||
| 183 | def __deepcopy__(self, memodict={}): | 183 | def __deepcopy__(self, memodict={}): | ||
| 184 | cls = self.__class__ | 184 | cls = self.__class__ | ||
| 185 | new_object = cls.__new__(cls) | 185 | new_object = cls.__new__(cls) | ||
| 186 | memodict[id(self)] = new_object | 186 | memodict[id(self)] = new_object | ||
| 187 | for key, value in self.__dict__.items(): | 187 | for key, value in self.__dict__.items(): | ||
| 188 | setattr(new_object, key, deepcopy(value, memodict)) | 188 | setattr(new_object, key, deepcopy(value, memodict)) | ||
| 189 | return new_object | 189 | return new_object | ||
| 190 | 190 | ||||
| 191 | def __eq__(self, other): | 191 | def __eq__(self, other): | ||
| 192 | return self._effects == other.effects and self._intensities == other.intensities | 192 | return self._effects == other.effects and self._intensities == other.intensities | ||
| 193 | 193 | ||||
| 194 | def __gt__(self, other): | 194 | def __gt__(self, other): | ||
| 195 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | 195 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | ||
| 196 | 196 | ||||
| 197 | def __lt__(self, other): | 197 | def __lt__(self, other): | ||
| 198 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | 198 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | ||
| 199 | 199 | ||||
| 200 | def get_applied(self, target): | 200 | def get_applied(self, target): | ||
| 201 | effects_map, masses = self._ordered_by_mass() | 201 | effects_map, masses = self._ordered_by_mass() | ||
| 202 | 202 | ||||
| 203 | for mass in masses: | 203 | for mass in masses: | ||
| 204 | name = effects_map[mass] | 204 | name = effects_map[mass] | ||
| 205 | if self._intensities[name] > 0: | 205 | if self._intensities[name] > 0: | ||
| 206 | effect = getattr(self, name) | 206 | effect = getattr(self, name) | ||
| 207 | effect(target) | 207 | effect(target) | ||
| 208 | 208 | ||||
| 209 | self.has_been_applied = True | 209 | self.has_been_applied = True | ||
| 210 | 210 | ||||
| 211 | def _ordered_by_mass(self): | 211 | def _ordered_by_mass(self): | ||
| 212 | effects_map = {self._get_mass(key): key for key in self._effects} | 212 | effects_map = {self._get_mass(key): key for key in self._effects} | ||
| 213 | masses = list(effects_map.keys()) | 213 | masses = list(effects_map.keys()) | ||
| 214 | masses.sort(reverse=True) | 214 | masses.sort(reverse=True) | ||
| 215 | 215 | ||||
| 216 | return effects_map, masses | 216 | return effects_map, masses | ||
| 217 | 217 | ||||
| 218 | @staticmethod | 218 | @staticmethod | ||
| 219 | def _get_mass(effect_name): | 219 | def _get_mass(effect_name): | ||
| 220 | return sum(map(ord, effect_name)) | 220 | return sum(map(ord, effect_name)) | ||
| 221 | 221 | ||||
| 222 | # Generated by IDE | 222 | # Generated by IDE | ||
| 223 | def __hash__(self): | 223 | def __hash__(self): | ||
| 224 | return super().__hash__() | 224 | return super().__hash__() | ||
| 225 | 225 | ||||
| 226 | 226 | ||||
| 227 | class ГоспожатаПоХимия: | 227 | class ГоспожатаПоХимия: | ||
| 228 | def __init__(self): | 228 | def __init__(self): | ||
| 229 | self._durations = {} | 229 | self._durations = {} | ||
| 230 | self._states = {} | 230 | self._states = {} | ||
| 231 | self._potions_on_targets = {} | 231 | self._potions_on_targets = {} | ||
| 232 | self._original_potions = {} | 232 | self._original_potions = {} | ||
| 233 | 233 | ||||
| 234 | def apply(self, target, potion): | 234 | def apply(self, target, potion): | ||
| 235 | self._durations[potion] = potion.duration | 235 | self._durations[potion] = potion.duration | ||
| 236 | 236 | ||||
| 237 | if target in self._potions_on_targets.values(): | 237 | if target in self._potions_on_targets.values(): | ||
| 238 | for key, value in self._potions_on_targets.items(): | 238 | for key, value in self._potions_on_targets.items(): | ||
| 239 | if value == target: | 239 | if value == target: | ||
| 240 | self._states[potion] = self._states[key] | 240 | self._states[potion] = self._states[key] | ||
| 241 | break | 241 | break | ||
| 242 | else: | 242 | else: | ||
| 243 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | 243 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | ||
| 244 | self._states[potion] = {name: getattr(target, name) for name in states_names} | 244 | self._states[potion] = {name: getattr(target, name) for name in states_names} | ||
| 245 | 245 | ||||
| 246 | self._potions_on_targets[potion] = target | 246 | self._potions_on_targets[potion] = target | ||
| 247 | self._original_potions[potion] = copy.deepcopy(potion) | 247 | self._original_potions[potion] = copy.deepcopy(potion) | ||
| 248 | 248 | ||||
| 249 | self._apply(target, potion) | 249 | self._apply(target, potion) | ||
| 250 | 250 | ||||
| 251 | @staticmethod | 251 | @staticmethod | ||
| 252 | def _apply(target, potion): | 252 | def _apply(target, potion): | ||
| 253 | potion.get_applied(target) | 253 | potion.get_applied(target) | ||
| 254 | 254 | ||||
| 255 | def tick(self): | 255 | def tick(self): | ||
| 256 | for potion in self._durations: | 256 | for potion in self._durations: | ||
| 257 | self._durations[potion] -= 1 | 257 | self._durations[potion] -= 1 | ||
| 258 | 258 | ||||
| 259 | expired_potions = [key for key, value in self._durations.items() if value == 0] | 259 | expired_potions = [key for key, value in self._durations.items() if value == 0] | ||
| 260 | 260 | ||||
| 261 | used_targets = [] | 261 | used_targets = [] | ||
| 262 | for potion in expired_potions: | 262 | for potion in expired_potions: | ||
| 263 | for attribute, value in self._states[potion].items(): | 263 | for attribute, value in self._states[potion].items(): | ||
| 264 | setattr(self._potions_on_targets[potion], attribute, value) | 264 | setattr(self._potions_on_targets[potion], attribute, value) | ||
| 265 | 265 | ||||
| 266 | used_targets.append(self._potions_on_targets[potion]) | 266 | used_targets.append(self._potions_on_targets[potion]) | ||
| 267 | 267 | ||||
| 268 | del self._durations[potion] | 268 | del self._durations[potion] | ||
| 269 | del self._potions_on_targets[potion] | 269 | del self._potions_on_targets[potion] | ||
| 270 | del self._states[potion] | 270 | del self._states[potion] | ||
| 271 | del self._original_potions[potion] | 271 | del self._original_potions[potion] | ||
| 272 | 272 | ||||
| 273 | for used_target in used_targets: | 273 | for used_target in used_targets: | ||
| 274 | for potion, target in self._potions_on_targets.items(): | 274 | for potion, target in self._potions_on_targets.items(): | ||
| 275 | if used_target == target: | 275 | if used_target == target: | ||
| 276 | self._apply(target, self._original_potions[potion]) | 276 | self._apply(target, self._original_potions[potion]) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import copy | f | 1 | import copy |
| 2 | import math | 2 | import math | ||
| 3 | import re | 3 | import re | ||
| 4 | from copy import deepcopy | 4 | from copy import deepcopy | ||
| 5 | 5 | ||||
| 6 | 6 | ||||
| 7 | class Potion: | 7 | class Potion: | ||
| 8 | def __init__(self, _effects, duration): | 8 | def __init__(self, _effects, duration): | ||
| 9 | self._effects = _effects | 9 | self._effects = _effects | ||
| 10 | self._duration = duration | 10 | self._duration = duration | ||
| 11 | self._intensities = {key: 1 for key in _effects} | 11 | self._intensities = {key: 1 for key in _effects} | ||
| 12 | self._has_been_used = False | 12 | self._has_been_used = False | ||
| 13 | self._has_been_applied = False | 13 | self._has_been_applied = False | ||
| 14 | 14 | ||||
| 15 | def __getattribute__(self, item): | 15 | def __getattribute__(self, item): | ||
| 16 | if object.__getattribute__(self, '_has_been_applied'): | 16 | if object.__getattribute__(self, '_has_been_applied'): | ||
| 17 | raise TypeError('Potion is depleted') | 17 | raise TypeError('Potion is depleted') | ||
| 18 | if object.__getattribute__(self, '_has_been_used'): | 18 | if object.__getattribute__(self, '_has_been_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.') | ||
| 20 | 20 | ||||
| 21 | return object.__getattribute__(self, item) | 21 | return object.__getattribute__(self, item) | ||
| 22 | 22 | ||||
| 23 | def __getattr__(self, item): | 23 | def __getattr__(self, item): | ||
| 24 | if self._has_been_applied: | 24 | if self._has_been_applied: | ||
| 25 | raise TypeError('Potion is depleted') | 25 | raise TypeError('Potion is depleted') | ||
| 26 | 26 | ||||
| 27 | if item not in self._effects: | 27 | if item not in self._effects: | ||
| 28 | raise AttributeError('No such effect') | 28 | raise AttributeError('No such effect') | ||
| 29 | 29 | ||||
| 30 | if self._intensities[item] == 0: | 30 | if self._intensities[item] == 0: | ||
| 31 | raise TypeError('Effect is depleted') | 31 | raise TypeError('Effect is depleted') | ||
| 32 | 32 | ||||
| 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | 33 | effect = self._intensify_effect(self._intensities[item])(self._effects[item]) | ||
| 34 | self._intensities[item] = 0 | 34 | self._intensities[item] = 0 | ||
| 35 | 35 | ||||
| 36 | return effect | 36 | return effect | ||
| 37 | 37 | ||||
| 38 | @staticmethod | 38 | @staticmethod | ||
| 39 | def _intensify_effect(times): | 39 | def _intensify_effect(times): | ||
| 40 | def intensifying_decorator(function): | 40 | def intensifying_decorator(function): | ||
| 41 | def intensifying_wrapper(*args, **kwargs): | 41 | def intensifying_wrapper(*args, **kwargs): | ||
| 42 | for _ in range(times): | 42 | for _ in range(times): | ||
| 43 | function(*args, **kwargs) | 43 | function(*args, **kwargs) | ||
| 44 | 44 | ||||
| 45 | return intensifying_wrapper | 45 | return intensifying_wrapper | ||
| 46 | 46 | ||||
| 47 | return intensifying_decorator | 47 | return intensifying_decorator | ||
| 48 | 48 | ||||
| 49 | @property | 49 | @property | ||
| 50 | def has_been_used(self): | 50 | def has_been_used(self): | ||
| 51 | return self._has_been_used | 51 | return self._has_been_used | ||
| 52 | 52 | ||||
| 53 | @has_been_used.setter | 53 | @has_been_used.setter | ||
| 54 | def has_been_used(self, value): | 54 | def has_been_used(self, value): | ||
| 55 | self._has_been_used = value | 55 | self._has_been_used = value | ||
| 56 | 56 | ||||
| 57 | @property | 57 | @property | ||
| 58 | def has_been_applied(self): | 58 | def has_been_applied(self): | ||
| 59 | return self._has_been_applied | 59 | return self._has_been_applied | ||
| 60 | 60 | ||||
| 61 | @has_been_applied.setter | 61 | @has_been_applied.setter | ||
| 62 | def has_been_applied(self, value): | 62 | def has_been_applied(self, value): | ||
| 63 | self._has_been_applied = value | 63 | self._has_been_applied = value | ||
| 64 | 64 | ||||
| 65 | @property | 65 | @property | ||
| 66 | def duration(self): | 66 | def duration(self): | ||
| 67 | return self._duration | 67 | return self._duration | ||
| 68 | 68 | ||||
| 69 | @duration.setter | 69 | @duration.setter | ||
| 70 | def duration(self, value): | 70 | def duration(self, value): | ||
| 71 | self._duration = value | 71 | self._duration = value | ||
| 72 | 72 | ||||
| 73 | @property | 73 | @property | ||
| 74 | def intensities(self): | 74 | def intensities(self): | ||
| 75 | return self._intensities | 75 | return self._intensities | ||
| 76 | 76 | ||||
| 77 | @intensities.setter | 77 | @intensities.setter | ||
| 78 | def intensities(self, value): | 78 | def intensities(self, value): | ||
| 79 | self._intensities = value | 79 | self._intensities = value | ||
| 80 | 80 | ||||
| 81 | @property | 81 | @property | ||
| 82 | def effects(self): | 82 | def effects(self): | ||
| 83 | return self._effects | 83 | return self._effects | ||
| 84 | 84 | ||||
| 85 | @effects.setter | 85 | @effects.setter | ||
| 86 | def effects(self, value): | 86 | def effects(self, value): | ||
| 87 | self._effects = value | 87 | self._effects = value | ||
| 88 | 88 | ||||
| 89 | def __add__(self, other): | 89 | def __add__(self, other): | ||
| 90 | new_effects = self._combine_effects(other) | 90 | new_effects = self._combine_effects(other) | ||
| 91 | new_intensities = self._combine_intensities(other) | 91 | new_intensities = self._combine_intensities(other) | ||
| 92 | 92 | ||||
| 93 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | 93 | new_potion = Potion(new_effects, max(self._duration, other.duration)) | ||
| 94 | new_potion._intensities = new_intensities | 94 | new_potion._intensities = new_intensities | ||
| 95 | 95 | ||||
| 96 | self.has_been_used = True | 96 | self.has_been_used = True | ||
| 97 | other.has_been_used = True | 97 | other.has_been_used = True | ||
| 98 | 98 | ||||
| 99 | return new_potion | 99 | return new_potion | ||
| 100 | 100 | ||||
| 101 | def _combine_effects(self, other): | 101 | def _combine_effects(self, other): | ||
| 102 | new_effects = {} | 102 | new_effects = {} | ||
| 103 | 103 | ||||
| 104 | for key, value in self.effects.items(): | 104 | for key, value in self.effects.items(): | ||
| 105 | new_effects[key] = value | 105 | new_effects[key] = value | ||
| 106 | 106 | ||||
| 107 | for key, value in other.effects.items(): | 107 | for key, value in other.effects.items(): | ||
| 108 | new_effects[key] = value | 108 | new_effects[key] = value | ||
| 109 | 109 | ||||
| 110 | return new_effects | 110 | return new_effects | ||
| 111 | 111 | ||||
| 112 | def _combine_intensities(self, other): | 112 | def _combine_intensities(self, other): | ||
| 113 | new_intensities = {} | 113 | new_intensities = {} | ||
| 114 | 114 | ||||
| 115 | for key, value in self._intensities.items(): | 115 | for key, value in self._intensities.items(): | ||
| 116 | new_intensities[key] = value | 116 | new_intensities[key] = value | ||
| 117 | 117 | ||||
| 118 | for key, value in other.intensities.items(): | 118 | for key, value in other.intensities.items(): | ||
| 119 | if key in new_intensities: | 119 | if key in new_intensities: | ||
| 120 | new_intensities[key] += value | 120 | new_intensities[key] += value | ||
| 121 | else: | 121 | else: | ||
| 122 | new_intensities[key] = value | 122 | new_intensities[key] = value | ||
| 123 | 123 | ||||
| 124 | return new_intensities | 124 | return new_intensities | ||
| 125 | 125 | ||||
| 126 | def __mul__(self, other): | 126 | def __mul__(self, other): | ||
| 127 | updated_intensities = {} | 127 | updated_intensities = {} | ||
| 128 | 128 | ||||
| 129 | if isinstance(other, int): | 129 | if isinstance(other, int): | ||
| 130 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | 130 | updated_intensities = {key: value * other for key, value in self._intensities.items()} | ||
| 131 | elif isinstance(other, float) and 0 <= other <= 1: | 131 | elif isinstance(other, float) and 0 <= other <= 1: | ||
| 132 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | 132 | updated_intensities = {key: self._round_to_whole(value * other) for key, value in self._intensities.items()} | ||
| 133 | 133 | ||||
| 134 | new_potion = Potion(self._effects, self._duration) | 134 | new_potion = Potion(self._effects, self._duration) | ||
| 135 | new_potion._intensities = updated_intensities | 135 | new_potion._intensities = updated_intensities | ||
| 136 | 136 | ||||
| 137 | self.has_been_used = True | 137 | self.has_been_used = True | ||
| 138 | 138 | ||||
| 139 | return new_potion | 139 | return new_potion | ||
| 140 | 140 | ||||
| 141 | @staticmethod | 141 | @staticmethod | ||
| 142 | def _round_to_whole(real): | 142 | def _round_to_whole(real): | ||
| 143 | fraction = real - math.floor(real) | 143 | fraction = real - math.floor(real) | ||
| 144 | 144 | ||||
| 145 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | 145 | return math.floor(real) if fraction <= 0.5 else math.ceil(real) | ||
| 146 | 146 | ||||
| 147 | def __sub__(self, other): | 147 | def __sub__(self, other): | ||
| 148 | if set(other.effects.keys()) - set(self._effects.keys()): | 148 | if set(other.effects.keys()) - set(self._effects.keys()): | ||
| 149 | raise TypeError('съдържанието няма значение') | 149 | raise TypeError('съдържанието няма значение') | ||
| 150 | 150 | ||||
| 151 | new_effects = {} | 151 | new_effects = {} | ||
| 152 | new_intensities = {} | 152 | new_intensities = {} | ||
| 153 | 153 | ||||
| 154 | for name, intensity in self._intensities.items(): | 154 | for name, intensity in self._intensities.items(): | ||
| 155 | if name not in other.intensities: | 155 | if name not in other.intensities: | ||
| 156 | new_effects[name] = self._effects[name] | 156 | new_effects[name] = self._effects[name] | ||
| 157 | new_intensities[name] = intensity | 157 | new_intensities[name] = intensity | ||
| 158 | else: | 158 | else: | ||
| 159 | difference = intensity - other.intensities[name] | 159 | difference = intensity - other.intensities[name] | ||
| 160 | if difference > 0: | 160 | if difference > 0: | ||
| 161 | new_effects[name] = self._effects[name] | 161 | new_effects[name] = self._effects[name] | ||
| 162 | new_intensities[name] = difference | 162 | new_intensities[name] = difference | ||
| 163 | 163 | ||||
| 164 | new_potion = Potion(new_effects, self._duration) | 164 | new_potion = Potion(new_effects, self._duration) | ||
| 165 | new_potion._intensities = new_intensities | 165 | new_potion._intensities = new_intensities | ||
| 166 | 166 | ||||
| 167 | self.has_been_used = True | 167 | self.has_been_used = True | ||
| 168 | other.has_been_used = True | 168 | other.has_been_used = True | ||
| 169 | 169 | ||||
| 170 | return new_potion | 170 | return new_potion | ||
| 171 | 171 | ||||
| 172 | def __truediv__(self, other): | 172 | def __truediv__(self, other): | ||
| 173 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | 173 | updated_intensities = {key: self._round_to_whole(value / other) for key, value in self._intensities.items()} | ||
| 174 | 174 | ||||
| 175 | new_potion = Potion(self._effects, self._duration) | 175 | new_potion = Potion(self._effects, self._duration) | ||
| 176 | new_potion._intensities = updated_intensities | 176 | new_potion._intensities = updated_intensities | ||
| 177 | 177 | ||||
| 178 | self.has_been_used = True | 178 | self.has_been_used = True | ||
| 179 | 179 | ||||
| 180 | return tuple(deepcopy(new_potion) for _ in range(other)) | 180 | return tuple(deepcopy(new_potion) for _ in range(other)) | ||
| 181 | 181 | ||||
| n | 182 | # Not sure which is the right convention here, so I had to check for a __deepcopy__ sample implementation | n | 182 | # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation |
| 183 | def __deepcopy__(self, memodict={}): | 183 | def __deepcopy__(self, memodict={}): | ||
| 184 | cls = self.__class__ | 184 | cls = self.__class__ | ||
| 185 | new_object = cls.__new__(cls) | 185 | new_object = cls.__new__(cls) | ||
| 186 | memodict[id(self)] = new_object | 186 | memodict[id(self)] = new_object | ||
| 187 | for key, value in self.__dict__.items(): | 187 | for key, value in self.__dict__.items(): | ||
| 188 | setattr(new_object, key, deepcopy(value, memodict)) | 188 | setattr(new_object, key, deepcopy(value, memodict)) | ||
| 189 | return new_object | 189 | return new_object | ||
| 190 | 190 | ||||
| 191 | def __eq__(self, other): | 191 | def __eq__(self, other): | ||
| 192 | return self._effects == other.effects and self._intensities == other.intensities | 192 | return self._effects == other.effects and self._intensities == other.intensities | ||
| 193 | 193 | ||||
| 194 | def __gt__(self, other): | 194 | def __gt__(self, other): | ||
| 195 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | 195 | return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other) | ||
| 196 | 196 | ||||
| 197 | def __lt__(self, other): | 197 | def __lt__(self, other): | ||
| 198 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | 198 | return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other) | ||
| 199 | 199 | ||||
| 200 | def get_applied(self, target): | 200 | def get_applied(self, target): | ||
| 201 | effects_map, masses = self._ordered_by_mass() | 201 | effects_map, masses = self._ordered_by_mass() | ||
| 202 | 202 | ||||
| 203 | for mass in masses: | 203 | for mass in masses: | ||
| 204 | name = effects_map[mass] | 204 | name = effects_map[mass] | ||
| 205 | if self._intensities[name] > 0: | 205 | if self._intensities[name] > 0: | ||
| 206 | effect = getattr(self, name) | 206 | effect = getattr(self, name) | ||
| 207 | effect(target) | 207 | effect(target) | ||
| 208 | 208 | ||||
| 209 | self.has_been_applied = True | 209 | self.has_been_applied = True | ||
| 210 | 210 | ||||
| 211 | def _ordered_by_mass(self): | 211 | def _ordered_by_mass(self): | ||
| 212 | effects_map = {self._get_mass(key): key for key in self._effects} | 212 | effects_map = {self._get_mass(key): key for key in self._effects} | ||
| 213 | masses = list(effects_map.keys()) | 213 | masses = list(effects_map.keys()) | ||
| 214 | masses.sort(reverse=True) | 214 | masses.sort(reverse=True) | ||
| 215 | 215 | ||||
| 216 | return effects_map, masses | 216 | return effects_map, masses | ||
| 217 | 217 | ||||
| 218 | @staticmethod | 218 | @staticmethod | ||
| 219 | def _get_mass(effect_name): | 219 | def _get_mass(effect_name): | ||
| 220 | return sum(map(ord, effect_name)) | 220 | return sum(map(ord, effect_name)) | ||
| 221 | 221 | ||||
| t | t | 222 | # Generated by IDE | ||
| 222 | def __hash__(self): | 223 | def __hash__(self): | ||
| 223 | return super().__hash__() | 224 | return super().__hash__() | ||
| 224 | 225 | ||||
| 225 | 226 | ||||
| 226 | class ГоспожатаПоХимия: | 227 | class ГоспожатаПоХимия: | ||
| 227 | def __init__(self): | 228 | def __init__(self): | ||
| 228 | self._durations = {} | 229 | self._durations = {} | ||
| 229 | self._states = {} | 230 | self._states = {} | ||
| 230 | self._potions_on_targets = {} | 231 | self._potions_on_targets = {} | ||
| 231 | self._original_potions = {} | 232 | self._original_potions = {} | ||
| 232 | 233 | ||||
| 233 | def apply(self, target, potion): | 234 | def apply(self, target, potion): | ||
| 234 | self._durations[potion] = potion.duration | 235 | self._durations[potion] = potion.duration | ||
| 235 | 236 | ||||
| 236 | if target in self._potions_on_targets.values(): | 237 | if target in self._potions_on_targets.values(): | ||
| 237 | for key, value in self._potions_on_targets.items(): | 238 | for key, value in self._potions_on_targets.items(): | ||
| 238 | if value == target: | 239 | if value == target: | ||
| 239 | self._states[potion] = self._states[key] | 240 | self._states[potion] = self._states[key] | ||
| 240 | break | 241 | break | ||
| 241 | else: | 242 | else: | ||
| 242 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | 243 | states_names = filter(lambda attribute: bool(re.search('^[^_].*', attribute)), dir(target)) | ||
| 243 | self._states[potion] = {name: getattr(target, name) for name in states_names} | 244 | self._states[potion] = {name: getattr(target, name) for name in states_names} | ||
| 244 | 245 | ||||
| 245 | self._potions_on_targets[potion] = target | 246 | self._potions_on_targets[potion] = target | ||
| 246 | self._original_potions[potion] = copy.deepcopy(potion) | 247 | self._original_potions[potion] = copy.deepcopy(potion) | ||
| 247 | 248 | ||||
| 248 | self._apply(target, potion) | 249 | self._apply(target, potion) | ||
| 249 | 250 | ||||
| 250 | @staticmethod | 251 | @staticmethod | ||
| 251 | def _apply(target, potion): | 252 | def _apply(target, potion): | ||
| 252 | potion.get_applied(target) | 253 | potion.get_applied(target) | ||
| 253 | 254 | ||||
| 254 | def tick(self): | 255 | def tick(self): | ||
| 255 | for potion in self._durations: | 256 | for potion in self._durations: | ||
| 256 | self._durations[potion] -= 1 | 257 | self._durations[potion] -= 1 | ||
| 257 | 258 | ||||
| 258 | expired_potions = [key for key, value in self._durations.items() if value == 0] | 259 | expired_potions = [key for key, value in self._durations.items() if value == 0] | ||
| 259 | 260 | ||||
| 260 | used_targets = [] | 261 | used_targets = [] | ||
| 261 | for potion in expired_potions: | 262 | for potion in expired_potions: | ||
| 262 | for attribute, value in self._states[potion].items(): | 263 | for attribute, value in self._states[potion].items(): | ||
| 263 | setattr(self._potions_on_targets[potion], attribute, value) | 264 | setattr(self._potions_on_targets[potion], attribute, value) | ||
| 264 | 265 | ||||
| 265 | used_targets.append(self._potions_on_targets[potion]) | 266 | used_targets.append(self._potions_on_targets[potion]) | ||
| 266 | 267 | ||||
| 267 | del self._durations[potion] | 268 | del self._durations[potion] | ||
| 268 | del self._potions_on_targets[potion] | 269 | del self._potions_on_targets[potion] | ||
| 269 | del self._states[potion] | 270 | del self._states[potion] | ||
| 270 | del self._original_potions[potion] | 271 | del self._original_potions[potion] | ||
| 271 | 272 | ||||
| 272 | for used_target in used_targets: | 273 | for used_target in used_targets: | ||
| 273 | for potion, target in self._potions_on_targets.items(): | 274 | for potion, target in self._potions_on_targets.items(): | ||
| 274 | if used_target == target: | 275 | if used_target == target: | ||
| 275 | self._apply(target, self._original_potions[potion]) | 276 | self._apply(target, self._original_potions[potion]) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||