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 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|