Домашни > Работилница за отвари! > Решения > Решението на Атанас Ников

Резултати
9 точки от тестове
2 точки от учител

11 точки общо

18 успешни теста
2 неуспешни теста
Код

  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` ми изглежда излишен, бивайки един ред...
История

f1import mathf1import math
2import re2import re
3from copy import deepcopy3from copy import deepcopy
44
55
6class Potion:6class Potion:
7    def __init__(self, effects, duration):7    def __init__(self, effects, duration):
8        self._effects = effects8        self._effects = effects
9        self._duration = duration9        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 = False12        self._has_been_used = False
13        self._has_been_applied = False13        self._has_been_applied = False
1414
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'):
n17            raise TypeError('Potion is depleted')n17            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.')
2020
21        return object.__getattribute__(self, item)21        return object.__getattribute__(self, item)
2222
23    def __getattr__(self, item):23    def __getattr__(self, item):
24        if self._has_been_applied:24        if self._has_been_applied:
n25            raise TypeError('Potion is depleted')n25            raise TypeError('Potion is depleted.')
2626
27        if item not in self._effects:27        if item not in self._effects:
n28            raise AttributeError('No such effect')n28            raise AttributeError('No such effect.')
2929
30        if item in self._depleted_effects:30        if item in self._depleted_effects:
t31            raise TypeError('Effect is depleted')t31            raise TypeError('Effect is depleted.')
3232
33        effect = self._intensify_effect(self._intensities[item])(self._effects[item])33        effect = self._intensify_effect(self._intensities[item])(self._effects[item])
3434
35        self._depleted_effects.add(item)35        self._depleted_effects.add(item)
3636
37        return effect37        return effect
3838
39    @staticmethod39    @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)
4545
46            return intensifying_wrapper46            return intensifying_wrapper
4747
48        return intensifying_decorator48        return intensifying_decorator
4949
50    @property50    @property
51    def has_been_used(self):51    def has_been_used(self):
52        return self._has_been_used52        return self._has_been_used
5353
54    @has_been_used.setter54    @has_been_used.setter
55    def has_been_used(self, value):55    def has_been_used(self, value):
56        self._has_been_used = value56        self._has_been_used = value
5757
58    @property58    @property
59    def has_been_applied(self):59    def has_been_applied(self):
60        return self._has_been_applied60        return self._has_been_applied
6161
62    @has_been_applied.setter62    @has_been_applied.setter
63    def has_been_applied(self, value):63    def has_been_applied(self, value):
64        self._has_been_applied = value64        self._has_been_applied = value
6565
66    @property66    @property
67    def duration(self):67    def duration(self):
68        return self._duration68        return self._duration
6969
70    @duration.setter70    @duration.setter
71    def duration(self, value):71    def duration(self, value):
72        self._duration = value72        self._duration = value
7373
74    @property74    @property
75    def intensities(self):75    def intensities(self):
76        return self._intensities76        return self._intensities
7777
78    @intensities.setter78    @intensities.setter
79    def intensities(self, value):79    def intensities(self, value):
80        self._intensities = value80        self._intensities = value
8181
82    @property82    @property
83    def effects(self):83    def effects(self):
84        return self._effects84        return self._effects
8585
86    @effects.setter86    @effects.setter
87    def effects(self, value):87    def effects(self, value):
88        self._effects = value88        self._effects = value
8989
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)
9393
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_intensities95        new_potion._intensities = new_intensities
9696
97        self.has_been_used = True97        self.has_been_used = True
98        other.has_been_used = True98        other.has_been_used = True
9999
100        return new_potion100        return new_potion
101101
102    def _combine_effects(self, other):102    def _combine_effects(self, other):
103        new_effects = {}103        new_effects = {}
104104
105        for key, value in self.effects.items():105        for key, value in self.effects.items():
106            new_effects[key] = value106            new_effects[key] = value
107107
108        for key, value in other.effects.items():108        for key, value in other.effects.items():
109            new_effects[key] = value109            new_effects[key] = value
110110
111        return new_effects111        return new_effects
112112
113    def _combine_intensities(self, other):113    def _combine_intensities(self, other):
114        new_intensities = {}114        new_intensities = {}
115115
116        for key, value in self._intensities.items():116        for key, value in self._intensities.items():
117            new_intensities[key] = value117            new_intensities[key] = value
118118
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] += value121                new_intensities[key] += value
122            else:122            else:
123                new_intensities[key] = value123                new_intensities[key] = value
124124
125        return new_intensities125        return new_intensities
126126
127    def __mul__(self, other):127    def __mul__(self, other):
128        updated_intensities = {}128        updated_intensities = {}
129129
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()}
134134
135        new_potion = Potion(self._effects, self._duration)135        new_potion = Potion(self._effects, self._duration)
136        new_potion._intensities = updated_intensities136        new_potion._intensities = updated_intensities
137137
138        self.has_been_used = True138        self.has_been_used = True
139139
140        return new_potion140        return new_potion
141141
142    @staticmethod142    @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)
145145
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)
147147
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('съдържанието няма значение')
151151
152        new_effects = {}152        new_effects = {}
153        new_intensities = {}153        new_intensities = {}
154154
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] = intensity158                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] = difference163                    new_intensities[name] = difference
164164
165        new_potion = Potion(new_effects, self._duration)165        new_potion = Potion(new_effects, self._duration)
166        new_potion._intensities = new_intensities166        new_potion._intensities = new_intensities
167167
168        self.has_been_used = True168        self.has_been_used = True
169        other.has_been_used = True169        other.has_been_used = True
170170
171        return new_potion171        return new_potion
172172
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()}
175175
176        new_potion = Potion(self._effects, self._duration)176        new_potion = Potion(self._effects, self._duration)
177        new_potion._intensities = updated_intensities177        new_potion._intensities = updated_intensities
178178
179        self.has_been_used = True179        self.has_been_used = True
180180
181        return tuple(deepcopy(new_potion) for _ in range(other))181        return tuple(deepcopy(new_potion) for _ in range(other))
182182
183    # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation183    # 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_object187        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_object190        return new_object
191191
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()
194194
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)
197197
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)
200200
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}
203203
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()
206206
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)
211211
212        self.has_been_applied = True212        self.has_been_applied = True
213213
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)
218218
219        return effects_map, masses219        return effects_map, masses
220220
221    @staticmethod221    @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))
224224
225    # Generated by IDE225    # Generated by IDE
226    def __hash__(self):226    def __hash__(self):
227        return super().__hash__()227        return super().__hash__()
228228
229229
230class ГоспожатаПоХимия:230class ГоспожатаПоХимия:
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 = {}
236236
237    def apply(self, target, potion):237    def apply(self, target, potion):
238        self._durations[potion] = potion.duration238        self._durations[potion] = potion.duration
239239
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                    break244                    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}
248248
249        self._potions_on_targets[potion] = target249        self._potions_on_targets[potion] = target
250        self._original_potions[potion] = deepcopy(potion)250        self._original_potions[potion] = deepcopy(potion)
251251
252        potion.get_applied(target)252        potion.get_applied(target)
253253
254    def tick(self):254    def tick(self):
255        for potion in self._durations:255        for potion in self._durations:
256            self._durations[potion] -= 1256            self._durations[potion] -= 1
257257
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]
259259
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)
264264
265            used_targets.append(self._potions_on_targets[potion])265            used_targets.append(self._potions_on_targets[potion])
266266
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]
271271
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
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import mathf1import math
2import re2import re
3from copy import deepcopy3from copy import deepcopy
44
55
6class Potion:6class Potion:
7    def __init__(self, effects, duration):7    def __init__(self, effects, duration):
8        self._effects = effects8        self._effects = effects
9        self._duration = duration9        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 = False12        self._has_been_used = False
13        self._has_been_applied = False13        self._has_been_applied = False
1414
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.')
2020
21        return object.__getattribute__(self, item)21        return object.__getattribute__(self, item)
2222
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')
2626
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')
2929
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')
3232
33        effect = self._intensify_effect(self._intensities[item])(self._effects[item])33        effect = self._intensify_effect(self._intensities[item])(self._effects[item])
3434
35        self._depleted_effects.add(item)35        self._depleted_effects.add(item)
3636
37        return effect37        return effect
3838
39    @staticmethod39    @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)
4545
46            return intensifying_wrapper46            return intensifying_wrapper
4747
48        return intensifying_decorator48        return intensifying_decorator
4949
50    @property50    @property
51    def has_been_used(self):51    def has_been_used(self):
52        return self._has_been_used52        return self._has_been_used
5353
54    @has_been_used.setter54    @has_been_used.setter
55    def has_been_used(self, value):55    def has_been_used(self, value):
56        self._has_been_used = value56        self._has_been_used = value
5757
58    @property58    @property
59    def has_been_applied(self):59    def has_been_applied(self):
60        return self._has_been_applied60        return self._has_been_applied
6161
62    @has_been_applied.setter62    @has_been_applied.setter
63    def has_been_applied(self, value):63    def has_been_applied(self, value):
64        self._has_been_applied = value64        self._has_been_applied = value
6565
66    @property66    @property
67    def duration(self):67    def duration(self):
68        return self._duration68        return self._duration
6969
70    @duration.setter70    @duration.setter
71    def duration(self, value):71    def duration(self, value):
72        self._duration = value72        self._duration = value
7373
74    @property74    @property
75    def intensities(self):75    def intensities(self):
76        return self._intensities76        return self._intensities
7777
78    @intensities.setter78    @intensities.setter
79    def intensities(self, value):79    def intensities(self, value):
80        self._intensities = value80        self._intensities = value
8181
82    @property82    @property
83    def effects(self):83    def effects(self):
84        return self._effects84        return self._effects
8585
86    @effects.setter86    @effects.setter
87    def effects(self, value):87    def effects(self, value):
88        self._effects = value88        self._effects = value
8989
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)
9393
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_intensities95        new_potion._intensities = new_intensities
9696
97        self.has_been_used = True97        self.has_been_used = True
98        other.has_been_used = True98        other.has_been_used = True
9999
100        return new_potion100        return new_potion
101101
102    def _combine_effects(self, other):102    def _combine_effects(self, other):
103        new_effects = {}103        new_effects = {}
104104
105        for key, value in self.effects.items():105        for key, value in self.effects.items():
106            new_effects[key] = value106            new_effects[key] = value
107107
108        for key, value in other.effects.items():108        for key, value in other.effects.items():
109            new_effects[key] = value109            new_effects[key] = value
110110
111        return new_effects111        return new_effects
112112
113    def _combine_intensities(self, other):113    def _combine_intensities(self, other):
114        new_intensities = {}114        new_intensities = {}
115115
116        for key, value in self._intensities.items():116        for key, value in self._intensities.items():
117            new_intensities[key] = value117            new_intensities[key] = value
118118
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] += value121                new_intensities[key] += value
122            else:122            else:
123                new_intensities[key] = value123                new_intensities[key] = value
124124
125        return new_intensities125        return new_intensities
126126
127    def __mul__(self, other):127    def __mul__(self, other):
128        updated_intensities = {}128        updated_intensities = {}
129129
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()}
134134
135        new_potion = Potion(self._effects, self._duration)135        new_potion = Potion(self._effects, self._duration)
136        new_potion._intensities = updated_intensities136        new_potion._intensities = updated_intensities
137137
138        self.has_been_used = True138        self.has_been_used = True
139139
140        return new_potion140        return new_potion
141141
142    @staticmethod142    @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)
145145
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)
147147
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('съдържанието няма значение')
151151
152        new_effects = {}152        new_effects = {}
153        new_intensities = {}153        new_intensities = {}
154154
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] = intensity158                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] = difference163                    new_intensities[name] = difference
164164
165        new_potion = Potion(new_effects, self._duration)165        new_potion = Potion(new_effects, self._duration)
166        new_potion._intensities = new_intensities166        new_potion._intensities = new_intensities
167167
168        self.has_been_used = True168        self.has_been_used = True
169        other.has_been_used = True169        other.has_been_used = True
170170
171        return new_potion171        return new_potion
172172
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()}
175175
176        new_potion = Potion(self._effects, self._duration)176        new_potion = Potion(self._effects, self._duration)
177        new_potion._intensities = updated_intensities177        new_potion._intensities = updated_intensities
178178
179        self.has_been_used = True179        self.has_been_used = True
180180
181        return tuple(deepcopy(new_potion) for _ in range(other))181        return tuple(deepcopy(new_potion) for _ in range(other))
182182
183    # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation183    # 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_object187        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_object190        return new_object
191191
192    def __eq__(self, other):192    def __eq__(self, other):
n193        return self._effects == other.effects and self._intensities == other.intensitiesn193        return self._effects == other.effects and self.get_comparable_effects() == other.get_comparable_effects()
194194
195    def __gt__(self, other):195    def __gt__(self, other):
n196        return sum(self._intensities.values()) > sum(other.intensities.values()) and not self.__eq__(other)n196        return sum(self.get_comparable_effects().values()) > sum(other.get_comparable_effects().values()) and not self.__eq__(other)
197197
198    def __lt__(self, other):198    def __lt__(self, other):
n199        return sum(self._intensities.values()) < sum(other.intensities.values()) and not self.__eq__(other)n199        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}
200203
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()
203206
204        for mass in masses:207        for mass in masses:
205            name = effects_map[mass]208            name = effects_map[mass]
t206            if self._intensities[name] > 0:t
207                effect = getattr(self, name)209            effect = getattr(self, name)
208                effect(target)210            effect(target)
209211
210        self.has_been_applied = True212        self.has_been_applied = True
211213
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)
216218
217        return effects_map, masses219        return effects_map, masses
218220
219    @staticmethod221    @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))
222224
223    # Generated by IDE225    # Generated by IDE
224    def __hash__(self):226    def __hash__(self):
225        return super().__hash__()227        return super().__hash__()
226228
227229
228class ГоспожатаПоХимия:230class ГоспожатаПоХимия:
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 = {}
234236
235    def apply(self, target, potion):237    def apply(self, target, potion):
236        self._durations[potion] = potion.duration238        self._durations[potion] = potion.duration
237239
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                    break244                    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}
246248
247        self._potions_on_targets[potion] = target249        self._potions_on_targets[potion] = target
248        self._original_potions[potion] = deepcopy(potion)250        self._original_potions[potion] = deepcopy(potion)
249251
250        potion.get_applied(target)252        potion.get_applied(target)
251253
252    def tick(self):254    def tick(self):
253        for potion in self._durations:255        for potion in self._durations:
254            self._durations[potion] -= 1256            self._durations[potion] -= 1
255257
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]
257259
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)
262264
263            used_targets.append(self._potions_on_targets[potion])265            used_targets.append(self._potions_on_targets[potion])
264266
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]
269271
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
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import mathf1import math
2import re2import re
3from copy import deepcopy3from copy import deepcopy
44
55
6class Potion:6class Potion:
7    def __init__(self, effects, duration):7    def __init__(self, effects, duration):
8        self._effects = effects8        self._effects = effects
9        self._duration = duration9        self._duration = duration
10        self._intensities = {key: 1 for key in effects}10        self._intensities = {key: 1 for key in effects}
nn11        self._depleted_effects = set()
11        self._has_been_used = False12        self._has_been_used = False
12        self._has_been_applied = False13        self._has_been_applied = False
1314
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.')
1920
20        return object.__getattribute__(self, item)21        return object.__getattribute__(self, item)
2122
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')
2526
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')
2829
n29        if self._intensities[item] == 0:n30        if item in self._depleted_effects:
30            raise TypeError('Effect is depleted')31            raise TypeError('Effect is depleted')
3132
32        effect = self._intensify_effect(self._intensities[item])(self._effects[item])33        effect = self._intensify_effect(self._intensities[item])(self._effects[item])
n33        self._intensities[item] = 0n34 
35        self._depleted_effects.add(item)
3436
35        return effect37        return effect
3638
37    @staticmethod39    @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)
4345
44            return intensifying_wrapper46            return intensifying_wrapper
4547
46        return intensifying_decorator48        return intensifying_decorator
4749
48    @property50    @property
49    def has_been_used(self):51    def has_been_used(self):
50        return self._has_been_used52        return self._has_been_used
5153
52    @has_been_used.setter54    @has_been_used.setter
53    def has_been_used(self, value):55    def has_been_used(self, value):
54        self._has_been_used = value56        self._has_been_used = value
5557
56    @property58    @property
57    def has_been_applied(self):59    def has_been_applied(self):
58        return self._has_been_applied60        return self._has_been_applied
5961
60    @has_been_applied.setter62    @has_been_applied.setter
61    def has_been_applied(self, value):63    def has_been_applied(self, value):
62        self._has_been_applied = value64        self._has_been_applied = value
6365
64    @property66    @property
65    def duration(self):67    def duration(self):
66        return self._duration68        return self._duration
6769
68    @duration.setter70    @duration.setter
69    def duration(self, value):71    def duration(self, value):
70        self._duration = value72        self._duration = value
7173
72    @property74    @property
73    def intensities(self):75    def intensities(self):
74        return self._intensities76        return self._intensities
7577
76    @intensities.setter78    @intensities.setter
77    def intensities(self, value):79    def intensities(self, value):
78        self._intensities = value80        self._intensities = value
7981
80    @property82    @property
81    def effects(self):83    def effects(self):
82        return self._effects84        return self._effects
8385
84    @effects.setter86    @effects.setter
85    def effects(self, value):87    def effects(self, value):
86        self._effects = value88        self._effects = value
8789
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)
9193
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_intensities95        new_potion._intensities = new_intensities
9496
95        self.has_been_used = True97        self.has_been_used = True
96        other.has_been_used = True98        other.has_been_used = True
9799
98        return new_potion100        return new_potion
99101
100    def _combine_effects(self, other):102    def _combine_effects(self, other):
101        new_effects = {}103        new_effects = {}
102104
103        for key, value in self.effects.items():105        for key, value in self.effects.items():
104            new_effects[key] = value106            new_effects[key] = value
105107
106        for key, value in other.effects.items():108        for key, value in other.effects.items():
107            new_effects[key] = value109            new_effects[key] = value
108110
109        return new_effects111        return new_effects
110112
111    def _combine_intensities(self, other):113    def _combine_intensities(self, other):
112        new_intensities = {}114        new_intensities = {}
113115
114        for key, value in self._intensities.items():116        for key, value in self._intensities.items():
115            new_intensities[key] = value117            new_intensities[key] = value
116118
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] += value121                new_intensities[key] += value
120            else:122            else:
121                new_intensities[key] = value123                new_intensities[key] = value
122124
123        return new_intensities125        return new_intensities
124126
125    def __mul__(self, other):127    def __mul__(self, other):
126        updated_intensities = {}128        updated_intensities = {}
127129
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()}
132134
133        new_potion = Potion(self._effects, self._duration)135        new_potion = Potion(self._effects, self._duration)
134        new_potion._intensities = updated_intensities136        new_potion._intensities = updated_intensities
135137
136        self.has_been_used = True138        self.has_been_used = True
137139
138        return new_potion140        return new_potion
139141
140    @staticmethod142    @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)
143145
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)
145147
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('съдържанието няма значение')
149151
150        new_effects = {}152        new_effects = {}
151        new_intensities = {}153        new_intensities = {}
152154
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] = intensity158                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] = difference163                    new_intensities[name] = difference
162164
163        new_potion = Potion(new_effects, self._duration)165        new_potion = Potion(new_effects, self._duration)
164        new_potion._intensities = new_intensities166        new_potion._intensities = new_intensities
165167
166        self.has_been_used = True168        self.has_been_used = True
167        other.has_been_used = True169        other.has_been_used = True
168170
169        return new_potion171        return new_potion
170172
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()}
173175
174        new_potion = Potion(self._effects, self._duration)176        new_potion = Potion(self._effects, self._duration)
175        new_potion._intensities = updated_intensities177        new_potion._intensities = updated_intensities
176178
177        self.has_been_used = True179        self.has_been_used = True
178180
179        return tuple(deepcopy(new_potion) for _ in range(other))181        return tuple(deepcopy(new_potion) for _ in range(other))
180182
181    # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation183    # 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_object187        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_object190        return new_object
189191
190    def __eq__(self, other):192    def __eq__(self, other):
191        return self._effects == other.effects and self._intensities == other.intensities193        return self._effects == other.effects and self._intensities == other.intensities
192194
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)
195197
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)
198200
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()
201203
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)
207209
208        self.has_been_applied = True210        self.has_been_applied = True
209211
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)
214216
215        return effects_map, masses217        return effects_map, masses
216218
217    @staticmethod219    @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))
220222
221    # Generated by IDE223    # Generated by IDE
222    def __hash__(self):224    def __hash__(self):
223        return super().__hash__()225        return super().__hash__()
224226
225227
226class ГоспожатаПоХимия:228class ГоспожатаПоХимия:
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 = {}
232234
233    def apply(self, target, potion):235    def apply(self, target, potion):
234        self._durations[potion] = potion.duration236        self._durations[potion] = potion.duration
235237
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                    break242                    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}
244246
245        self._potions_on_targets[potion] = target247        self._potions_on_targets[potion] = target
246        self._original_potions[potion] = deepcopy(potion)248        self._original_potions[potion] = deepcopy(potion)
247249
n248        self._apply(target, potion)n
249 
250    @staticmethod
251    def _apply(target, potion):
252        potion.get_applied(target)250        potion.get_applied(target)
253251
254    def tick(self):252    def tick(self):
255        for potion in self._durations:253        for potion in self._durations:
256            self._durations[potion] -= 1254            self._durations[potion] -= 1
257255
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]
259257
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)
264262
265            used_targets.append(self._potions_on_targets[potion])263            used_targets.append(self._potions_on_targets[potion])
266264
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]
271269
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:
t275                    self._apply(target, self._original_potions[potion])t273                    self._original_potions[potion].get_applied(target)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

n1import copyn
2import math1import math
3import re2import re
4from copy import deepcopy3from copy import deepcopy
54
65
7class Potion:6class Potion:
8    def __init__(self, effects, duration):7    def __init__(self, effects, duration):
9        self._effects = effects8        self._effects = effects
10        self._duration = duration9        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 = False11        self._has_been_used = False
13        self._has_been_applied = False12        self._has_been_applied = False
1413
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.')
2019
21        return object.__getattribute__(self, item)20        return object.__getattribute__(self, item)
2221
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')
2625
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')
2928
30        if self._intensities[item] == 0:29        if self._intensities[item] == 0:
31            raise TypeError('Effect is depleted')30            raise TypeError('Effect is depleted')
3231
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] = 033        self._intensities[item] = 0
3534
36        return effect35        return effect
3736
38    @staticmethod37    @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)
4443
45            return intensifying_wrapper44            return intensifying_wrapper
4645
47        return intensifying_decorator46        return intensifying_decorator
4847
49    @property48    @property
50    def has_been_used(self):49    def has_been_used(self):
51        return self._has_been_used50        return self._has_been_used
5251
53    @has_been_used.setter52    @has_been_used.setter
54    def has_been_used(self, value):53    def has_been_used(self, value):
55        self._has_been_used = value54        self._has_been_used = value
5655
57    @property56    @property
58    def has_been_applied(self):57    def has_been_applied(self):
59        return self._has_been_applied58        return self._has_been_applied
6059
61    @has_been_applied.setter60    @has_been_applied.setter
62    def has_been_applied(self, value):61    def has_been_applied(self, value):
63        self._has_been_applied = value62        self._has_been_applied = value
6463
65    @property64    @property
66    def duration(self):65    def duration(self):
67        return self._duration66        return self._duration
6867
69    @duration.setter68    @duration.setter
70    def duration(self, value):69    def duration(self, value):
71        self._duration = value70        self._duration = value
7271
73    @property72    @property
74    def intensities(self):73    def intensities(self):
75        return self._intensities74        return self._intensities
7675
77    @intensities.setter76    @intensities.setter
78    def intensities(self, value):77    def intensities(self, value):
79        self._intensities = value78        self._intensities = value
8079
81    @property80    @property
82    def effects(self):81    def effects(self):
83        return self._effects82        return self._effects
8483
85    @effects.setter84    @effects.setter
86    def effects(self, value):85    def effects(self, value):
87        self._effects = value86        self._effects = value
8887
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)
9291
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_intensities93        new_potion._intensities = new_intensities
9594
96        self.has_been_used = True95        self.has_been_used = True
97        other.has_been_used = True96        other.has_been_used = True
9897
99        return new_potion98        return new_potion
10099
101    def _combine_effects(self, other):100    def _combine_effects(self, other):
102        new_effects = {}101        new_effects = {}
103102
104        for key, value in self.effects.items():103        for key, value in self.effects.items():
105            new_effects[key] = value104            new_effects[key] = value
106105
107        for key, value in other.effects.items():106        for key, value in other.effects.items():
108            new_effects[key] = value107            new_effects[key] = value
109108
110        return new_effects109        return new_effects
111110
112    def _combine_intensities(self, other):111    def _combine_intensities(self, other):
113        new_intensities = {}112        new_intensities = {}
114113
115        for key, value in self._intensities.items():114        for key, value in self._intensities.items():
116            new_intensities[key] = value115            new_intensities[key] = value
117116
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] += value119                new_intensities[key] += value
121            else:120            else:
122                new_intensities[key] = value121                new_intensities[key] = value
123122
124        return new_intensities123        return new_intensities
125124
126    def __mul__(self, other):125    def __mul__(self, other):
127        updated_intensities = {}126        updated_intensities = {}
128127
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()}
133132
134        new_potion = Potion(self._effects, self._duration)133        new_potion = Potion(self._effects, self._duration)
135        new_potion._intensities = updated_intensities134        new_potion._intensities = updated_intensities
136135
137        self.has_been_used = True136        self.has_been_used = True
138137
139        return new_potion138        return new_potion
140139
141    @staticmethod140    @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)
144143
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)
146145
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('съдържанието няма значение')
150149
151        new_effects = {}150        new_effects = {}
152        new_intensities = {}151        new_intensities = {}
153152
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] = intensity156                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] = difference161                    new_intensities[name] = difference
163162
164        new_potion = Potion(new_effects, self._duration)163        new_potion = Potion(new_effects, self._duration)
165        new_potion._intensities = new_intensities164        new_potion._intensities = new_intensities
166165
167        self.has_been_used = True166        self.has_been_used = True
168        other.has_been_used = True167        other.has_been_used = True
169168
170        return new_potion169        return new_potion
171170
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()}
174173
175        new_potion = Potion(self._effects, self._duration)174        new_potion = Potion(self._effects, self._duration)
176        new_potion._intensities = updated_intensities175        new_potion._intensities = updated_intensities
177176
178        self.has_been_used = True177        self.has_been_used = True
179178
180        return tuple(deepcopy(new_potion) for _ in range(other))179        return tuple(deepcopy(new_potion) for _ in range(other))
181180
182    # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation181    # 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_object185        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_object188        return new_object
190189
191    def __eq__(self, other):190    def __eq__(self, other):
192        return self._effects == other.effects and self._intensities == other.intensities191        return self._effects == other.effects and self._intensities == other.intensities
193192
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)
196195
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)
199198
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()
202201
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)
208207
209        self.has_been_applied = True208        self.has_been_applied = True
210209
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)
215214
216        return effects_map, masses215        return effects_map, masses
217216
218    @staticmethod217    @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))
221220
222    # Generated by IDE221    # Generated by IDE
223    def __hash__(self):222    def __hash__(self):
224        return super().__hash__()223        return super().__hash__()
225224
226225
227class ГоспожатаПоХимия:226class ГоспожатаПоХимия:
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 = {}
233232
234    def apply(self, target, potion):233    def apply(self, target, potion):
235        self._durations[potion] = potion.duration234        self._durations[potion] = potion.duration
236235
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                    break240                    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}
245244
246        self._potions_on_targets[potion] = target245        self._potions_on_targets[potion] = target
t247        self._original_potions[potion] = copy.deepcopy(potion)t246        self._original_potions[potion] = deepcopy(potion)
248247
249        self._apply(target, potion)248        self._apply(target, potion)
250249
251    @staticmethod250    @staticmethod
252    def _apply(target, potion):251    def _apply(target, potion):
253        potion.get_applied(target)252        potion.get_applied(target)
254253
255    def tick(self):254    def tick(self):
256        for potion in self._durations:255        for potion in self._durations:
257            self._durations[potion] -= 1256            self._durations[potion] -= 1
258257
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]
260259
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)
265264
266            used_targets.append(self._potions_on_targets[potion])265            used_targets.append(self._potions_on_targets[potion])
267266
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]
272271
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
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import copyf1import copy
2import math2import math
3import re3import re
4from copy import deepcopy4from copy import deepcopy
55
66
7class Potion:7class Potion:
n8    def __init__(self, _effects, duration):n8    def __init__(self, effects, duration):
9        self._effects = _effects9        self._effects = effects
10        self._duration = duration10        self._duration = duration
t11        self._intensities = {key: 1 for key in _effects}t11        self._intensities = {key: 1 for key in effects}
12        self._has_been_used = False12        self._has_been_used = False
13        self._has_been_applied = False13        self._has_been_applied = False
1414
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.')
2020
21        return object.__getattribute__(self, item)21        return object.__getattribute__(self, item)
2222
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')
2626
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')
2929
30        if self._intensities[item] == 0:30        if self._intensities[item] == 0:
31            raise TypeError('Effect is depleted')31            raise TypeError('Effect is depleted')
3232
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] = 034        self._intensities[item] = 0
3535
36        return effect36        return effect
3737
38    @staticmethod38    @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)
4444
45            return intensifying_wrapper45            return intensifying_wrapper
4646
47        return intensifying_decorator47        return intensifying_decorator
4848
49    @property49    @property
50    def has_been_used(self):50    def has_been_used(self):
51        return self._has_been_used51        return self._has_been_used
5252
53    @has_been_used.setter53    @has_been_used.setter
54    def has_been_used(self, value):54    def has_been_used(self, value):
55        self._has_been_used = value55        self._has_been_used = value
5656
57    @property57    @property
58    def has_been_applied(self):58    def has_been_applied(self):
59        return self._has_been_applied59        return self._has_been_applied
6060
61    @has_been_applied.setter61    @has_been_applied.setter
62    def has_been_applied(self, value):62    def has_been_applied(self, value):
63        self._has_been_applied = value63        self._has_been_applied = value
6464
65    @property65    @property
66    def duration(self):66    def duration(self):
67        return self._duration67        return self._duration
6868
69    @duration.setter69    @duration.setter
70    def duration(self, value):70    def duration(self, value):
71        self._duration = value71        self._duration = value
7272
73    @property73    @property
74    def intensities(self):74    def intensities(self):
75        return self._intensities75        return self._intensities
7676
77    @intensities.setter77    @intensities.setter
78    def intensities(self, value):78    def intensities(self, value):
79        self._intensities = value79        self._intensities = value
8080
81    @property81    @property
82    def effects(self):82    def effects(self):
83        return self._effects83        return self._effects
8484
85    @effects.setter85    @effects.setter
86    def effects(self, value):86    def effects(self, value):
87        self._effects = value87        self._effects = value
8888
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)
9292
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_intensities94        new_potion._intensities = new_intensities
9595
96        self.has_been_used = True96        self.has_been_used = True
97        other.has_been_used = True97        other.has_been_used = True
9898
99        return new_potion99        return new_potion
100100
101    def _combine_effects(self, other):101    def _combine_effects(self, other):
102        new_effects = {}102        new_effects = {}
103103
104        for key, value in self.effects.items():104        for key, value in self.effects.items():
105            new_effects[key] = value105            new_effects[key] = value
106106
107        for key, value in other.effects.items():107        for key, value in other.effects.items():
108            new_effects[key] = value108            new_effects[key] = value
109109
110        return new_effects110        return new_effects
111111
112    def _combine_intensities(self, other):112    def _combine_intensities(self, other):
113        new_intensities = {}113        new_intensities = {}
114114
115        for key, value in self._intensities.items():115        for key, value in self._intensities.items():
116            new_intensities[key] = value116            new_intensities[key] = value
117117
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] += value120                new_intensities[key] += value
121            else:121            else:
122                new_intensities[key] = value122                new_intensities[key] = value
123123
124        return new_intensities124        return new_intensities
125125
126    def __mul__(self, other):126    def __mul__(self, other):
127        updated_intensities = {}127        updated_intensities = {}
128128
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()}
133133
134        new_potion = Potion(self._effects, self._duration)134        new_potion = Potion(self._effects, self._duration)
135        new_potion._intensities = updated_intensities135        new_potion._intensities = updated_intensities
136136
137        self.has_been_used = True137        self.has_been_used = True
138138
139        return new_potion139        return new_potion
140140
141    @staticmethod141    @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)
144144
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)
146146
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('съдържанието няма значение')
150150
151        new_effects = {}151        new_effects = {}
152        new_intensities = {}152        new_intensities = {}
153153
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] = intensity157                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] = difference162                    new_intensities[name] = difference
163163
164        new_potion = Potion(new_effects, self._duration)164        new_potion = Potion(new_effects, self._duration)
165        new_potion._intensities = new_intensities165        new_potion._intensities = new_intensities
166166
167        self.has_been_used = True167        self.has_been_used = True
168        other.has_been_used = True168        other.has_been_used = True
169169
170        return new_potion170        return new_potion
171171
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()}
174174
175        new_potion = Potion(self._effects, self._duration)175        new_potion = Potion(self._effects, self._duration)
176        new_potion._intensities = updated_intensities176        new_potion._intensities = updated_intensities
177177
178        self.has_been_used = True178        self.has_been_used = True
179179
180        return tuple(deepcopy(new_potion) for _ in range(other))180        return tuple(deepcopy(new_potion) for _ in range(other))
181181
182    # Not sure which the right convention is here, so I had to check for a __deepcopy__ sample implementation182    # 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_object186        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_object189        return new_object
190190
191    def __eq__(self, other):191    def __eq__(self, other):
192        return self._effects == other.effects and self._intensities == other.intensities192        return self._effects == other.effects and self._intensities == other.intensities
193193
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)
196196
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)
199199
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()
202202
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)
208208
209        self.has_been_applied = True209        self.has_been_applied = True
210210
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)
215215
216        return effects_map, masses216        return effects_map, masses
217217
218    @staticmethod218    @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))
221221
222    # Generated by IDE222    # Generated by IDE
223    def __hash__(self):223    def __hash__(self):
224        return super().__hash__()224        return super().__hash__()
225225
226226
227class ГоспожатаПоХимия:227class ГоспожатаПоХимия:
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 = {}
233233
234    def apply(self, target, potion):234    def apply(self, target, potion):
235        self._durations[potion] = potion.duration235        self._durations[potion] = potion.duration
236236
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                    break241                    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}
245245
246        self._potions_on_targets[potion] = target246        self._potions_on_targets[potion] = target
247        self._original_potions[potion] = copy.deepcopy(potion)247        self._original_potions[potion] = copy.deepcopy(potion)
248248
249        self._apply(target, potion)249        self._apply(target, potion)
250250
251    @staticmethod251    @staticmethod
252    def _apply(target, potion):252    def _apply(target, potion):
253        potion.get_applied(target)253        potion.get_applied(target)
254254
255    def tick(self):255    def tick(self):
256        for potion in self._durations:256        for potion in self._durations:
257            self._durations[potion] -= 1257            self._durations[potion] -= 1
258258
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]
260260
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)
265265
266            used_targets.append(self._potions_on_targets[potion])266            used_targets.append(self._potions_on_targets[potion])
267267
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]
272272
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
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import copyf1import copy
2import math2import math
3import re3import re
4from copy import deepcopy4from copy import deepcopy
55
66
7class Potion:7class Potion:
8    def __init__(self, _effects, duration):8    def __init__(self, _effects, duration):
9        self._effects = _effects9        self._effects = _effects
10        self._duration = duration10        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 = False12        self._has_been_used = False
13        self._has_been_applied = False13        self._has_been_applied = False
1414
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.')
2020
21        return object.__getattribute__(self, item)21        return object.__getattribute__(self, item)
2222
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')
2626
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')
2929
30        if self._intensities[item] == 0:30        if self._intensities[item] == 0:
31            raise TypeError('Effect is depleted')31            raise TypeError('Effect is depleted')
3232
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] = 034        self._intensities[item] = 0
3535
36        return effect36        return effect
3737
38    @staticmethod38    @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)
4444
45            return intensifying_wrapper45            return intensifying_wrapper
4646
47        return intensifying_decorator47        return intensifying_decorator
4848
49    @property49    @property
50    def has_been_used(self):50    def has_been_used(self):
51        return self._has_been_used51        return self._has_been_used
5252
53    @has_been_used.setter53    @has_been_used.setter
54    def has_been_used(self, value):54    def has_been_used(self, value):
55        self._has_been_used = value55        self._has_been_used = value
5656
57    @property57    @property
58    def has_been_applied(self):58    def has_been_applied(self):
59        return self._has_been_applied59        return self._has_been_applied
6060
61    @has_been_applied.setter61    @has_been_applied.setter
62    def has_been_applied(self, value):62    def has_been_applied(self, value):
63        self._has_been_applied = value63        self._has_been_applied = value
6464
65    @property65    @property
66    def duration(self):66    def duration(self):
67        return self._duration67        return self._duration
6868
69    @duration.setter69    @duration.setter
70    def duration(self, value):70    def duration(self, value):
71        self._duration = value71        self._duration = value
7272
73    @property73    @property
74    def intensities(self):74    def intensities(self):
75        return self._intensities75        return self._intensities
7676
77    @intensities.setter77    @intensities.setter
78    def intensities(self, value):78    def intensities(self, value):
79        self._intensities = value79        self._intensities = value
8080
81    @property81    @property
82    def effects(self):82    def effects(self):
83        return self._effects83        return self._effects
8484
85    @effects.setter85    @effects.setter
86    def effects(self, value):86    def effects(self, value):
87        self._effects = value87        self._effects = value
8888
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)
9292
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_intensities94        new_potion._intensities = new_intensities
9595
96        self.has_been_used = True96        self.has_been_used = True
97        other.has_been_used = True97        other.has_been_used = True
9898
99        return new_potion99        return new_potion
100100
101    def _combine_effects(self, other):101    def _combine_effects(self, other):
102        new_effects = {}102        new_effects = {}
103103
104        for key, value in self.effects.items():104        for key, value in self.effects.items():
105            new_effects[key] = value105            new_effects[key] = value
106106
107        for key, value in other.effects.items():107        for key, value in other.effects.items():
108            new_effects[key] = value108            new_effects[key] = value
109109
110        return new_effects110        return new_effects
111111
112    def _combine_intensities(self, other):112    def _combine_intensities(self, other):
113        new_intensities = {}113        new_intensities = {}
114114
115        for key, value in self._intensities.items():115        for key, value in self._intensities.items():
116            new_intensities[key] = value116            new_intensities[key] = value
117117
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] += value120                new_intensities[key] += value
121            else:121            else:
122                new_intensities[key] = value122                new_intensities[key] = value
123123
124        return new_intensities124        return new_intensities
125125
126    def __mul__(self, other):126    def __mul__(self, other):
127        updated_intensities = {}127        updated_intensities = {}
128128
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()}
133133
134        new_potion = Potion(self._effects, self._duration)134        new_potion = Potion(self._effects, self._duration)
135        new_potion._intensities = updated_intensities135        new_potion._intensities = updated_intensities
136136
137        self.has_been_used = True137        self.has_been_used = True
138138
139        return new_potion139        return new_potion
140140
141    @staticmethod141    @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)
144144
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)
146146
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('съдържанието няма значение')
150150
151        new_effects = {}151        new_effects = {}
152        new_intensities = {}152        new_intensities = {}
153153
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] = intensity157                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] = difference162                    new_intensities[name] = difference
163163
164        new_potion = Potion(new_effects, self._duration)164        new_potion = Potion(new_effects, self._duration)
165        new_potion._intensities = new_intensities165        new_potion._intensities = new_intensities
166166
167        self.has_been_used = True167        self.has_been_used = True
168        other.has_been_used = True168        other.has_been_used = True
169169
170        return new_potion170        return new_potion
171171
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()}
174174
175        new_potion = Potion(self._effects, self._duration)175        new_potion = Potion(self._effects, self._duration)
176        new_potion._intensities = updated_intensities176        new_potion._intensities = updated_intensities
177177
178        self.has_been_used = True178        self.has_been_used = True
179179
180        return tuple(deepcopy(new_potion) for _ in range(other))180        return tuple(deepcopy(new_potion) for _ in range(other))
181181
n182    # Not sure which is the right convention here, so I had to check for a __deepcopy__ sample implementationn182    # 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_object186        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_object189        return new_object
190190
191    def __eq__(self, other):191    def __eq__(self, other):
192        return self._effects == other.effects and self._intensities == other.intensities192        return self._effects == other.effects and self._intensities == other.intensities
193193
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)
196196
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)
199199
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()
202202
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)
208208
209        self.has_been_applied = True209        self.has_been_applied = True
210210
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)
215215
216        return effects_map, masses216        return effects_map, masses
217217
218    @staticmethod218    @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))
221221
tt222    # Generated by IDE
222    def __hash__(self):223    def __hash__(self):
223        return super().__hash__()224        return super().__hash__()
224225
225226
226class ГоспожатаПоХимия:227class ГоспожатаПоХимия:
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 = {}
232233
233    def apply(self, target, potion):234    def apply(self, target, potion):
234        self._durations[potion] = potion.duration235        self._durations[potion] = potion.duration
235236
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                    break241                    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}
244245
245        self._potions_on_targets[potion] = target246        self._potions_on_targets[potion] = target
246        self._original_potions[potion] = copy.deepcopy(potion)247        self._original_potions[potion] = copy.deepcopy(potion)
247248
248        self._apply(target, potion)249        self._apply(target, potion)
249250
250    @staticmethod251    @staticmethod
251    def _apply(target, potion):252    def _apply(target, potion):
252        potion.get_applied(target)253        potion.get_applied(target)
253254
254    def tick(self):255    def tick(self):
255        for potion in self._durations:256        for potion in self._durations:
256            self._durations[potion] -= 1257            self._durations[potion] -= 1
257258
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]
259260
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)
264265
265            used_targets.append(self._potions_on_targets[potion])266            used_targets.append(self._potions_on_targets[potion])
266267
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]
271272
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
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op