Домашни > Работилница за отвари! > Решения > Решението на Сашо Василчев

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

9 точки общо

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

  1import cmath
  2
  3EFFECT_ERROR_TEXT = "Effect is depleted."
  4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
  5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
  6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
  7
  8
  9class PotionEffect:
 10    @staticmethod
 11    def custom_round(value):
 12        result = round(value)
 13        if cmath.isclose(
 14            result - value, 0.5
 15        ):  # the edge case where x.5 should be rounded down
 16            result -= 1
 17        return result
 18
 19    def __init__(self, func):
 20        self.func = func
 21        self.times = 1
 22        self.used = False
 23
 24    def __iadd__(self, other):
 25        self.times += other.times
 26        return self
 27
 28    def __isub__(self, other):
 29        self.times -= other.times
 30        return self
 31
 32    def __imul__(self, other):
 33        self.times = PotionEffect.custom_round(self.times * other)
 34        return self
 35
 36    def __itruediv__(self, other):
 37        self.times = PotionEffect.custom_round(self.times / other)
 38        return self
 39
 40    def copy(self):
 41        result = PotionEffect(self.func)
 42        result.times = self.times
 43        result.used = self.used
 44        return result
 45
 46    def __call__(self, target):
 47        if self.used:
 48            raise TypeError(EFFECT_ERROR_TEXT)
 49        for _ in range(self.times):
 50            self.func(target)
 51        self.used = True
 52
 53
 54class meta(type):
 55    def __new__(cls, name, bases, attr_dict):
 56        return type.__new__(cls, name, bases, attr_dict)
 57
 58
 59class Potion(metaclass=meta):
 60    @staticmethod
 61    def fake_func_for_component(target):
 62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
 63
 64    @staticmethod
 65    def update_dict_with_class_funcs(result_dict):
 66        result_dict.update(
 67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
 68        )
 69        result_dict["__init__"] = Potion.__init__
 70        result_dict["__eq__"] = Potion.__eq__
 71        result_dict["__lt__"] = Potion.__lt__
 72        result_dict["__gt__"] = Potion.__gt__
 73        result_dict.pop("__weakref__")
 74        return result_dict
 75
 76    def validate_state_on_operation(self):
 77        if self.is_component:
 78            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
 79        if self.is_used():
 80            raise TypeError(POTION_IS_USED_ERROR_TEXT)
 81
 82    def __init__(self, effects, duration):
 83        for key, value in effects.items():
 84            setattr(self, key, PotionEffect(value))
 85        self.duration = duration
 86        self.is_component = False
 87
 88    def is_used(self):
 89        for key in dir(self):
 90            value = getattr(self, key)
 91            if type(value) is PotionEffect and not value.used:
 92                return False
 93        return True
 94
 95    def __getattribute__(self, name):
 96        result = object.__getattribute__(self, name)
 97        if (
 98            object.__getattribute__(self, "is_component")
 99            and type(result) is PotionEffect
100        ):
101            fake_result = PotionEffect(Potion.fake_func_for_component)
102            fake_result.times = result.times
103            fake_result.used = result.used
104            return fake_result
105
106        return result
107
108    def __add__(self, other):
109        self.validate_state_on_operation()
110        other.validate_state_on_operation()
111        # transfering the methods from the object on the left side to dict,
112        # and if there are matching methods in the right side, we increace the intensity
113        result_dict = {}
114        for key in dir(self):
115            value = getattr(self, key)
116            if type(value) is PotionEffect and not value.used:
117                result_dict[key] = value.copy()
118                if key in dir(other):
119                    other_value = getattr(other, key)
120                    if not other_value.used:
121                        result_dict[key] += other_value
122
123        # transfering the methods that are only in the right side to the dict
124        for key in dir(other):
125            value = getattr(other, key)
126            if (
127                type(value) is PotionEffect
128                and not value.used
129                and not key in result_dict.keys()
130            ):
131                result_dict[key] = getattr(other, key).copy()
132
133        Potion.update_dict_with_class_funcs(result_dict)
134        result = type("Potion", (object,), result_dict)(
135            {}, max(self.duration, other.duration)
136        )
137        self.is_component = True
138        other.is_component = True
139
140        return result
141
142    def __mul__(self, other):
143        self.validate_state_on_operation()
144        result_dict = {}
145        # transfering the methods from the object to the dict and multiply them with the number
146        for key in dir(self):
147            value = getattr(self, key)
148            if type(value) is PotionEffect and not value.used:
149                result_dict[key] = value.copy()
150                result_dict[key] *= other
151
152        Potion.update_dict_with_class_funcs(result_dict)
153
154        result = meta("Potion", (object,), result_dict)({}, self.duration)
155        self.is_component = True
156
157        return result
158
159    def __sub__(self, other):
160        self.validate_state_on_operation()
161        other.validate_state_on_operation()
162        result_dict = {}
163        # validation that the substitution is valid
164        for key in dir(other):
165            value = getattr(other, key)
166            if type(value) is PotionEffect and not value.used and not key in dir(self):
167                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
168        # transfering the methods from the object on the left side to dict,
169        # and if there are matching methods in the right side, we subtract their intensity
170        for key in dir(self):
171            value = getattr(self, key)
172            if not type(value) is PotionEffect or value.used:
173                continue
174            result_dict[key] = value.copy()
175            if key in dir(other):
176                other_value = getattr(other, key)
177                if not other_value.used:
178                    result_dict[key] -= getattr(other, key)
179                    if result_dict[key].times <= 0:
180                        result_dict.pop(key)
181
182        Potion.update_dict_with_class_funcs(result_dict)
183        result = meta("Potion", (object,), result_dict)({}, self.duration)
184        self.is_component = True
185        other.is_component = True
186        return result
187
188    def __truediv__(self, other):
189        self.validate_state_on_operation()
190        # spliting the object into equal parts, where the intensity is devided by the number
191        result_list = []
192        for _ in range(other):
193            result_dict = {}
194            for key in dir(self):
195                value = getattr(self, key)
196                if type(value) is PotionEffect and not value.used:
197                    result_dict[key] = value.copy()
198                    result_dict[key] /= other
199
200            Potion.update_dict_with_class_funcs(result_dict)
201            result = meta("Potion", (object,), result_dict)({}, self.duration)
202            result_list.append(result)
203
204        self.is_component = True
205        return tuple(result_list)
206
207    def __eq__(self, other):
208        self.validate_state_on_operation()
209        other.validate_state_on_operation()
210        for key in dir(self):
211            value = getattr(self, key)
212            if type(value) is PotionEffect and not value.used:
213                if not key in dir(other):
214                    return False
215                other_value = getattr(other, key)
216                if value.times != other_value.times or value.used != other_value.used:
217                    return False
218
219        for key in dir(other):
220            value = getattr(other, key)
221            if type(value) is PotionEffect and not value.used and not key in dir(self):
222                return False
223
224        return True
225
226    def get_sum(self):
227        result = 0
228        for key in dir(self):
229            value = getattr(self, key)
230            if type(value) is PotionEffect and not value.used:
231                result += value.times
232        return result
233
234    def __gt__(self, other):
235        self.validate_state_on_operation()
236        other.validate_state_on_operation()
237        return self.get_sum() > other.get_sum()
238
239    def __lt__(self, other):
240        self.validate_state_on_operation()
241        other.validate_state_on_operation()
242        return self.get_sum() < other.get_sum()
243
244
245class ГоспожатаПоХимия:
246    @staticmethod
247    def calculate_molecular_mass(element):
248        return sum([ord(i) for i in element])
249
250    def __init__(self):
251        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
252        self.timer = {}
253
254    def apply_effect(self, target, effect):
255        # creating a revrse function to reverse the changes after the effect expires
256        old_attributes = vars(target).copy()
257        effect(target)
258        mid__attributes = vars(target).copy()
259
260        def reverse_effect():
261            new_attributes = vars(target).copy()
262            for key, value in new_attributes.items():
263                if not key in mid__attributes.keys():
264                    continue
265                is_old = key in old_attributes.keys()
266                if type(value) in (int, float):
267                    old_val = 0
268                    if is_old:
269                        old_val = old_attributes[key]
270
271                    if (
272                        value - (mid__attributes[key] - old_val)
273                    ) == old_val and not is_old:
274                        delattr(target, key)
275                    else:
276                        setattr(target, key, value - (mid__attributes[key] - old_val))
277                elif value == mid__attributes[key] and key in old_attributes.keys():
278                    setattr(target, key, old_attributes[key])
279                elif not is_old:
280                    delattr(target, key)
281
282        return reverse_effect
283
284    def apply(self, target, potion):
285        if potion.is_used():
286            raise TypeError(POTION_IS_USED_ERROR_TEXT)
287
288        if potion.is_component:  # this is probably useless, but just to be sure
289            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
290
291        if potion.duration == 0:
292            return
293        ordered_dir = sorted(
294            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
295        )
296        for key in ordered_dir:
297            value = getattr(potion, key)
298            if type(value) is PotionEffect and not value.used:
299                reverse_func = self.apply_effect(target, value)
300                self.timer[reverse_func] = potion.duration
301
302    def tick(self):
303        to_iterate = self.timer.copy().items()
304        for key, value in to_iterate:
305            self.timer[key] -= 1
306            if value <= 1:
307                key()
308                self.timer.pop(key)

.................F.F
======================================================================
FAIL: test_ticking_multiple_potions (test.TestГоспожатаПоХимия)
Test ticking after applying multiple potions which affect the same attribute.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 458, in test_ticking_multiple_potions
self.assertEqual(self._target.int_attr, 50)
AssertionError: 455 != 50

======================================================================
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.010s

FAILED (failures=2)

Дискусия
История

nn1 
1import cmath2import cmath
23
3EFFECT_ERROR_TEXT = "Effect is depleted."4EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."5POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"6INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."7POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
78
89
9class PotionEffect:10class PotionEffect:
10    @staticmethod11    @staticmethod
11    def custom_round(value):12    def custom_round(value):
12        result = round(value)13        result = round(value)
13        if cmath.isclose(14        if cmath.isclose(
14            result - value, 0.515            result - value, 0.5
15        ):  # the edge case where x.5 should be rounded down16        ):  # the edge case where x.5 should be rounded down
16            result -= 117            result -= 1
17        return result18        return result
1819
19    def __init__(self, func):20    def __init__(self, func):
20        self.func = func21        self.func = func
21        self.times = 122        self.times = 1
22        self.used = False23        self.used = False
2324
24    def __iadd__(self, other):25    def __iadd__(self, other):
25        self.times += other.times26        self.times += other.times
26        return self27        return self
2728
28    def __isub__(self, other):29    def __isub__(self, other):
29        self.times -= other.times30        self.times -= other.times
30        return self31        return self
3132
32    def __imul__(self, other):33    def __imul__(self, other):
33        self.times = PotionEffect.custom_round(self.times * other)34        self.times = PotionEffect.custom_round(self.times * other)
34        return self35        return self
3536
36    def __itruediv__(self, other):37    def __itruediv__(self, other):
37        self.times = PotionEffect.custom_round(self.times / other)38        self.times = PotionEffect.custom_round(self.times / other)
38        return self39        return self
3940
40    def copy(self):41    def copy(self):
41        result = PotionEffect(self.func)42        result = PotionEffect(self.func)
42        result.times = self.times43        result.times = self.times
43        result.used = self.used44        result.used = self.used
44        return result45        return result
4546
46    def __call__(self, target):47    def __call__(self, target):
47        if self.used:48        if self.used:
48            raise TypeError(EFFECT_ERROR_TEXT)49            raise TypeError(EFFECT_ERROR_TEXT)
49        for _ in range(self.times):50        for _ in range(self.times):
50            self.func(target)51            self.func(target)
51        self.used = True52        self.used = True
5253
5354
54class meta(type):55class meta(type):
55    def __new__(cls, name, bases, attr_dict):56    def __new__(cls, name, bases, attr_dict):
56        return type.__new__(cls, name, bases, attr_dict)57        return type.__new__(cls, name, bases, attr_dict)
5758
5859
59class Potion(metaclass=meta):60class Potion(metaclass=meta):
60    @staticmethod61    @staticmethod
61    def fake_func_for_component(target):62    def fake_func_for_component(target):
62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)63        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
6364
64    @staticmethod65    @staticmethod
65    def update_dict_with_class_funcs(result_dict):66    def update_dict_with_class_funcs(result_dict):
66        result_dict.update(67        result_dict.update(
67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}68            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
68        )69        )
69        result_dict["__init__"] = Potion.__init__70        result_dict["__init__"] = Potion.__init__
70        result_dict["__eq__"] = Potion.__eq__71        result_dict["__eq__"] = Potion.__eq__
71        result_dict["__lt__"] = Potion.__lt__72        result_dict["__lt__"] = Potion.__lt__
72        result_dict["__gt__"] = Potion.__gt__73        result_dict["__gt__"] = Potion.__gt__
73        result_dict.pop("__weakref__")74        result_dict.pop("__weakref__")
74        return result_dict75        return result_dict
7576
76    def validate_state_on_operation(self):77    def validate_state_on_operation(self):
77        if self.is_component:78        if self.is_component:
78            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)79            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
79        if self.is_used():80        if self.is_used():
80            raise TypeError(POTION_IS_USED_ERROR_TEXT)81            raise TypeError(POTION_IS_USED_ERROR_TEXT)
8182
82    def __init__(self, effects, duration):83    def __init__(self, effects, duration):
83        for key, value in effects.items():84        for key, value in effects.items():
84            setattr(self, key, PotionEffect(value))85            setattr(self, key, PotionEffect(value))
85        self.duration = duration86        self.duration = duration
86        self.is_component = False87        self.is_component = False
8788
88    def is_used(self):89    def is_used(self):
89        for key in dir(self):90        for key in dir(self):
90            value = getattr(self, key)91            value = getattr(self, key)
91            if type(value) is PotionEffect and not value.used:92            if type(value) is PotionEffect and not value.used:
92                return False93                return False
93        return True94        return True
9495
95    def __getattribute__(self, name):96    def __getattribute__(self, name):
96        result = object.__getattribute__(self, name)97        result = object.__getattribute__(self, name)
97        if (98        if (
98            object.__getattribute__(self, "is_component")99            object.__getattribute__(self, "is_component")
99            and type(result) is PotionEffect100            and type(result) is PotionEffect
100        ):101        ):
101            fake_result = PotionEffect(Potion.fake_func_for_component)102            fake_result = PotionEffect(Potion.fake_func_for_component)
102            fake_result.times = result.times103            fake_result.times = result.times
103            fake_result.used = result.used104            fake_result.used = result.used
104            return fake_result105            return fake_result
105106
106        return result107        return result
107108
108    def __add__(self, other):109    def __add__(self, other):
109        self.validate_state_on_operation()110        self.validate_state_on_operation()
110        other.validate_state_on_operation()111        other.validate_state_on_operation()
111        # transfering the methods from the object on the left side to dict,112        # transfering the methods from the object on the left side to dict,
112        # and if there are matching methods in the right side, we increace the intensity113        # and if there are matching methods in the right side, we increace the intensity
113        result_dict = {}114        result_dict = {}
114        for key in dir(self):115        for key in dir(self):
115            value = getattr(self, key)116            value = getattr(self, key)
116            if type(value) is PotionEffect and not value.used:117            if type(value) is PotionEffect and not value.used:
117                result_dict[key] = value.copy()118                result_dict[key] = value.copy()
118                if key in dir(other):119                if key in dir(other):
119                    other_value = getattr(other, key)120                    other_value = getattr(other, key)
120                    if not other_value.used:121                    if not other_value.used:
121                        result_dict[key] += other_value122                        result_dict[key] += other_value
122123
123        # transfering the methods that are only in the right side to the dict124        # transfering the methods that are only in the right side to the dict
124        for key in dir(other):125        for key in dir(other):
125            value = getattr(other, key)126            value = getattr(other, key)
126            if (127            if (
127                type(value) is PotionEffect128                type(value) is PotionEffect
128                and not value.used129                and not value.used
129                and not key in result_dict.keys()130                and not key in result_dict.keys()
130            ):131            ):
131                result_dict[key] = getattr(other, key).copy()132                result_dict[key] = getattr(other, key).copy()
132133
133        Potion.update_dict_with_class_funcs(result_dict)134        Potion.update_dict_with_class_funcs(result_dict)
134        result = type("Potion", (object,), result_dict)(135        result = type("Potion", (object,), result_dict)(
135            {}, max(self.duration, other.duration)136            {}, max(self.duration, other.duration)
136        )137        )
137        self.is_component = True138        self.is_component = True
138        other.is_component = True139        other.is_component = True
139140
140        return result141        return result
141142
142    def __mul__(self, other):143    def __mul__(self, other):
143        self.validate_state_on_operation()144        self.validate_state_on_operation()
144        result_dict = {}145        result_dict = {}
145        # transfering the methods from the object to the dict and multiply them with the number146        # transfering the methods from the object to the dict and multiply them with the number
146        for key in dir(self):147        for key in dir(self):
147            value = getattr(self, key)148            value = getattr(self, key)
148            if type(value) is PotionEffect and not value.used:149            if type(value) is PotionEffect and not value.used:
149                result_dict[key] = value.copy()150                result_dict[key] = value.copy()
150                result_dict[key] *= other151                result_dict[key] *= other
151152
152        Potion.update_dict_with_class_funcs(result_dict)153        Potion.update_dict_with_class_funcs(result_dict)
153154
154        result = meta("Potion", (object,), result_dict)({}, self.duration)155        result = meta("Potion", (object,), result_dict)({}, self.duration)
155        self.is_component = True156        self.is_component = True
156157
157        return result158        return result
158159
159    def __sub__(self, other):160    def __sub__(self, other):
160        self.validate_state_on_operation()161        self.validate_state_on_operation()
161        other.validate_state_on_operation()162        other.validate_state_on_operation()
162        result_dict = {}163        result_dict = {}
163        # validation that the substitution is valid164        # validation that the substitution is valid
164        for key in dir(other):165        for key in dir(other):
165            value = getattr(other, key)166            value = getattr(other, key)
166            if type(value) is PotionEffect and not value.used and not key in dir(self):167            if type(value) is PotionEffect and not value.used and not key in dir(self):
167                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)168                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
168        # transfering the methods from the object on the left side to dict,169        # transfering the methods from the object on the left side to dict,
169        # and if there are matching methods in the right side, we subtract their intensity170        # and if there are matching methods in the right side, we subtract their intensity
170        for key in dir(self):171        for key in dir(self):
171            value = getattr(self, key)172            value = getattr(self, key)
172            if not type(value) is PotionEffect or value.used:173            if not type(value) is PotionEffect or value.used:
173                continue174                continue
174            result_dict[key] = value.copy()175            result_dict[key] = value.copy()
175            if key in dir(other):176            if key in dir(other):
176                other_value = getattr(other, key)177                other_value = getattr(other, key)
177                if not other_value.used:178                if not other_value.used:
178                    result_dict[key] -= getattr(other, key)179                    result_dict[key] -= getattr(other, key)
t179                    if result_dict[key].times < 0:t180                    if result_dict[key].times <= 0:
180                        result_dict.pop(key)181                        result_dict.pop(key)
181182
182        Potion.update_dict_with_class_funcs(result_dict)183        Potion.update_dict_with_class_funcs(result_dict)
183        result = meta("Potion", (object,), result_dict)({}, self.duration)184        result = meta("Potion", (object,), result_dict)({}, self.duration)
184        self.is_component = True185        self.is_component = True
185        other.is_component = True186        other.is_component = True
186        return result187        return result
187188
188    def __truediv__(self, other):189    def __truediv__(self, other):
189        self.validate_state_on_operation()190        self.validate_state_on_operation()
190        # spliting the object into equal parts, where the intensity is devided by the number191        # spliting the object into equal parts, where the intensity is devided by the number
191        result_list = []192        result_list = []
192        for _ in range(other):193        for _ in range(other):
193            result_dict = {}194            result_dict = {}
194            for key in dir(self):195            for key in dir(self):
195                value = getattr(self, key)196                value = getattr(self, key)
196                if type(value) is PotionEffect and not value.used:197                if type(value) is PotionEffect and not value.used:
197                    result_dict[key] = value.copy()198                    result_dict[key] = value.copy()
198                    result_dict[key] /= other199                    result_dict[key] /= other
199200
200            Potion.update_dict_with_class_funcs(result_dict)201            Potion.update_dict_with_class_funcs(result_dict)
201            result = meta("Potion", (object,), result_dict)({}, self.duration)202            result = meta("Potion", (object,), result_dict)({}, self.duration)
202            result_list.append(result)203            result_list.append(result)
203204
204        self.is_component = True205        self.is_component = True
205        return tuple(result_list)206        return tuple(result_list)
206207
207    def __eq__(self, other):208    def __eq__(self, other):
208        self.validate_state_on_operation()209        self.validate_state_on_operation()
209        other.validate_state_on_operation()210        other.validate_state_on_operation()
210        for key in dir(self):211        for key in dir(self):
211            value = getattr(self, key)212            value = getattr(self, key)
212            if type(value) is PotionEffect and not value.used:213            if type(value) is PotionEffect and not value.used:
213                if not key in dir(other):214                if not key in dir(other):
214                    return False215                    return False
215                other_value = getattr(other, key)216                other_value = getattr(other, key)
216                if value.times != other_value.times or value.used != other_value.used:217                if value.times != other_value.times or value.used != other_value.used:
217                    return False218                    return False
218219
219        for key in dir(other):220        for key in dir(other):
220            value = getattr(other, key)221            value = getattr(other, key)
221            if type(value) is PotionEffect and not value.used and not key in dir(self):222            if type(value) is PotionEffect and not value.used and not key in dir(self):
222                return False223                return False
223224
224        return True225        return True
225226
226    def get_sum(self):227    def get_sum(self):
227        result = 0228        result = 0
228        for key in dir(self):229        for key in dir(self):
229            value = getattr(self, key)230            value = getattr(self, key)
230            if type(value) is PotionEffect and not value.used:231            if type(value) is PotionEffect and not value.used:
231                result += value.times232                result += value.times
232        return result233        return result
233234
234    def __gt__(self, other):235    def __gt__(self, other):
235        self.validate_state_on_operation()236        self.validate_state_on_operation()
236        other.validate_state_on_operation()237        other.validate_state_on_operation()
237        return self.get_sum() > other.get_sum()238        return self.get_sum() > other.get_sum()
238239
239    def __lt__(self, other):240    def __lt__(self, other):
240        self.validate_state_on_operation()241        self.validate_state_on_operation()
241        other.validate_state_on_operation()242        other.validate_state_on_operation()
242        return self.get_sum() < other.get_sum()243        return self.get_sum() < other.get_sum()
243244
244245
245class ГоспожатаПоХимия:246class ГоспожатаПоХимия:
246    @staticmethod247    @staticmethod
247    def calculate_molecular_mass(element):248    def calculate_molecular_mass(element):
248        return sum([ord(i) for i in element])249        return sum([ord(i) for i in element])
249250
250    def __init__(self):251    def __init__(self):
251        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values252        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
252        self.timer = {}253        self.timer = {}
253254
254    def apply_effect(self, target, effect):255    def apply_effect(self, target, effect):
255        # creating a revrse function to reverse the changes after the effect expires256        # creating a revrse function to reverse the changes after the effect expires
256        old_attributes = vars(target).copy()257        old_attributes = vars(target).copy()
257        effect(target)258        effect(target)
258        mid__attributes = vars(target).copy()259        mid__attributes = vars(target).copy()
259260
260        def reverse_effect():261        def reverse_effect():
261            new_attributes = vars(target).copy()262            new_attributes = vars(target).copy()
262            for key, value in new_attributes.items():263            for key, value in new_attributes.items():
263                if not key in mid__attributes.keys():264                if not key in mid__attributes.keys():
264                    continue265                    continue
265                is_old = key in old_attributes.keys()266                is_old = key in old_attributes.keys()
266                if type(value) in (int, float):267                if type(value) in (int, float):
267                    old_val = 0268                    old_val = 0
268                    if is_old:269                    if is_old:
269                        old_val = old_attributes[key]270                        old_val = old_attributes[key]
270271
271                    if (272                    if (
272                        value - (mid__attributes[key] - old_val)273                        value - (mid__attributes[key] - old_val)
273                    ) == old_val and not is_old:274                    ) == old_val and not is_old:
274                        delattr(target, key)275                        delattr(target, key)
275                    else:276                    else:
276                        setattr(target, key, value - (mid__attributes[key] - old_val))277                        setattr(target, key, value - (mid__attributes[key] - old_val))
277                elif value == mid__attributes[key] and key in old_attributes.keys():278                elif value == mid__attributes[key] and key in old_attributes.keys():
278                    setattr(target, key, old_attributes[key])279                    setattr(target, key, old_attributes[key])
279                elif not is_old:280                elif not is_old:
280                    delattr(target, key)281                    delattr(target, key)
281282
282        return reverse_effect283        return reverse_effect
283284
284    def apply(self, target, potion):285    def apply(self, target, potion):
285        if potion.is_used():286        if potion.is_used():
286            raise TypeError(POTION_IS_USED_ERROR_TEXT)287            raise TypeError(POTION_IS_USED_ERROR_TEXT)
287288
288        if potion.is_component:  # this is probably useless, but just to be sure289        if potion.is_component:  # this is probably useless, but just to be sure
289            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)290            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
290291
291        if potion.duration == 0:292        if potion.duration == 0:
292            return293            return
293        ordered_dir = sorted(294        ordered_dir = sorted(
294            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True295            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
295        )296        )
296        for key in ordered_dir:297        for key in ordered_dir:
297            value = getattr(potion, key)298            value = getattr(potion, key)
298            if type(value) is PotionEffect and not value.used:299            if type(value) is PotionEffect and not value.used:
299                reverse_func = self.apply_effect(target, value)300                reverse_func = self.apply_effect(target, value)
300                self.timer[reverse_func] = potion.duration301                self.timer[reverse_func] = potion.duration
301302
302    def tick(self):303    def tick(self):
303        to_iterate = self.timer.copy().items()304        to_iterate = self.timer.copy().items()
304        for key, value in to_iterate:305        for key, value in to_iterate:
305            self.timer[key] -= 1306            self.timer[key] -= 1
306            if value <= 1:307            if value <= 1:
307                key()308                key()
308                self.timer.pop(key)309                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
77
88
9class PotionEffect:9class PotionEffect:
10    @staticmethod10    @staticmethod
11    def custom_round(value):11    def custom_round(value):
12        result = round(value)12        result = round(value)
13        if cmath.isclose(13        if cmath.isclose(
14            result - value, 0.514            result - value, 0.5
15        ):  # the edge case where x.5 should be rounded down15        ):  # the edge case where x.5 should be rounded down
16            result -= 116            result -= 1
17        return result17        return result
1818
19    def __init__(self, func):19    def __init__(self, func):
20        self.func = func20        self.func = func
21        self.times = 121        self.times = 1
22        self.used = False22        self.used = False
2323
24    def __iadd__(self, other):24    def __iadd__(self, other):
25        self.times += other.times25        self.times += other.times
26        return self26        return self
2727
28    def __isub__(self, other):28    def __isub__(self, other):
29        self.times -= other.times29        self.times -= other.times
30        return self30        return self
3131
32    def __imul__(self, other):32    def __imul__(self, other):
33        self.times = PotionEffect.custom_round(self.times * other)33        self.times = PotionEffect.custom_round(self.times * other)
34        return self34        return self
3535
36    def __itruediv__(self, other):36    def __itruediv__(self, other):
37        self.times = PotionEffect.custom_round(self.times / other)37        self.times = PotionEffect.custom_round(self.times / other)
38        return self38        return self
3939
40    def copy(self):40    def copy(self):
41        result = PotionEffect(self.func)41        result = PotionEffect(self.func)
42        result.times = self.times42        result.times = self.times
43        result.used = self.used43        result.used = self.used
44        return result44        return result
4545
46    def __call__(self, target):46    def __call__(self, target):
47        if self.used:47        if self.used:
48            raise TypeError(EFFECT_ERROR_TEXT)48            raise TypeError(EFFECT_ERROR_TEXT)
49        for _ in range(self.times):49        for _ in range(self.times):
50            self.func(target)50            self.func(target)
51        self.used = True51        self.used = True
5252
5353
54class meta(type):54class meta(type):
55    def __new__(cls, name, bases, attr_dict):55    def __new__(cls, name, bases, attr_dict):
56        return type.__new__(cls, name, bases, attr_dict)56        return type.__new__(cls, name, bases, attr_dict)
5757
5858
59class Potion(metaclass=meta):59class Potion(metaclass=meta):
60    @staticmethod60    @staticmethod
61    def fake_func_for_component(target):61    def fake_func_for_component(target):
62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
6363
64    @staticmethod64    @staticmethod
65    def update_dict_with_class_funcs(result_dict):65    def update_dict_with_class_funcs(result_dict):
66        result_dict.update(66        result_dict.update(
67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
68        )68        )
69        result_dict["__init__"] = Potion.__init__69        result_dict["__init__"] = Potion.__init__
70        result_dict["__eq__"] = Potion.__eq__70        result_dict["__eq__"] = Potion.__eq__
71        result_dict["__lt__"] = Potion.__lt__71        result_dict["__lt__"] = Potion.__lt__
72        result_dict["__gt__"] = Potion.__gt__72        result_dict["__gt__"] = Potion.__gt__
73        result_dict.pop("__weakref__")73        result_dict.pop("__weakref__")
74        return result_dict74        return result_dict
7575
76    def validate_state_on_operation(self):76    def validate_state_on_operation(self):
77        if self.is_component:77        if self.is_component:
78            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)78            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
79        if self.is_used():79        if self.is_used():
80            raise TypeError(POTION_IS_USED_ERROR_TEXT)80            raise TypeError(POTION_IS_USED_ERROR_TEXT)
8181
82    def __init__(self, effects, duration):82    def __init__(self, effects, duration):
83        for key, value in effects.items():83        for key, value in effects.items():
84            setattr(self, key, PotionEffect(value))84            setattr(self, key, PotionEffect(value))
85        self.duration = duration85        self.duration = duration
86        self.is_component = False86        self.is_component = False
8787
88    def is_used(self):88    def is_used(self):
89        for key in dir(self):89        for key in dir(self):
90            value = getattr(self, key)90            value = getattr(self, key)
91            if type(value) is PotionEffect and not value.used:91            if type(value) is PotionEffect and not value.used:
92                return False92                return False
93        return True93        return True
9494
95    def __getattribute__(self, name):95    def __getattribute__(self, name):
96        result = object.__getattribute__(self, name)96        result = object.__getattribute__(self, name)
97        if (97        if (
98            object.__getattribute__(self, "is_component")98            object.__getattribute__(self, "is_component")
99            and type(result) is PotionEffect99            and type(result) is PotionEffect
100        ):100        ):
101            fake_result = PotionEffect(Potion.fake_func_for_component)101            fake_result = PotionEffect(Potion.fake_func_for_component)
102            fake_result.times = result.times102            fake_result.times = result.times
103            fake_result.used = result.used103            fake_result.used = result.used
104            return fake_result104            return fake_result
105105
106        return result106        return result
107107
108    def __add__(self, other):108    def __add__(self, other):
109        self.validate_state_on_operation()109        self.validate_state_on_operation()
110        other.validate_state_on_operation()110        other.validate_state_on_operation()
111        # transfering the methods from the object on the left side to dict,111        # transfering the methods from the object on the left side to dict,
112        # and if there are matching methods in the right side, we increace the intensity112        # and if there are matching methods in the right side, we increace the intensity
113        result_dict = {}113        result_dict = {}
114        for key in dir(self):114        for key in dir(self):
115            value = getattr(self, key)115            value = getattr(self, key)
116            if type(value) is PotionEffect and not value.used:116            if type(value) is PotionEffect and not value.used:
117                result_dict[key] = value.copy()117                result_dict[key] = value.copy()
118                if key in dir(other):118                if key in dir(other):
119                    other_value = getattr(other, key)119                    other_value = getattr(other, key)
120                    if not other_value.used:120                    if not other_value.used:
121                        result_dict[key] += other_value121                        result_dict[key] += other_value
122122
123        # transfering the methods that are only in the right side to the dict123        # transfering the methods that are only in the right side to the dict
124        for key in dir(other):124        for key in dir(other):
125            value = getattr(other, key)125            value = getattr(other, key)
126            if (126            if (
127                type(value) is PotionEffect127                type(value) is PotionEffect
128                and not value.used128                and not value.used
129                and not key in result_dict.keys()129                and not key in result_dict.keys()
130            ):130            ):
131                result_dict[key] = getattr(other, key).copy()131                result_dict[key] = getattr(other, key).copy()
132132
133        Potion.update_dict_with_class_funcs(result_dict)133        Potion.update_dict_with_class_funcs(result_dict)
134        result = type("Potion", (object,), result_dict)(134        result = type("Potion", (object,), result_dict)(
135            {}, max(self.duration, other.duration)135            {}, max(self.duration, other.duration)
136        )136        )
137        self.is_component = True137        self.is_component = True
138        other.is_component = True138        other.is_component = True
139139
140        return result140        return result
141141
142    def __mul__(self, other):142    def __mul__(self, other):
143        self.validate_state_on_operation()143        self.validate_state_on_operation()
144        result_dict = {}144        result_dict = {}
145        # transfering the methods from the object to the dict and multiply them with the number145        # transfering the methods from the object to the dict and multiply them with the number
146        for key in dir(self):146        for key in dir(self):
147            value = getattr(self, key)147            value = getattr(self, key)
148            if type(value) is PotionEffect and not value.used:148            if type(value) is PotionEffect and not value.used:
149                result_dict[key] = value.copy()149                result_dict[key] = value.copy()
150                result_dict[key] *= other150                result_dict[key] *= other
151151
152        Potion.update_dict_with_class_funcs(result_dict)152        Potion.update_dict_with_class_funcs(result_dict)
153153
154        result = meta("Potion", (object,), result_dict)({}, self.duration)154        result = meta("Potion", (object,), result_dict)({}, self.duration)
155        self.is_component = True155        self.is_component = True
156156
157        return result157        return result
158158
159    def __sub__(self, other):159    def __sub__(self, other):
160        self.validate_state_on_operation()160        self.validate_state_on_operation()
161        other.validate_state_on_operation()161        other.validate_state_on_operation()
162        result_dict = {}162        result_dict = {}
163        # validation that the substitution is valid163        # validation that the substitution is valid
164        for key in dir(other):164        for key in dir(other):
165            value = getattr(other, key)165            value = getattr(other, key)
166            if type(value) is PotionEffect and not value.used and not key in dir(self):166            if type(value) is PotionEffect and not value.used and not key in dir(self):
167                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)167                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
168        # transfering the methods from the object on the left side to dict,168        # transfering the methods from the object on the left side to dict,
169        # and if there are matching methods in the right side, we subtract their intensity169        # and if there are matching methods in the right side, we subtract their intensity
170        for key in dir(self):170        for key in dir(self):
171            value = getattr(self, key)171            value = getattr(self, key)
172            if not type(value) is PotionEffect or value.used:172            if not type(value) is PotionEffect or value.used:
173                continue173                continue
174            result_dict[key] = value.copy()174            result_dict[key] = value.copy()
175            if key in dir(other):175            if key in dir(other):
176                other_value = getattr(other, key)176                other_value = getattr(other, key)
177                if not other_value.used:177                if not other_value.used:
178                    result_dict[key] -= getattr(other, key)178                    result_dict[key] -= getattr(other, key)
t179                    if result_dict[key].times <= 0:t179                    if result_dict[key].times < 0:
180                        result_dict.pop(key)180                        result_dict.pop(key)
181181
182        Potion.update_dict_with_class_funcs(result_dict)182        Potion.update_dict_with_class_funcs(result_dict)
183        result = meta("Potion", (object,), result_dict)({}, self.duration)183        result = meta("Potion", (object,), result_dict)({}, self.duration)
184        self.is_component = True184        self.is_component = True
185        other.is_component = True185        other.is_component = True
186        return result186        return result
187187
188    def __truediv__(self, other):188    def __truediv__(self, other):
189        self.validate_state_on_operation()189        self.validate_state_on_operation()
190        # spliting the object into equal parts, where the intensity is devided by the number190        # spliting the object into equal parts, where the intensity is devided by the number
191        result_list = []191        result_list = []
192        for _ in range(other):192        for _ in range(other):
193            result_dict = {}193            result_dict = {}
194            for key in dir(self):194            for key in dir(self):
195                value = getattr(self, key)195                value = getattr(self, key)
196                if type(value) is PotionEffect and not value.used:196                if type(value) is PotionEffect and not value.used:
197                    result_dict[key] = value.copy()197                    result_dict[key] = value.copy()
198                    result_dict[key] /= other198                    result_dict[key] /= other
199199
200            Potion.update_dict_with_class_funcs(result_dict)200            Potion.update_dict_with_class_funcs(result_dict)
201            result = meta("Potion", (object,), result_dict)({}, self.duration)201            result = meta("Potion", (object,), result_dict)({}, self.duration)
202            result_list.append(result)202            result_list.append(result)
203203
204        self.is_component = True204        self.is_component = True
205        return tuple(result_list)205        return tuple(result_list)
206206
207    def __eq__(self, other):207    def __eq__(self, other):
208        self.validate_state_on_operation()208        self.validate_state_on_operation()
209        other.validate_state_on_operation()209        other.validate_state_on_operation()
210        for key in dir(self):210        for key in dir(self):
211            value = getattr(self, key)211            value = getattr(self, key)
212            if type(value) is PotionEffect and not value.used:212            if type(value) is PotionEffect and not value.used:
213                if not key in dir(other):213                if not key in dir(other):
214                    return False214                    return False
215                other_value = getattr(other, key)215                other_value = getattr(other, key)
216                if value.times != other_value.times or value.used != other_value.used:216                if value.times != other_value.times or value.used != other_value.used:
217                    return False217                    return False
218218
219        for key in dir(other):219        for key in dir(other):
220            value = getattr(other, key)220            value = getattr(other, key)
221            if type(value) is PotionEffect and not value.used and not key in dir(self):221            if type(value) is PotionEffect and not value.used and not key in dir(self):
222                return False222                return False
223223
224        return True224        return True
225225
226    def get_sum(self):226    def get_sum(self):
227        result = 0227        result = 0
228        for key in dir(self):228        for key in dir(self):
229            value = getattr(self, key)229            value = getattr(self, key)
230            if type(value) is PotionEffect and not value.used:230            if type(value) is PotionEffect and not value.used:
231                result += value.times231                result += value.times
232        return result232        return result
233233
234    def __gt__(self, other):234    def __gt__(self, other):
235        self.validate_state_on_operation()235        self.validate_state_on_operation()
236        other.validate_state_on_operation()236        other.validate_state_on_operation()
237        return self.get_sum() > other.get_sum()237        return self.get_sum() > other.get_sum()
238238
239    def __lt__(self, other):239    def __lt__(self, other):
240        self.validate_state_on_operation()240        self.validate_state_on_operation()
241        other.validate_state_on_operation()241        other.validate_state_on_operation()
242        return self.get_sum() < other.get_sum()242        return self.get_sum() < other.get_sum()
243243
244244
245class ГоспожатаПоХимия:245class ГоспожатаПоХимия:
246    @staticmethod246    @staticmethod
247    def calculate_molecular_mass(element):247    def calculate_molecular_mass(element):
248        return sum([ord(i) for i in element])248        return sum([ord(i) for i in element])
249249
250    def __init__(self):250    def __init__(self):
251        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values251        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
252        self.timer = {}252        self.timer = {}
253253
254    def apply_effect(self, target, effect):254    def apply_effect(self, target, effect):
255        # creating a revrse function to reverse the changes after the effect expires255        # creating a revrse function to reverse the changes after the effect expires
256        old_attributes = vars(target).copy()256        old_attributes = vars(target).copy()
257        effect(target)257        effect(target)
258        mid__attributes = vars(target).copy()258        mid__attributes = vars(target).copy()
259259
260        def reverse_effect():260        def reverse_effect():
261            new_attributes = vars(target).copy()261            new_attributes = vars(target).copy()
262            for key, value in new_attributes.items():262            for key, value in new_attributes.items():
263                if not key in mid__attributes.keys():263                if not key in mid__attributes.keys():
264                    continue264                    continue
265                is_old = key in old_attributes.keys()265                is_old = key in old_attributes.keys()
266                if type(value) in (int, float):266                if type(value) in (int, float):
267                    old_val = 0267                    old_val = 0
268                    if is_old:268                    if is_old:
269                        old_val = old_attributes[key]269                        old_val = old_attributes[key]
270270
271                    if (271                    if (
272                        value - (mid__attributes[key] - old_val)272                        value - (mid__attributes[key] - old_val)
273                    ) == old_val and not is_old:273                    ) == old_val and not is_old:
274                        delattr(target, key)274                        delattr(target, key)
275                    else:275                    else:
276                        setattr(target, key, value - (mid__attributes[key] - old_val))276                        setattr(target, key, value - (mid__attributes[key] - old_val))
277                elif value == mid__attributes[key] and key in old_attributes.keys():277                elif value == mid__attributes[key] and key in old_attributes.keys():
278                    setattr(target, key, old_attributes[key])278                    setattr(target, key, old_attributes[key])
279                elif not is_old:279                elif not is_old:
280                    delattr(target, key)280                    delattr(target, key)
281281
282        return reverse_effect282        return reverse_effect
283283
284    def apply(self, target, potion):284    def apply(self, target, potion):
285        if potion.is_used():285        if potion.is_used():
286            raise TypeError(POTION_IS_USED_ERROR_TEXT)286            raise TypeError(POTION_IS_USED_ERROR_TEXT)
287287
288        if potion.is_component:  # this is probably useless, but just to be sure288        if potion.is_component:  # this is probably useless, but just to be sure
289            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)289            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
290290
291        if potion.duration == 0:291        if potion.duration == 0:
292            return292            return
293        ordered_dir = sorted(293        ordered_dir = sorted(
294            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True294            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
295        )295        )
296        for key in ordered_dir:296        for key in ordered_dir:
297            value = getattr(potion, key)297            value = getattr(potion, key)
298            if type(value) is PotionEffect and not value.used:298            if type(value) is PotionEffect and not value.used:
299                reverse_func = self.apply_effect(target, value)299                reverse_func = self.apply_effect(target, value)
300                self.timer[reverse_func] = potion.duration300                self.timer[reverse_func] = potion.duration
301301
302    def tick(self):302    def tick(self):
303        to_iterate = self.timer.copy().items()303        to_iterate = self.timer.copy().items()
304        for key, value in to_iterate:304        for key, value in to_iterate:
305            self.timer[key] -= 1305            self.timer[key] -= 1
306            if value <= 1:306            if value <= 1:
307                key()307                key()
308                self.timer.pop(key)308                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
77
88
9class PotionEffect:9class PotionEffect:
10    @staticmethod10    @staticmethod
11    def custom_round(value):11    def custom_round(value):
12        result = round(value)12        result = round(value)
13        if cmath.isclose(13        if cmath.isclose(
14            result - value, 0.514            result - value, 0.5
15        ):  # the edge case where x.5 should be rounded down15        ):  # the edge case where x.5 should be rounded down
16            result -= 116            result -= 1
17        return result17        return result
1818
19    def __init__(self, func):19    def __init__(self, func):
20        self.func = func20        self.func = func
21        self.times = 121        self.times = 1
22        self.used = False22        self.used = False
2323
24    def __iadd__(self, other):24    def __iadd__(self, other):
25        self.times += other.times25        self.times += other.times
26        return self26        return self
2727
28    def __isub__(self, other):28    def __isub__(self, other):
29        self.times -= other.times29        self.times -= other.times
30        return self30        return self
3131
32    def __imul__(self, other):32    def __imul__(self, other):
33        self.times = PotionEffect.custom_round(self.times * other)33        self.times = PotionEffect.custom_round(self.times * other)
34        return self34        return self
3535
36    def __itruediv__(self, other):36    def __itruediv__(self, other):
37        self.times = PotionEffect.custom_round(self.times / other)37        self.times = PotionEffect.custom_round(self.times / other)
38        return self38        return self
3939
40    def copy(self):40    def copy(self):
41        result = PotionEffect(self.func)41        result = PotionEffect(self.func)
42        result.times = self.times42        result.times = self.times
43        result.used = self.used43        result.used = self.used
44        return result44        return result
4545
46    def __call__(self, target):46    def __call__(self, target):
47        if self.used:47        if self.used:
48            raise TypeError(EFFECT_ERROR_TEXT)48            raise TypeError(EFFECT_ERROR_TEXT)
49        for _ in range(self.times):49        for _ in range(self.times):
50            self.func(target)50            self.func(target)
51        self.used = True51        self.used = True
5252
5353
54class meta(type):54class meta(type):
55    def __new__(cls, name, bases, attr_dict):55    def __new__(cls, name, bases, attr_dict):
56        return type.__new__(cls, name, bases, attr_dict)56        return type.__new__(cls, name, bases, attr_dict)
5757
5858
59class Potion(metaclass=meta):59class Potion(metaclass=meta):
60    @staticmethod60    @staticmethod
n61    def fake_func(target):n61    def fake_func_for_component(target):
62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
6363
64    @staticmethod64    @staticmethod
65    def update_dict_with_class_funcs(result_dict):65    def update_dict_with_class_funcs(result_dict):
66        result_dict.update(66        result_dict.update(
67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
68        )68        )
69        result_dict["__init__"] = Potion.__init__69        result_dict["__init__"] = Potion.__init__
nn70        result_dict["__eq__"] = Potion.__eq__
71        result_dict["__lt__"] = Potion.__lt__
72        result_dict["__gt__"] = Potion.__gt__
70        result_dict.pop("__weakref__")73        result_dict.pop("__weakref__")
71        return result_dict74        return result_dict
7275
73    def validate_state_on_operation(self):76    def validate_state_on_operation(self):
74        if self.is_component:77        if self.is_component:
75            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)78            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
76        if self.is_used():79        if self.is_used():
77            raise TypeError(POTION_IS_USED_ERROR_TEXT)80            raise TypeError(POTION_IS_USED_ERROR_TEXT)
7881
79    def __init__(self, effects, duration):82    def __init__(self, effects, duration):
80        for key, value in effects.items():83        for key, value in effects.items():
81            setattr(self, key, PotionEffect(value))84            setattr(self, key, PotionEffect(value))
82        self.duration = duration85        self.duration = duration
83        self.is_component = False86        self.is_component = False
8487
85    def is_used(self):88    def is_used(self):
86        for key in dir(self):89        for key in dir(self):
87            value = getattr(self, key)90            value = getattr(self, key)
88            if type(value) is PotionEffect and not value.used:91            if type(value) is PotionEffect and not value.used:
89                return False92                return False
90        return True93        return True
9194
92    def __getattribute__(self, name):95    def __getattribute__(self, name):
93        result = object.__getattribute__(self, name)96        result = object.__getattribute__(self, name)
94        if (97        if (
95            object.__getattribute__(self, "is_component")98            object.__getattribute__(self, "is_component")
96            and type(result) is PotionEffect99            and type(result) is PotionEffect
97        ):100        ):
n98            fake_result = PotionEffect(Potion.fake_func)n101            fake_result = PotionEffect(Potion.fake_func_for_component)
99            fake_result.times = result.times102            fake_result.times = result.times
100            fake_result.used = result.used103            fake_result.used = result.used
101            return fake_result104            return fake_result
102105
103        return result106        return result
104107
105    def __add__(self, other):108    def __add__(self, other):
106        self.validate_state_on_operation()109        self.validate_state_on_operation()
107        other.validate_state_on_operation()110        other.validate_state_on_operation()
108        # transfering the methods from the object on the left side to dict,111        # transfering the methods from the object on the left side to dict,
109        # and if there are matching methods in the right side, we increace the intensity112        # and if there are matching methods in the right side, we increace the intensity
110        result_dict = {}113        result_dict = {}
111        for key in dir(self):114        for key in dir(self):
112            value = getattr(self, key)115            value = getattr(self, key)
113            if type(value) is PotionEffect and not value.used:116            if type(value) is PotionEffect and not value.used:
114                result_dict[key] = value.copy()117                result_dict[key] = value.copy()
115                if key in dir(other):118                if key in dir(other):
116                    other_value = getattr(other, key)119                    other_value = getattr(other, key)
117                    if not other_value.used:120                    if not other_value.used:
118                        result_dict[key] += other_value121                        result_dict[key] += other_value
119122
120        # transfering the methods that are only in the right side to the dict123        # transfering the methods that are only in the right side to the dict
121        for key in dir(other):124        for key in dir(other):
122            value = getattr(other, key)125            value = getattr(other, key)
n123            if type(value) is PotionEffect and not key in dir(self) and not value.used:n126            if (
127                type(value) is PotionEffect
128                and not value.used
129                and not key in result_dict.keys()
130            ):
124                result_dict[key] = getattr(other, key).copy()131                result_dict[key] = getattr(other, key).copy()
125132
126        Potion.update_dict_with_class_funcs(result_dict)133        Potion.update_dict_with_class_funcs(result_dict)
127        result = type("Potion", (object,), result_dict)(134        result = type("Potion", (object,), result_dict)(
128            {}, max(self.duration, other.duration)135            {}, max(self.duration, other.duration)
129        )136        )
130        self.is_component = True137        self.is_component = True
131        other.is_component = True138        other.is_component = True
132139
133        return result140        return result
134141
135    def __mul__(self, other):142    def __mul__(self, other):
136        self.validate_state_on_operation()143        self.validate_state_on_operation()
137        result_dict = {}144        result_dict = {}
138        # transfering the methods from the object to the dict and multiply them with the number145        # transfering the methods from the object to the dict and multiply them with the number
139        for key in dir(self):146        for key in dir(self):
140            value = getattr(self, key)147            value = getattr(self, key)
n141            if type(value) is PotionEffect:n148            if type(value) is PotionEffect and not value.used:
142                result_dict[key] = value.copy()149                result_dict[key] = value.copy()
143                result_dict[key] *= other150                result_dict[key] *= other
144151
145        Potion.update_dict_with_class_funcs(result_dict)152        Potion.update_dict_with_class_funcs(result_dict)
146153
147        result = meta("Potion", (object,), result_dict)({}, self.duration)154        result = meta("Potion", (object,), result_dict)({}, self.duration)
148        self.is_component = True155        self.is_component = True
149156
150        return result157        return result
151158
152    def __sub__(self, other):159    def __sub__(self, other):
153        self.validate_state_on_operation()160        self.validate_state_on_operation()
154        other.validate_state_on_operation()161        other.validate_state_on_operation()
155        result_dict = {}162        result_dict = {}
156        # validation that the substitution is valid163        # validation that the substitution is valid
157        for key in dir(other):164        for key in dir(other):
158            value = getattr(other, key)165            value = getattr(other, key)
n159            if type(value) is PotionEffect and not key in dir(self):n166            if type(value) is PotionEffect and not value.used and not key in dir(self):
160                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)167                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
161        # transfering the methods from the object on the left side to dict,168        # transfering the methods from the object on the left side to dict,
162        # and if there are matching methods in the right side, we subtract their intensity169        # and if there are matching methods in the right side, we subtract their intensity
163        for key in dir(self):170        for key in dir(self):
164            value = getattr(self, key)171            value = getattr(self, key)
n165            if not type(value) is PotionEffect:n172            if not type(value) is PotionEffect or value.used:
166                continue173                continue
167            result_dict[key] = value.copy()174            result_dict[key] = value.copy()
168            if key in dir(other):175            if key in dir(other):
169                other_value = getattr(other, key)176                other_value = getattr(other, key)
170                if not other_value.used:177                if not other_value.used:
171                    result_dict[key] -= getattr(other, key)178                    result_dict[key] -= getattr(other, key)
172                    if result_dict[key].times <= 0:179                    if result_dict[key].times <= 0:
173                        result_dict.pop(key)180                        result_dict.pop(key)
174181
175        Potion.update_dict_with_class_funcs(result_dict)182        Potion.update_dict_with_class_funcs(result_dict)
176        result = meta("Potion", (object,), result_dict)({}, self.duration)183        result = meta("Potion", (object,), result_dict)({}, self.duration)
177        self.is_component = True184        self.is_component = True
178        other.is_component = True185        other.is_component = True
179        return result186        return result
180187
181    def __truediv__(self, other):188    def __truediv__(self, other):
182        self.validate_state_on_operation()189        self.validate_state_on_operation()
183        # spliting the object into equal parts, where the intensity is devided by the number190        # spliting the object into equal parts, where the intensity is devided by the number
184        result_list = []191        result_list = []
185        for _ in range(other):192        for _ in range(other):
186            result_dict = {}193            result_dict = {}
187            for key in dir(self):194            for key in dir(self):
188                value = getattr(self, key)195                value = getattr(self, key)
n189                if type(value) is PotionEffect:n196                if type(value) is PotionEffect and not value.used:
190                    result_dict[key] = value.copy()197                    result_dict[key] = value.copy()
191                    result_dict[key] /= other198                    result_dict[key] /= other
192199
193            Potion.update_dict_with_class_funcs(result_dict)200            Potion.update_dict_with_class_funcs(result_dict)
194            result = meta("Potion", (object,), result_dict)({}, self.duration)201            result = meta("Potion", (object,), result_dict)({}, self.duration)
195            result_list.append(result)202            result_list.append(result)
196203
197        self.is_component = True204        self.is_component = True
198        return tuple(result_list)205        return tuple(result_list)
199206
200    def __eq__(self, other):207    def __eq__(self, other):
201        self.validate_state_on_operation()208        self.validate_state_on_operation()
202        other.validate_state_on_operation()209        other.validate_state_on_operation()
n203 n
204        for key in dir(self):210        for key in dir(self):
205            value = getattr(self, key)211            value = getattr(self, key)
206            if type(value) is PotionEffect and not value.used:212            if type(value) is PotionEffect and not value.used:
207                if not key in dir(other):213                if not key in dir(other):
208                    return False214                    return False
209                other_value = getattr(other, key)215                other_value = getattr(other, key)
210                if value.times != other_value.times or value.used != other_value.used:216                if value.times != other_value.times or value.used != other_value.used:
211                    return False217                    return False
212218
213        for key in dir(other):219        for key in dir(other):
214            value = getattr(other, key)220            value = getattr(other, key)
215            if type(value) is PotionEffect and not value.used and not key in dir(self):221            if type(value) is PotionEffect and not value.used and not key in dir(self):
216                return False222                return False
217223
218        return True224        return True
219225
220    def get_sum(self):226    def get_sum(self):
221        result = 0227        result = 0
222        for key in dir(self):228        for key in dir(self):
223            value = getattr(self, key)229            value = getattr(self, key)
224            if type(value) is PotionEffect and not value.used:230            if type(value) is PotionEffect and not value.used:
225                result += value.times231                result += value.times
226        return result232        return result
227233
228    def __gt__(self, other):234    def __gt__(self, other):
229        self.validate_state_on_operation()235        self.validate_state_on_operation()
230        other.validate_state_on_operation()236        other.validate_state_on_operation()
231        return self.get_sum() > other.get_sum()237        return self.get_sum() > other.get_sum()
232238
233    def __lt__(self, other):239    def __lt__(self, other):
234        self.validate_state_on_operation()240        self.validate_state_on_operation()
235        other.validate_state_on_operation()241        other.validate_state_on_operation()
236        return self.get_sum() < other.get_sum()242        return self.get_sum() < other.get_sum()
237243
238244
239class ГоспожатаПоХимия:245class ГоспожатаПоХимия:
240    @staticmethod246    @staticmethod
241    def calculate_molecular_mass(element):247    def calculate_molecular_mass(element):
242        return sum([ord(i) for i in element])248        return sum([ord(i) for i in element])
243249
244    def __init__(self):250    def __init__(self):
245        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values251        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
246        self.timer = {}252        self.timer = {}
247253
248    def apply_effect(self, target, effect):254    def apply_effect(self, target, effect):
249        # creating a revrse function to reverse the changes after the effect expires255        # creating a revrse function to reverse the changes after the effect expires
250        old_attributes = vars(target).copy()256        old_attributes = vars(target).copy()
251        effect(target)257        effect(target)
252        mid__attributes = vars(target).copy()258        mid__attributes = vars(target).copy()
253259
254        def reverse_effect():260        def reverse_effect():
255            new_attributes = vars(target).copy()261            new_attributes = vars(target).copy()
256            for key, value in new_attributes.items():262            for key, value in new_attributes.items():
257                if not key in mid__attributes.keys():263                if not key in mid__attributes.keys():
258                    continue264                    continue
nn265                is_old = key in old_attributes.keys()
259                if type(value) in (int, float):266                if type(value) in (int, float):
260                    old_val = 0267                    old_val = 0
n261                    if key in old_attributes.keys():n268                    if is_old:
262                        old_val = old_attributes[key]269                        old_val = old_attributes[key]
263270
264                    if (271                    if (
265                        value - (mid__attributes[key] - old_val)272                        value - (mid__attributes[key] - old_val)
n266                    ) == old_val and old_val == 0:n273                    ) == old_val and not is_old:
267                        delattr(target, key)274                        delattr(target, key)
268                    else:275                    else:
269                        setattr(target, key, value - (mid__attributes[key] - old_val))276                        setattr(target, key, value - (mid__attributes[key] - old_val))
270                elif value == mid__attributes[key] and key in old_attributes.keys():277                elif value == mid__attributes[key] and key in old_attributes.keys():
271                    setattr(target, key, old_attributes[key])278                    setattr(target, key, old_attributes[key])
n272                else:n279                elif not is_old:
273                    delattr(target, key)280                    delattr(target, key)
274281
275        return reverse_effect282        return reverse_effect
276283
277    def apply(self, target, potion):284    def apply(self, target, potion):
278        if potion.is_used():285        if potion.is_used():
279            raise TypeError(POTION_IS_USED_ERROR_TEXT)286            raise TypeError(POTION_IS_USED_ERROR_TEXT)
280287
281        if potion.is_component:  # this is probably useless, but just to be sure288        if potion.is_component:  # this is probably useless, but just to be sure
282            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)289            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
tt290 
291        if potion.duration == 0:
292            return
283        ordered_dir = sorted(293        ordered_dir = sorted(
284            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True294            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
285        )295        )
286        for key in ordered_dir:296        for key in ordered_dir:
287            value = getattr(potion, key)297            value = getattr(potion, key)
288            if type(value) is PotionEffect and not value.used:298            if type(value) is PotionEffect and not value.used:
289                reverse_func = self.apply_effect(target, value)299                reverse_func = self.apply_effect(target, value)
290                self.timer[reverse_func] = potion.duration300                self.timer[reverse_func] = potion.duration
291301
292    def tick(self):302    def tick(self):
293        to_iterate = self.timer.copy().items()303        to_iterate = self.timer.copy().items()
294        for key, value in to_iterate:304        for key, value in to_iterate:
295            self.timer[key] -= 1305            self.timer[key] -= 1
296            if value <= 1:306            if value <= 1:
297                key()307                key()
298                self.timer.pop(key)308                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
77
88
9class PotionEffect:9class PotionEffect:
10    @staticmethod10    @staticmethod
11    def custom_round(value):11    def custom_round(value):
12        result = round(value)12        result = round(value)
13        if cmath.isclose(13        if cmath.isclose(
14            result - value, 0.514            result - value, 0.5
15        ):  # the edge case where x.5 should be rounded down15        ):  # the edge case where x.5 should be rounded down
16            result -= 116            result -= 1
17        return result17        return result
1818
19    def __init__(self, func):19    def __init__(self, func):
20        self.func = func20        self.func = func
21        self.times = 121        self.times = 1
22        self.used = False22        self.used = False
2323
24    def __iadd__(self, other):24    def __iadd__(self, other):
25        self.times += other.times25        self.times += other.times
26        return self26        return self
2727
28    def __isub__(self, other):28    def __isub__(self, other):
29        self.times -= other.times29        self.times -= other.times
30        return self30        return self
3131
32    def __imul__(self, other):32    def __imul__(self, other):
33        self.times = PotionEffect.custom_round(self.times * other)33        self.times = PotionEffect.custom_round(self.times * other)
34        return self34        return self
3535
36    def __itruediv__(self, other):36    def __itruediv__(self, other):
37        self.times = PotionEffect.custom_round(self.times / other)37        self.times = PotionEffect.custom_round(self.times / other)
38        return self38        return self
3939
40    def copy(self):40    def copy(self):
41        result = PotionEffect(self.func)41        result = PotionEffect(self.func)
42        result.times = self.times42        result.times = self.times
43        result.used = self.used43        result.used = self.used
44        return result44        return result
4545
46    def __call__(self, target):46    def __call__(self, target):
47        if self.used:47        if self.used:
48            raise TypeError(EFFECT_ERROR_TEXT)48            raise TypeError(EFFECT_ERROR_TEXT)
49        for _ in range(self.times):49        for _ in range(self.times):
50            self.func(target)50            self.func(target)
51        self.used = True51        self.used = True
5252
5353
54class meta(type):54class meta(type):
55    def __new__(cls, name, bases, attr_dict):55    def __new__(cls, name, bases, attr_dict):
56        return type.__new__(cls, name, bases, attr_dict)56        return type.__new__(cls, name, bases, attr_dict)
5757
5858
59class Potion(metaclass=meta):59class Potion(metaclass=meta):
60    @staticmethod60    @staticmethod
61    def fake_func(target):61    def fake_func(target):
62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
6363
64    @staticmethod64    @staticmethod
65    def update_dict_with_class_funcs(result_dict):65    def update_dict_with_class_funcs(result_dict):
66        result_dict.update(66        result_dict.update(
67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
68        )68        )
69        result_dict["__init__"] = Potion.__init__69        result_dict["__init__"] = Potion.__init__
70        result_dict.pop("__weakref__")70        result_dict.pop("__weakref__")
71        return result_dict71        return result_dict
7272
73    def validate_state_on_operation(self):73    def validate_state_on_operation(self):
74        if self.is_component:74        if self.is_component:
75            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)75            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
76        if self.is_used():76        if self.is_used():
77            raise TypeError(POTION_IS_USED_ERROR_TEXT)77            raise TypeError(POTION_IS_USED_ERROR_TEXT)
7878
79    def __init__(self, effects, duration):79    def __init__(self, effects, duration):
80        for key, value in effects.items():80        for key, value in effects.items():
81            setattr(self, key, PotionEffect(value))81            setattr(self, key, PotionEffect(value))
82        self.duration = duration82        self.duration = duration
83        self.is_component = False83        self.is_component = False
8484
85    def is_used(self):85    def is_used(self):
86        for key in dir(self):86        for key in dir(self):
87            value = getattr(self, key)87            value = getattr(self, key)
88            if type(value) is PotionEffect and not value.used:88            if type(value) is PotionEffect and not value.used:
89                return False89                return False
90        return True90        return True
9191
92    def __getattribute__(self, name):92    def __getattribute__(self, name):
93        result = object.__getattribute__(self, name)93        result = object.__getattribute__(self, name)
94        if (94        if (
95            object.__getattribute__(self, "is_component")95            object.__getattribute__(self, "is_component")
96            and type(result) is PotionEffect96            and type(result) is PotionEffect
97        ):97        ):
98            fake_result = PotionEffect(Potion.fake_func)98            fake_result = PotionEffect(Potion.fake_func)
99            fake_result.times = result.times99            fake_result.times = result.times
100            fake_result.used = result.used100            fake_result.used = result.used
101            return fake_result101            return fake_result
102102
103        return result103        return result
104104
105    def __add__(self, other):105    def __add__(self, other):
106        self.validate_state_on_operation()106        self.validate_state_on_operation()
107        other.validate_state_on_operation()107        other.validate_state_on_operation()
108        # transfering the methods from the object on the left side to dict,108        # transfering the methods from the object on the left side to dict,
109        # and if there are matching methods in the right side, we increace the intensity109        # and if there are matching methods in the right side, we increace the intensity
110        result_dict = {}110        result_dict = {}
111        for key in dir(self):111        for key in dir(self):
112            value = getattr(self, key)112            value = getattr(self, key)
113            if type(value) is PotionEffect and not value.used:113            if type(value) is PotionEffect and not value.used:
114                result_dict[key] = value.copy()114                result_dict[key] = value.copy()
115                if key in dir(other):115                if key in dir(other):
116                    other_value = getattr(other, key)116                    other_value = getattr(other, key)
117                    if not other_value.used:117                    if not other_value.used:
118                        result_dict[key] += other_value118                        result_dict[key] += other_value
119119
120        # transfering the methods that are only in the right side to the dict120        # transfering the methods that are only in the right side to the dict
121        for key in dir(other):121        for key in dir(other):
122            value = getattr(other, key)122            value = getattr(other, key)
123            if type(value) is PotionEffect and not key in dir(self) and not value.used:123            if type(value) is PotionEffect and not key in dir(self) and not value.used:
124                result_dict[key] = getattr(other, key).copy()124                result_dict[key] = getattr(other, key).copy()
125125
126        Potion.update_dict_with_class_funcs(result_dict)126        Potion.update_dict_with_class_funcs(result_dict)
127        result = type("Potion", (object,), result_dict)(127        result = type("Potion", (object,), result_dict)(
128            {}, max(self.duration, other.duration)128            {}, max(self.duration, other.duration)
129        )129        )
130        self.is_component = True130        self.is_component = True
131        other.is_component = True131        other.is_component = True
132132
133        return result133        return result
134134
135    def __mul__(self, other):135    def __mul__(self, other):
136        self.validate_state_on_operation()136        self.validate_state_on_operation()
137        result_dict = {}137        result_dict = {}
138        # transfering the methods from the object to the dict and multiply them with the number138        # transfering the methods from the object to the dict and multiply them with the number
139        for key in dir(self):139        for key in dir(self):
140            value = getattr(self, key)140            value = getattr(self, key)
141            if type(value) is PotionEffect:141            if type(value) is PotionEffect:
142                result_dict[key] = value.copy()142                result_dict[key] = value.copy()
143                result_dict[key] *= other143                result_dict[key] *= other
144144
145        Potion.update_dict_with_class_funcs(result_dict)145        Potion.update_dict_with_class_funcs(result_dict)
146146
147        result = meta("Potion", (object,), result_dict)({}, self.duration)147        result = meta("Potion", (object,), result_dict)({}, self.duration)
148        self.is_component = True148        self.is_component = True
149149
150        return result150        return result
151151
152    def __sub__(self, other):152    def __sub__(self, other):
153        self.validate_state_on_operation()153        self.validate_state_on_operation()
154        other.validate_state_on_operation()154        other.validate_state_on_operation()
155        result_dict = {}155        result_dict = {}
156        # validation that the substitution is valid156        # validation that the substitution is valid
157        for key in dir(other):157        for key in dir(other):
158            value = getattr(other, key)158            value = getattr(other, key)
159            if type(value) is PotionEffect and not key in dir(self):159            if type(value) is PotionEffect and not key in dir(self):
160                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)160                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
161        # transfering the methods from the object on the left side to dict,161        # transfering the methods from the object on the left side to dict,
162        # and if there are matching methods in the right side, we subtract their intensity162        # and if there are matching methods in the right side, we subtract their intensity
163        for key in dir(self):163        for key in dir(self):
164            value = getattr(self, key)164            value = getattr(self, key)
165            if not type(value) is PotionEffect:165            if not type(value) is PotionEffect:
166                continue166                continue
167            result_dict[key] = value.copy()167            result_dict[key] = value.copy()
168            if key in dir(other):168            if key in dir(other):
169                other_value = getattr(other, key)169                other_value = getattr(other, key)
170                if not other_value.used:170                if not other_value.used:
171                    result_dict[key] -= getattr(other, key)171                    result_dict[key] -= getattr(other, key)
172                    if result_dict[key].times <= 0:172                    if result_dict[key].times <= 0:
173                        result_dict.pop(key)173                        result_dict.pop(key)
174174
175        Potion.update_dict_with_class_funcs(result_dict)175        Potion.update_dict_with_class_funcs(result_dict)
176        result = meta("Potion", (object,), result_dict)({}, self.duration)176        result = meta("Potion", (object,), result_dict)({}, self.duration)
177        self.is_component = True177        self.is_component = True
178        other.is_component = True178        other.is_component = True
179        return result179        return result
180180
181    def __truediv__(self, other):181    def __truediv__(self, other):
182        self.validate_state_on_operation()182        self.validate_state_on_operation()
183        # spliting the object into equal parts, where the intensity is devided by the number183        # spliting the object into equal parts, where the intensity is devided by the number
184        result_list = []184        result_list = []
185        for _ in range(other):185        for _ in range(other):
186            result_dict = {}186            result_dict = {}
187            for key in dir(self):187            for key in dir(self):
188                value = getattr(self, key)188                value = getattr(self, key)
189                if type(value) is PotionEffect:189                if type(value) is PotionEffect:
190                    result_dict[key] = value.copy()190                    result_dict[key] = value.copy()
191                    result_dict[key] /= other191                    result_dict[key] /= other
192192
193            Potion.update_dict_with_class_funcs(result_dict)193            Potion.update_dict_with_class_funcs(result_dict)
194            result = meta("Potion", (object,), result_dict)({}, self.duration)194            result = meta("Potion", (object,), result_dict)({}, self.duration)
195            result_list.append(result)195            result_list.append(result)
196196
197        self.is_component = True197        self.is_component = True
198        return tuple(result_list)198        return tuple(result_list)
199199
200    def __eq__(self, other):200    def __eq__(self, other):
201        self.validate_state_on_operation()201        self.validate_state_on_operation()
202        other.validate_state_on_operation()202        other.validate_state_on_operation()
203203
204        for key in dir(self):204        for key in dir(self):
205            value = getattr(self, key)205            value = getattr(self, key)
n206            if type(value) is PotionEffect:n206            if type(value) is PotionEffect and not value.used:
207                if not key in dir(other):207                if not key in dir(other):
208                    return False208                    return False
209                other_value = getattr(other, key)209                other_value = getattr(other, key)
210                if value.times != other_value.times or value.used != other_value.used:210                if value.times != other_value.times or value.used != other_value.used:
211                    return False211                    return False
212212
213        for key in dir(other):213        for key in dir(other):
214            value = getattr(other, key)214            value = getattr(other, key)
n215            if type(value) is PotionEffect and not key in dir(self):n215            if type(value) is PotionEffect and not value.used and not key in dir(self):
216                return False216                return False
217217
218        return True218        return True
219219
220    def get_sum(self):220    def get_sum(self):
221        result = 0221        result = 0
222        for key in dir(self):222        for key in dir(self):
223            value = getattr(self, key)223            value = getattr(self, key)
224            if type(value) is PotionEffect and not value.used:224            if type(value) is PotionEffect and not value.used:
225                result += value.times225                result += value.times
226        return result226        return result
227227
228    def __gt__(self, other):228    def __gt__(self, other):
229        self.validate_state_on_operation()229        self.validate_state_on_operation()
230        other.validate_state_on_operation()230        other.validate_state_on_operation()
231        return self.get_sum() > other.get_sum()231        return self.get_sum() > other.get_sum()
232232
233    def __lt__(self, other):233    def __lt__(self, other):
234        self.validate_state_on_operation()234        self.validate_state_on_operation()
235        other.validate_state_on_operation()235        other.validate_state_on_operation()
236        return self.get_sum() < other.get_sum()236        return self.get_sum() < other.get_sum()
237237
238238
239class ГоспожатаПоХимия:239class ГоспожатаПоХимия:
240    @staticmethod240    @staticmethod
241    def calculate_molecular_mass(element):241    def calculate_molecular_mass(element):
242        return sum([ord(i) for i in element])242        return sum([ord(i) for i in element])
243243
244    def __init__(self):244    def __init__(self):
245        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values245        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
246        self.timer = {}246        self.timer = {}
247247
248    def apply_effect(self, target, effect):248    def apply_effect(self, target, effect):
249        # creating a revrse function to reverse the changes after the effect expires249        # creating a revrse function to reverse the changes after the effect expires
250        old_attributes = vars(target).copy()250        old_attributes = vars(target).copy()
251        effect(target)251        effect(target)
n252        to_reverse = {}n252        mid__attributes = vars(target).copy()
253        # set to store the new attributes added by the effect
254        new_attribuets = set()
255 
256        for key, value in vars(target).items():
257            old_value = 0
258            if key in old_attributes.keys():
259                old_value = old_attributes[key]
260            else:
261                new_attribuets.add(key)
262            if value != old_value:
263                to_reverse[key] = value - old_value
264253
265        def reverse_effect():254        def reverse_effect():
nn255            new_attributes = vars(target).copy()
266            for key, value in to_reverse.items():256            for key, value in new_attributes.items():
257                if not key in mid__attributes.keys():
258                    continue
259                if type(value) in (int, float):
260                    old_val = 0
261                    if key in old_attributes.keys():
262                        old_val = old_attributes[key]
263 
264                    if (
265                        value - (mid__attributes[key] - old_val)
266                    ) == old_val and old_val == 0:
267                new_value = getattr(target, key)267                        delattr(target, key)
268                if new_value - value == 0 and key in new_attribuets:268                    else:
269                    # the attribute is added in the function and when it is depleted it should be deleted269                        setattr(target, key, value - (mid__attributes[key] - old_val))
270                elif value == mid__attributes[key] and key in old_attributes.keys():
271                    setattr(target, key, old_attributes[key])
272                else:
270                    delattr(target, key)273                    delattr(target, key)
t271                else:t
272                    setattr(target, key, new_value - value)
273274
274        return reverse_effect275        return reverse_effect
275276
276    def apply(self, target, potion):277    def apply(self, target, potion):
277        if potion.is_used():278        if potion.is_used():
278            raise TypeError(POTION_IS_USED_ERROR_TEXT)279            raise TypeError(POTION_IS_USED_ERROR_TEXT)
279280
280        if potion.is_component:  # this is probably useless, but just to be sure281        if potion.is_component:  # this is probably useless, but just to be sure
281            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)282            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
282        ordered_dir = sorted(283        ordered_dir = sorted(
283            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True284            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
284        )285        )
285        for key in ordered_dir:286        for key in ordered_dir:
286            value = getattr(potion, key)287            value = getattr(potion, key)
287            if type(value) is PotionEffect and not value.used:288            if type(value) is PotionEffect and not value.used:
288                reverse_func = self.apply_effect(target, value)289                reverse_func = self.apply_effect(target, value)
289                self.timer[reverse_func] = potion.duration290                self.timer[reverse_func] = potion.duration
290291
291    def tick(self):292    def tick(self):
292        to_iterate = self.timer.copy().items()293        to_iterate = self.timer.copy().items()
293        for key, value in to_iterate:294        for key, value in to_iterate:
294            self.timer[key] -= 1295            self.timer[key] -= 1
295            if value <= 1:296            if value <= 1:
296                key()297                key()
297                self.timer.pop(key)298                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
77
88
9class PotionEffect:9class PotionEffect:
10    @staticmethod10    @staticmethod
11    def custom_round(value):11    def custom_round(value):
12        result = round(value)12        result = round(value)
13        if cmath.isclose(13        if cmath.isclose(
14            result - value, 0.514            result - value, 0.5
15        ):  # the edge case where x.5 should be rounded down15        ):  # the edge case where x.5 should be rounded down
16            result -= 116            result -= 1
17        return result17        return result
1818
19    def __init__(self, func):19    def __init__(self, func):
20        self.func = func20        self.func = func
21        self.times = 121        self.times = 1
22        self.used = False22        self.used = False
2323
24    def __iadd__(self, other):24    def __iadd__(self, other):
25        self.times += other.times25        self.times += other.times
26        return self26        return self
2727
28    def __isub__(self, other):28    def __isub__(self, other):
29        self.times -= other.times29        self.times -= other.times
30        return self30        return self
3131
32    def __imul__(self, other):32    def __imul__(self, other):
33        self.times = PotionEffect.custom_round(self.times * other)33        self.times = PotionEffect.custom_round(self.times * other)
34        return self34        return self
3535
36    def __itruediv__(self, other):36    def __itruediv__(self, other):
37        self.times = PotionEffect.custom_round(self.times / other)37        self.times = PotionEffect.custom_round(self.times / other)
38        return self38        return self
3939
40    def copy(self):40    def copy(self):
41        result = PotionEffect(self.func)41        result = PotionEffect(self.func)
42        result.times = self.times42        result.times = self.times
43        result.used = self.used43        result.used = self.used
44        return result44        return result
4545
46    def __call__(self, target):46    def __call__(self, target):
47        if self.used:47        if self.used:
48            raise TypeError(EFFECT_ERROR_TEXT)48            raise TypeError(EFFECT_ERROR_TEXT)
49        for _ in range(self.times):49        for _ in range(self.times):
50            self.func(target)50            self.func(target)
51        self.used = True51        self.used = True
5252
5353
54class meta(type):54class meta(type):
55    def __new__(cls, name, bases, attr_dict):55    def __new__(cls, name, bases, attr_dict):
56        return type.__new__(cls, name, bases, attr_dict)56        return type.__new__(cls, name, bases, attr_dict)
5757
5858
59class Potion(metaclass=meta):59class Potion(metaclass=meta):
60    @staticmethod60    @staticmethod
61    def fake_func(target):61    def fake_func(target):
62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
6363
64    @staticmethod64    @staticmethod
65    def update_dict_with_class_funcs(result_dict):65    def update_dict_with_class_funcs(result_dict):
66        result_dict.update(66        result_dict.update(
67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
68        )68        )
69        result_dict["__init__"] = Potion.__init__69        result_dict["__init__"] = Potion.__init__
70        result_dict.pop("__weakref__")70        result_dict.pop("__weakref__")
71        return result_dict71        return result_dict
7272
73    def validate_state_on_operation(self):73    def validate_state_on_operation(self):
74        if self.is_component:74        if self.is_component:
75            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)75            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
76        if self.is_used():76        if self.is_used():
77            raise TypeError(POTION_IS_USED_ERROR_TEXT)77            raise TypeError(POTION_IS_USED_ERROR_TEXT)
7878
79    def __init__(self, effects, duration):79    def __init__(self, effects, duration):
80        for key, value in effects.items():80        for key, value in effects.items():
81            setattr(self, key, PotionEffect(value))81            setattr(self, key, PotionEffect(value))
82        self.duration = duration82        self.duration = duration
83        self.is_component = False83        self.is_component = False
8484
85    def is_used(self):85    def is_used(self):
86        for key in dir(self):86        for key in dir(self):
87            value = getattr(self, key)87            value = getattr(self, key)
88            if type(value) is PotionEffect and not value.used:88            if type(value) is PotionEffect and not value.used:
89                return False89                return False
90        return True90        return True
9191
92    def __getattribute__(self, name):92    def __getattribute__(self, name):
93        result = object.__getattribute__(self, name)93        result = object.__getattribute__(self, name)
94        if (94        if (
95            object.__getattribute__(self, "is_component")95            object.__getattribute__(self, "is_component")
96            and type(result) is PotionEffect96            and type(result) is PotionEffect
97        ):97        ):
98            fake_result = PotionEffect(Potion.fake_func)98            fake_result = PotionEffect(Potion.fake_func)
99            fake_result.times = result.times99            fake_result.times = result.times
100            fake_result.used = result.used100            fake_result.used = result.used
101            return fake_result101            return fake_result
102102
103        return result103        return result
104104
105    def __add__(self, other):105    def __add__(self, other):
106        self.validate_state_on_operation()106        self.validate_state_on_operation()
107        other.validate_state_on_operation()107        other.validate_state_on_operation()
108        # transfering the methods from the object on the left side to dict,108        # transfering the methods from the object on the left side to dict,
109        # and if there are matching methods in the right side, we increace the intensity109        # and if there are matching methods in the right side, we increace the intensity
110        result_dict = {}110        result_dict = {}
111        for key in dir(self):111        for key in dir(self):
112            value = getattr(self, key)112            value = getattr(self, key)
113            if type(value) is PotionEffect and not value.used:113            if type(value) is PotionEffect and not value.used:
114                result_dict[key] = value.copy()114                result_dict[key] = value.copy()
115                if key in dir(other):115                if key in dir(other):
116                    other_value = getattr(other, key)116                    other_value = getattr(other, key)
117                    if not other_value.used:117                    if not other_value.used:
118                        result_dict[key] += other_value118                        result_dict[key] += other_value
119119
120        # transfering the methods that are only in the right side to the dict120        # transfering the methods that are only in the right side to the dict
121        for key in dir(other):121        for key in dir(other):
122            value = getattr(other, key)122            value = getattr(other, key)
123            if type(value) is PotionEffect and not key in dir(self) and not value.used:123            if type(value) is PotionEffect and not key in dir(self) and not value.used:
124                result_dict[key] = getattr(other, key).copy()124                result_dict[key] = getattr(other, key).copy()
125125
126        Potion.update_dict_with_class_funcs(result_dict)126        Potion.update_dict_with_class_funcs(result_dict)
127        result = type("Potion", (object,), result_dict)(127        result = type("Potion", (object,), result_dict)(
128            {}, max(self.duration, other.duration)128            {}, max(self.duration, other.duration)
129        )129        )
130        self.is_component = True130        self.is_component = True
131        other.is_component = True131        other.is_component = True
132132
133        return result133        return result
134134
135    def __mul__(self, other):135    def __mul__(self, other):
136        self.validate_state_on_operation()136        self.validate_state_on_operation()
137        result_dict = {}137        result_dict = {}
138        # transfering the methods from the object to the dict and multiply them with the number138        # transfering the methods from the object to the dict and multiply them with the number
139        for key in dir(self):139        for key in dir(self):
140            value = getattr(self, key)140            value = getattr(self, key)
141            if type(value) is PotionEffect:141            if type(value) is PotionEffect:
142                result_dict[key] = value.copy()142                result_dict[key] = value.copy()
143                result_dict[key] *= other143                result_dict[key] *= other
144144
145        Potion.update_dict_with_class_funcs(result_dict)145        Potion.update_dict_with_class_funcs(result_dict)
146146
147        result = meta("Potion", (object,), result_dict)({}, self.duration)147        result = meta("Potion", (object,), result_dict)({}, self.duration)
148        self.is_component = True148        self.is_component = True
149149
150        return result150        return result
151151
152    def __sub__(self, other):152    def __sub__(self, other):
153        self.validate_state_on_operation()153        self.validate_state_on_operation()
154        other.validate_state_on_operation()154        other.validate_state_on_operation()
155        result_dict = {}155        result_dict = {}
156        # validation that the substitution is valid156        # validation that the substitution is valid
157        for key in dir(other):157        for key in dir(other):
158            value = getattr(other, key)158            value = getattr(other, key)
159            if type(value) is PotionEffect and not key in dir(self):159            if type(value) is PotionEffect and not key in dir(self):
160                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)160                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
161        # transfering the methods from the object on the left side to dict,161        # transfering the methods from the object on the left side to dict,
162        # and if there are matching methods in the right side, we subtract their intensity162        # and if there are matching methods in the right side, we subtract their intensity
163        for key in dir(self):163        for key in dir(self):
164            value = getattr(self, key)164            value = getattr(self, key)
165            if not type(value) is PotionEffect:165            if not type(value) is PotionEffect:
166                continue166                continue
167            result_dict[key] = value.copy()167            result_dict[key] = value.copy()
168            if key in dir(other):168            if key in dir(other):
169                other_value = getattr(other, key)169                other_value = getattr(other, key)
170                if not other_value.used:170                if not other_value.used:
171                    result_dict[key] -= getattr(other, key)171                    result_dict[key] -= getattr(other, key)
172                    if result_dict[key].times <= 0:172                    if result_dict[key].times <= 0:
173                        result_dict.pop(key)173                        result_dict.pop(key)
174174
175        Potion.update_dict_with_class_funcs(result_dict)175        Potion.update_dict_with_class_funcs(result_dict)
176        result = meta("Potion", (object,), result_dict)({}, self.duration)176        result = meta("Potion", (object,), result_dict)({}, self.duration)
177        self.is_component = True177        self.is_component = True
178        other.is_component = True178        other.is_component = True
179        return result179        return result
180180
181    def __truediv__(self, other):181    def __truediv__(self, other):
182        self.validate_state_on_operation()182        self.validate_state_on_operation()
183        # spliting the object into equal parts, where the intensity is devided by the number183        # spliting the object into equal parts, where the intensity is devided by the number
184        result_list = []184        result_list = []
185        for _ in range(other):185        for _ in range(other):
186            result_dict = {}186            result_dict = {}
187            for key in dir(self):187            for key in dir(self):
188                value = getattr(self, key)188                value = getattr(self, key)
189                if type(value) is PotionEffect:189                if type(value) is PotionEffect:
190                    result_dict[key] = value.copy()190                    result_dict[key] = value.copy()
191                    result_dict[key] /= other191                    result_dict[key] /= other
192192
193            Potion.update_dict_with_class_funcs(result_dict)193            Potion.update_dict_with_class_funcs(result_dict)
194            result = meta("Potion", (object,), result_dict)({}, self.duration)194            result = meta("Potion", (object,), result_dict)({}, self.duration)
195            result_list.append(result)195            result_list.append(result)
196196
197        self.is_component = True197        self.is_component = True
198        return tuple(result_list)198        return tuple(result_list)
199199
200    def __eq__(self, other):200    def __eq__(self, other):
201        self.validate_state_on_operation()201        self.validate_state_on_operation()
202        other.validate_state_on_operation()202        other.validate_state_on_operation()
203203
204        for key in dir(self):204        for key in dir(self):
205            value = getattr(self, key)205            value = getattr(self, key)
206            if type(value) is PotionEffect:206            if type(value) is PotionEffect:
207                if not key in dir(other):207                if not key in dir(other):
208                    return False208                    return False
209                other_value = getattr(other, key)209                other_value = getattr(other, key)
210                if value.times != other_value.times or value.used != other_value.used:210                if value.times != other_value.times or value.used != other_value.used:
211                    return False211                    return False
212212
213        for key in dir(other):213        for key in dir(other):
214            value = getattr(other, key)214            value = getattr(other, key)
215            if type(value) is PotionEffect and not key in dir(self):215            if type(value) is PotionEffect and not key in dir(self):
216                return False216                return False
217217
218        return True218        return True
219219
220    def get_sum(self):220    def get_sum(self):
221        result = 0221        result = 0
222        for key in dir(self):222        for key in dir(self):
223            value = getattr(self, key)223            value = getattr(self, key)
t224            if type(value) is PotionEffect:t224            if type(value) is PotionEffect and not value.used:
225                result += value.times225                result += value.times
226        return result226        return result
227227
228    def __gt__(self, other):228    def __gt__(self, other):
229        self.validate_state_on_operation()229        self.validate_state_on_operation()
230        other.validate_state_on_operation()230        other.validate_state_on_operation()
231        return self.get_sum() > other.get_sum()231        return self.get_sum() > other.get_sum()
232232
233    def __lt__(self, other):233    def __lt__(self, other):
234        self.validate_state_on_operation()234        self.validate_state_on_operation()
235        other.validate_state_on_operation()235        other.validate_state_on_operation()
236        return self.get_sum() < other.get_sum()236        return self.get_sum() < other.get_sum()
237237
238238
239class ГоспожатаПоХимия:239class ГоспожатаПоХимия:
240    @staticmethod240    @staticmethod
241    def calculate_molecular_mass(element):241    def calculate_molecular_mass(element):
242        return sum([ord(i) for i in element])242        return sum([ord(i) for i in element])
243243
244    def __init__(self):244    def __init__(self):
245        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values245        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
246        self.timer = {}246        self.timer = {}
247247
248    def apply_effect(self, target, effect):248    def apply_effect(self, target, effect):
249        # creating a revrse function to reverse the changes after the effect expires249        # creating a revrse function to reverse the changes after the effect expires
250        old_attributes = vars(target).copy()250        old_attributes = vars(target).copy()
251        effect(target)251        effect(target)
252        to_reverse = {}252        to_reverse = {}
253        # set to store the new attributes added by the effect253        # set to store the new attributes added by the effect
254        new_attribuets = set()254        new_attribuets = set()
255255
256        for key, value in vars(target).items():256        for key, value in vars(target).items():
257            old_value = 0257            old_value = 0
258            if key in old_attributes.keys():258            if key in old_attributes.keys():
259                old_value = old_attributes[key]259                old_value = old_attributes[key]
260            else:260            else:
261                new_attribuets.add(key)261                new_attribuets.add(key)
262            if value != old_value:262            if value != old_value:
263                to_reverse[key] = value - old_value263                to_reverse[key] = value - old_value
264264
265        def reverse_effect():265        def reverse_effect():
266            for key, value in to_reverse.items():266            for key, value in to_reverse.items():
267                new_value = getattr(target, key)267                new_value = getattr(target, key)
268                if new_value - value == 0 and key in new_attribuets:268                if new_value - value == 0 and key in new_attribuets:
269                    # the attribute is added in the function and when it is depleted it should be deleted269                    # the attribute is added in the function and when it is depleted it should be deleted
270                    delattr(target, key)270                    delattr(target, key)
271                else:271                else:
272                    setattr(target, key, new_value - value)272                    setattr(target, key, new_value - value)
273273
274        return reverse_effect274        return reverse_effect
275275
276    def apply(self, target, potion):276    def apply(self, target, potion):
277        if potion.is_used():277        if potion.is_used():
278            raise TypeError(POTION_IS_USED_ERROR_TEXT)278            raise TypeError(POTION_IS_USED_ERROR_TEXT)
279279
280        if potion.is_component:  # this is probably useless, but just to be sure280        if potion.is_component:  # this is probably useless, but just to be sure
281            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)281            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
282        ordered_dir = sorted(282        ordered_dir = sorted(
283            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True283            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
284        )284        )
285        for key in ordered_dir:285        for key in ordered_dir:
286            value = getattr(potion, key)286            value = getattr(potion, key)
287            if type(value) is PotionEffect and not value.used:287            if type(value) is PotionEffect and not value.used:
288                reverse_func = self.apply_effect(target, value)288                reverse_func = self.apply_effect(target, value)
289                self.timer[reverse_func] = potion.duration289                self.timer[reverse_func] = potion.duration
290290
291    def tick(self):291    def tick(self):
292        to_iterate = self.timer.copy().items()292        to_iterate = self.timer.copy().items()
293        for key, value in to_iterate:293        for key, value in to_iterate:
294            self.timer[key] -= 1294            self.timer[key] -= 1
295            if value <= 1:295            if value <= 1:
296                key()296                key()
297                self.timer.pop(key)297                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
77
88
9class PotionEffect:9class PotionEffect:
10    @staticmethod10    @staticmethod
11    def custom_round(value):11    def custom_round(value):
12        result = round(value)12        result = round(value)
13        if cmath.isclose(13        if cmath.isclose(
14            result - value, 0.514            result - value, 0.5
15        ):  # the edge case where x.5 should be rounded down15        ):  # the edge case where x.5 should be rounded down
16            result -= 116            result -= 1
17        return result17        return result
1818
19    def __init__(self, func):19    def __init__(self, func):
20        self.func = func20        self.func = func
21        self.times = 121        self.times = 1
22        self.used = False22        self.used = False
2323
24    def __iadd__(self, other):24    def __iadd__(self, other):
25        self.times += other.times25        self.times += other.times
26        return self26        return self
2727
28    def __isub__(self, other):28    def __isub__(self, other):
29        self.times -= other.times29        self.times -= other.times
30        return self30        return self
3131
32    def __imul__(self, other):32    def __imul__(self, other):
33        self.times = PotionEffect.custom_round(self.times * other)33        self.times = PotionEffect.custom_round(self.times * other)
34        return self34        return self
3535
36    def __itruediv__(self, other):36    def __itruediv__(self, other):
37        self.times = PotionEffect.custom_round(self.times / other)37        self.times = PotionEffect.custom_round(self.times / other)
38        return self38        return self
3939
40    def copy(self):40    def copy(self):
41        result = PotionEffect(self.func)41        result = PotionEffect(self.func)
42        result.times = self.times42        result.times = self.times
43        result.used = self.used43        result.used = self.used
44        return result44        return result
4545
46    def __call__(self, target):46    def __call__(self, target):
47        if self.used:47        if self.used:
48            raise TypeError(EFFECT_ERROR_TEXT)48            raise TypeError(EFFECT_ERROR_TEXT)
49        for _ in range(self.times):49        for _ in range(self.times):
50            self.func(target)50            self.func(target)
51        self.used = True51        self.used = True
5252
5353
54class meta(type):54class meta(type):
55    def __new__(cls, name, bases, attr_dict):55    def __new__(cls, name, bases, attr_dict):
56        return type.__new__(cls, name, bases, attr_dict)56        return type.__new__(cls, name, bases, attr_dict)
5757
5858
59class Potion(metaclass=meta):59class Potion(metaclass=meta):
60    @staticmethod60    @staticmethod
61    def fake_func(target):61    def fake_func(target):
62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
6363
64    @staticmethod64    @staticmethod
65    def update_dict_with_class_funcs(result_dict):65    def update_dict_with_class_funcs(result_dict):
66        result_dict.update(66        result_dict.update(
67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
68        )68        )
69        result_dict["__init__"] = Potion.__init__69        result_dict["__init__"] = Potion.__init__
70        result_dict.pop("__weakref__")70        result_dict.pop("__weakref__")
71        return result_dict71        return result_dict
nn72 
73    def validate_state_on_operation(self):
74        if self.is_component:
75            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
76        if self.is_used():
77            raise TypeError(POTION_IS_USED_ERROR_TEXT)
7278
73    def __init__(self, effects, duration):79    def __init__(self, effects, duration):
74        for key, value in effects.items():80        for key, value in effects.items():
75            setattr(self, key, PotionEffect(value))81            setattr(self, key, PotionEffect(value))
76        self.duration = duration82        self.duration = duration
77        self.is_component = False83        self.is_component = False
7884
79    def is_used(self):85    def is_used(self):
80        for key in dir(self):86        for key in dir(self):
81            value = getattr(self, key)87            value = getattr(self, key)
82            if type(value) is PotionEffect and not value.used:88            if type(value) is PotionEffect and not value.used:
83                return False89                return False
84        return True90        return True
8591
86    def __getattribute__(self, name):92    def __getattribute__(self, name):
87        result = object.__getattribute__(self, name)93        result = object.__getattribute__(self, name)
88        if (94        if (
89            object.__getattribute__(self, "is_component")95            object.__getattribute__(self, "is_component")
90            and type(result) is PotionEffect96            and type(result) is PotionEffect
91        ):97        ):
92            fake_result = PotionEffect(Potion.fake_func)98            fake_result = PotionEffect(Potion.fake_func)
93            fake_result.times = result.times99            fake_result.times = result.times
94            fake_result.used = result.used100            fake_result.used = result.used
95            return fake_result101            return fake_result
96102
97        return result103        return result
98104
99    def __add__(self, other):105    def __add__(self, other):
n100        if self.is_component or other.is_component:n106        self.validate_state_on_operation()
101            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)107        other.validate_state_on_operation()
102        if self.is_used() or other.is_used():
103            raise TypeError(POTION_IS_USED_ERROR_TEXT)
104 
105        # transfering the methods from the object on the left side to dict,108        # transfering the methods from the object on the left side to dict,
106        # and if there are matching methods in the right side, we increace the intensity109        # and if there are matching methods in the right side, we increace the intensity
107        result_dict = {}110        result_dict = {}
108        for key in dir(self):111        for key in dir(self):
109            value = getattr(self, key)112            value = getattr(self, key)
110            if type(value) is PotionEffect and not value.used:113            if type(value) is PotionEffect and not value.used:
111                result_dict[key] = value.copy()114                result_dict[key] = value.copy()
112                if key in dir(other):115                if key in dir(other):
113                    other_value = getattr(other, key)116                    other_value = getattr(other, key)
114                    if not other_value.used:117                    if not other_value.used:
115                        result_dict[key] += other_value118                        result_dict[key] += other_value
116119
117        # transfering the methods that are only in the right side to the dict120        # transfering the methods that are only in the right side to the dict
118        for key in dir(other):121        for key in dir(other):
119            value = getattr(other, key)122            value = getattr(other, key)
120            if type(value) is PotionEffect and not key in dir(self) and not value.used:123            if type(value) is PotionEffect and not key in dir(self) and not value.used:
121                result_dict[key] = getattr(other, key).copy()124                result_dict[key] = getattr(other, key).copy()
122125
123        Potion.update_dict_with_class_funcs(result_dict)126        Potion.update_dict_with_class_funcs(result_dict)
124        result = type("Potion", (object,), result_dict)(127        result = type("Potion", (object,), result_dict)(
125            {}, max(self.duration, other.duration)128            {}, max(self.duration, other.duration)
126        )129        )
127        self.is_component = True130        self.is_component = True
128        other.is_component = True131        other.is_component = True
129132
130        return result133        return result
131134
132    def __mul__(self, other):135    def __mul__(self, other):
n133        if self.is_component:n136        self.validate_state_on_operation()
134            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
135        if self.is_used():
136            raise TypeError(POTION_IS_USED_ERROR_TEXT)
137        result_dict = {}137        result_dict = {}
138        # transfering the methods from the object to the dict and multiply them with the number138        # transfering the methods from the object to the dict and multiply them with the number
139        for key in dir(self):139        for key in dir(self):
140            value = getattr(self, key)140            value = getattr(self, key)
141            if type(value) is PotionEffect:141            if type(value) is PotionEffect:
142                result_dict[key] = value.copy()142                result_dict[key] = value.copy()
143                result_dict[key] *= other143                result_dict[key] *= other
144144
145        Potion.update_dict_with_class_funcs(result_dict)145        Potion.update_dict_with_class_funcs(result_dict)
146146
147        result = meta("Potion", (object,), result_dict)({}, self.duration)147        result = meta("Potion", (object,), result_dict)({}, self.duration)
148        self.is_component = True148        self.is_component = True
149149
150        return result150        return result
151151
152    def __sub__(self, other):152    def __sub__(self, other):
n153        if self.is_component or other.is_component:n153        self.validate_state_on_operation()
154            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)154        other.validate_state_on_operation()
155        if self.is_used() or other.is_used():
156            raise TypeError(POTION_IS_USED_ERROR_TEXT)
157        result_dict = {}155        result_dict = {}
158        # validation that the substitution is valid156        # validation that the substitution is valid
159        for key in dir(other):157        for key in dir(other):
160            value = getattr(other, key)158            value = getattr(other, key)
161            if type(value) is PotionEffect and not key in dir(self):159            if type(value) is PotionEffect and not key in dir(self):
162                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)160                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
163        # transfering the methods from the object on the left side to dict,161        # transfering the methods from the object on the left side to dict,
164        # and if there are matching methods in the right side, we subtract their intensity162        # and if there are matching methods in the right side, we subtract their intensity
165        for key in dir(self):163        for key in dir(self):
166            value = getattr(self, key)164            value = getattr(self, key)
167            if not type(value) is PotionEffect:165            if not type(value) is PotionEffect:
168                continue166                continue
169            result_dict[key] = value.copy()167            result_dict[key] = value.copy()
170            if key in dir(other):168            if key in dir(other):
171                other_value = getattr(other, key)169                other_value = getattr(other, key)
172                if not other_value.used:170                if not other_value.used:
173                    result_dict[key] -= getattr(other, key)171                    result_dict[key] -= getattr(other, key)
174                    if result_dict[key].times <= 0:172                    if result_dict[key].times <= 0:
175                        result_dict.pop(key)173                        result_dict.pop(key)
176174
177        Potion.update_dict_with_class_funcs(result_dict)175        Potion.update_dict_with_class_funcs(result_dict)
178        result = meta("Potion", (object,), result_dict)({}, self.duration)176        result = meta("Potion", (object,), result_dict)({}, self.duration)
179        self.is_component = True177        self.is_component = True
180        other.is_component = True178        other.is_component = True
181        return result179        return result
182180
183    def __truediv__(self, other):181    def __truediv__(self, other):
n184        if self.is_component:n182        self.validate_state_on_operation()
185            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
186        if self.is_used():
187            raise TypeError(POTION_IS_USED_ERROR_TEXT)
188        # spliting the object into equal parts, where the intensity is devided by the number183        # spliting the object into equal parts, where the intensity is devided by the number
189        result_list = []184        result_list = []
190        for _ in range(other):185        for _ in range(other):
191            result_dict = {}186            result_dict = {}
192            for key in dir(self):187            for key in dir(self):
193                value = getattr(self, key)188                value = getattr(self, key)
194                if type(value) is PotionEffect:189                if type(value) is PotionEffect:
195                    result_dict[key] = value.copy()190                    result_dict[key] = value.copy()
196                    result_dict[key] /= other191                    result_dict[key] /= other
197192
198            Potion.update_dict_with_class_funcs(result_dict)193            Potion.update_dict_with_class_funcs(result_dict)
199            result = meta("Potion", (object,), result_dict)({}, self.duration)194            result = meta("Potion", (object,), result_dict)({}, self.duration)
200            result_list.append(result)195            result_list.append(result)
201196
202        self.is_component = True197        self.is_component = True
203        return tuple(result_list)198        return tuple(result_list)
204199
205    def __eq__(self, other):200    def __eq__(self, other):
nn201        self.validate_state_on_operation()
202        other.validate_state_on_operation()
203 
206        for key in dir(self):204        for key in dir(self):
207            value = getattr(self, key)205            value = getattr(self, key)
208            if type(value) is PotionEffect:206            if type(value) is PotionEffect:
209                if not key in dir(other):207                if not key in dir(other):
210                    return False208                    return False
211                other_value = getattr(other, key)209                other_value = getattr(other, key)
212                if value.times != other_value.times or value.used != other_value.used:210                if value.times != other_value.times or value.used != other_value.used:
213                    return False211                    return False
214212
215        for key in dir(other):213        for key in dir(other):
216            value = getattr(other, key)214            value = getattr(other, key)
217            if type(value) is PotionEffect and not key in dir(self):215            if type(value) is PotionEffect and not key in dir(self):
218                return False216                return False
219217
220        return True218        return True
221219
222    def get_sum(self):220    def get_sum(self):
223        result = 0221        result = 0
224        for key in dir(self):222        for key in dir(self):
225            value = getattr(self, key)223            value = getattr(self, key)
226            if type(value) is PotionEffect:224            if type(value) is PotionEffect:
227                result += value.times225                result += value.times
228        return result226        return result
229227
230    def __gt__(self, other):228    def __gt__(self, other):
nn229        self.validate_state_on_operation()
230        other.validate_state_on_operation()
231        return self.get_sum() > other.get_sum()231        return self.get_sum() > other.get_sum()
232232
233    def __lt__(self, other):233    def __lt__(self, other):
nn234        self.validate_state_on_operation()
235        other.validate_state_on_operation()
234        return self.get_sum() < other.get_sum()236        return self.get_sum() < other.get_sum()
235237
236238
237class ГоспожатаПоХимия:239class ГоспожатаПоХимия:
238    @staticmethod240    @staticmethod
239    def calculate_molecular_mass(element):241    def calculate_molecular_mass(element):
240        return sum([ord(i) for i in element])242        return sum([ord(i) for i in element])
241243
242    def __init__(self):244    def __init__(self):
243        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values245        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
244        self.timer = {}246        self.timer = {}
245247
246    def apply_effect(self, target, effect):248    def apply_effect(self, target, effect):
247        # creating a revrse function to reverse the changes after the effect expires249        # creating a revrse function to reverse the changes after the effect expires
248        old_attributes = vars(target).copy()250        old_attributes = vars(target).copy()
249        effect(target)251        effect(target)
250        to_reverse = {}252        to_reverse = {}
nn253        # set to store the new attributes added by the effect
254        new_attribuets = set()
251255
nn256        for key, value in vars(target).items():
257            old_value = 0
252        for key, value in old_attributes.items():258            if key in old_attributes.keys():
253            new_value = getattr(target, key)259                old_value = old_attributes[key]
254            if new_value != value:260            else:
261                new_attribuets.add(key)
262            if value != old_value:
255                to_reverse[key] = new_value - value263                to_reverse[key] = value - old_value
256264
257        def reverse_effect():265        def reverse_effect():
258            for key, value in to_reverse.items():266            for key, value in to_reverse.items():
259                new_value = getattr(target, key)267                new_value = getattr(target, key)
tt268                if new_value - value == 0 and key in new_attribuets:
269                    # the attribute is added in the function and when it is depleted it should be deleted
270                    delattr(target, key)
271                else:
260                setattr(target, key, new_value - value)272                    setattr(target, key, new_value - value)
261273
262        return reverse_effect274        return reverse_effect
263275
264    def apply(self, target, potion):276    def apply(self, target, potion):
265        if potion.is_used():277        if potion.is_used():
266            raise TypeError(POTION_IS_USED_ERROR_TEXT)278            raise TypeError(POTION_IS_USED_ERROR_TEXT)
267279
268        if potion.is_component:  # this is probably useless, but just to be sure280        if potion.is_component:  # this is probably useless, but just to be sure
269            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)281            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
270        ordered_dir = sorted(282        ordered_dir = sorted(
271            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True283            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
272        )284        )
273        for key in ordered_dir:285        for key in ordered_dir:
274            value = getattr(potion, key)286            value = getattr(potion, key)
275            if type(value) is PotionEffect and not value.used:287            if type(value) is PotionEffect and not value.used:
276                reverse_func = self.apply_effect(target, value)288                reverse_func = self.apply_effect(target, value)
277                self.timer[reverse_func] = potion.duration289                self.timer[reverse_func] = potion.duration
278290
279    def tick(self):291    def tick(self):
280        to_iterate = self.timer.copy().items()292        to_iterate = self.timer.copy().items()
281        for key, value in to_iterate:293        for key, value in to_iterate:
282            self.timer[key] -= 1294            self.timer[key] -= 1
283            if value <= 1:295            if value <= 1:
284                key()296                key()
285                self.timer.pop(key)297                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
77
88
n9def fake_func(target):n
10    raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
11 
12 
13def calculate_molecular_mass(element):
14    return sum([ord(i) for i in element])
15 
16 
17def custom_round(value):
18    result = round(value)
19    if cmath.isclose(
20        result - value, 0.5
21    ):  # the edge case where x.5 should be rounded down
22        result -= 1
23    return result
24 
25 
26class PotionEffect:9class PotionEffect:
nn10    @staticmethod
11    def custom_round(value):
12        result = round(value)
13        if cmath.isclose(
14            result - value, 0.5
15        ):  # the edge case where x.5 should be rounded down
16            result -= 1
17        return result
18 
27    def __init__(self, func):19    def __init__(self, func):
28        self.func = func20        self.func = func
29        self.times = 121        self.times = 1
30        self.used = False22        self.used = False
3123
32    def __iadd__(self, other):24    def __iadd__(self, other):
33        self.times += other.times25        self.times += other.times
34        return self26        return self
3527
36    def __isub__(self, other):28    def __isub__(self, other):
37        self.times -= other.times29        self.times -= other.times
38        return self30        return self
3931
40    def __imul__(self, other):32    def __imul__(self, other):
n41        self.times = custom_round(self.times * other)n33        self.times = PotionEffect.custom_round(self.times * other)
42        return self34        return self
4335
44    def __itruediv__(self, other):36    def __itruediv__(self, other):
n45        self.times = custom_round(self.times / other)n37        self.times = PotionEffect.custom_round(self.times / other)
46        return self38        return self
4739
48    def copy(self):40    def copy(self):
49        result = PotionEffect(self.func)41        result = PotionEffect(self.func)
50        result.times = self.times42        result.times = self.times
51        result.used = self.used43        result.used = self.used
52        return result44        return result
5345
54    def __call__(self, target):46    def __call__(self, target):
55        if self.used:47        if self.used:
56            raise TypeError(EFFECT_ERROR_TEXT)48            raise TypeError(EFFECT_ERROR_TEXT)
57        for _ in range(self.times):49        for _ in range(self.times):
58            self.func(target)50            self.func(target)
59        self.used = True51        self.used = True
6052
6153
62class meta(type):54class meta(type):
63    def __new__(cls, name, bases, attr_dict):55    def __new__(cls, name, bases, attr_dict):
n64        attr_dict["is_component"] = Falsen
65        return type.__new__(cls, name, bases, attr_dict)56        return type.__new__(cls, name, bases, attr_dict)
6657
6758
68class Potion(metaclass=meta):59class Potion(metaclass=meta):
nn60    @staticmethod
61    def fake_func(target):
62        raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
63 
64    @staticmethod
65    def update_dict_with_class_funcs(result_dict):
66        result_dict.update(
67            {key: value for key, value in vars(Potion).items() if not key in dir(type)}
68        )
69        result_dict["__init__"] = Potion.__init__
70        result_dict.pop("__weakref__")
71        return result_dict
72 
69    def __init__(self, effects, duration):73    def __init__(self, effects, duration):
70        for key, value in effects.items():74        for key, value in effects.items():
71            setattr(self, key, PotionEffect(value))75            setattr(self, key, PotionEffect(value))
72        self.duration = duration76        self.duration = duration
nn77        self.is_component = False
7378
74    def is_used(self):79    def is_used(self):
75        for key in dir(self):80        for key in dir(self):
76            value = getattr(self, key)81            value = getattr(self, key)
77            if type(value) is PotionEffect and not value.used:82            if type(value) is PotionEffect and not value.used:
78                return False83                return False
79        return True84        return True
8085
81    def __getattribute__(self, name):86    def __getattribute__(self, name):
82        result = object.__getattribute__(self, name)87        result = object.__getattribute__(self, name)
83        if (88        if (
84            object.__getattribute__(self, "is_component")89            object.__getattribute__(self, "is_component")
85            and type(result) is PotionEffect90            and type(result) is PotionEffect
86        ):91        ):
n87            fake_result = PotionEffect(fake_func)n92            fake_result = PotionEffect(Potion.fake_func)
88            fake_result.times = result.times93            fake_result.times = result.times
89            fake_result.used = result.used94            fake_result.used = result.used
90            return fake_result95            return fake_result
9196
92        return result97        return result
9398
94    def __add__(self, other):99    def __add__(self, other):
95        if self.is_component or other.is_component:100        if self.is_component or other.is_component:
96            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)101            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
97        if self.is_used() or other.is_used():102        if self.is_used() or other.is_used():
98            raise TypeError(POTION_IS_USED_ERROR_TEXT)103            raise TypeError(POTION_IS_USED_ERROR_TEXT)
99104
100        # transfering the methods from the object on the left side to dict,105        # transfering the methods from the object on the left side to dict,
101        # and if there are matching methods in the right side, we increace the intensity106        # and if there are matching methods in the right side, we increace the intensity
102        result_dict = {}107        result_dict = {}
103        for key in dir(self):108        for key in dir(self):
104            value = getattr(self, key)109            value = getattr(self, key)
105            if type(value) is PotionEffect and not value.used:110            if type(value) is PotionEffect and not value.used:
106                result_dict[key] = value.copy()111                result_dict[key] = value.copy()
107                if key in dir(other):112                if key in dir(other):
108                    other_value = getattr(other, key)113                    other_value = getattr(other, key)
109                    if not other_value.used:114                    if not other_value.used:
110                        result_dict[key] += other_value115                        result_dict[key] += other_value
111116
112        # transfering the methods that are only in the right side to the dict117        # transfering the methods that are only in the right side to the dict
113        for key in dir(other):118        for key in dir(other):
114            value = getattr(other, key)119            value = getattr(other, key)
115            if type(value) is PotionEffect and not key in dir(self) and not value.used:120            if type(value) is PotionEffect and not key in dir(self) and not value.used:
116                result_dict[key] = getattr(other, key).copy()121                result_dict[key] = getattr(other, key).copy()
117122
n118        result_dict["duration"] = max(self.duration, other.duration)n123        Potion.update_dict_with_class_funcs(result_dict)
119        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])124        result = type("Potion", (object,), result_dict)(
125            {}, max(self.duration, other.duration)
126        )
120        self.is_component = True127        self.is_component = True
121        other.is_component = True128        other.is_component = True
122129
123        return result130        return result
124131
125    def __mul__(self, other):132    def __mul__(self, other):
126        if self.is_component:133        if self.is_component:
127            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)134            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
128        if self.is_used():135        if self.is_used():
129            raise TypeError(POTION_IS_USED_ERROR_TEXT)136            raise TypeError(POTION_IS_USED_ERROR_TEXT)
130        result_dict = {}137        result_dict = {}
131        # transfering the methods from the object to the dict and multiply them with the number138        # transfering the methods from the object to the dict and multiply them with the number
132        for key in dir(self):139        for key in dir(self):
133            value = getattr(self, key)140            value = getattr(self, key)
134            if type(value) is PotionEffect:141            if type(value) is PotionEffect:
135                result_dict[key] = value.copy()142                result_dict[key] = value.copy()
136                result_dict[key] *= other143                result_dict[key] *= other
137144
n138        result_dict["duration"] = self.durationn145        Potion.update_dict_with_class_funcs(result_dict)
146 
139        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])147        result = meta("Potion", (object,), result_dict)({}, self.duration)
140        self.is_component = True148        self.is_component = True
141149
142        return result150        return result
143151
144    def __sub__(self, other):152    def __sub__(self, other):
145        if self.is_component or other.is_component:153        if self.is_component or other.is_component:
146            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)154            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
147        if self.is_used() or other.is_used():155        if self.is_used() or other.is_used():
148            raise TypeError(POTION_IS_USED_ERROR_TEXT)156            raise TypeError(POTION_IS_USED_ERROR_TEXT)
149        result_dict = {}157        result_dict = {}
150        # validation that the substitution is valid158        # validation that the substitution is valid
151        for key in dir(other):159        for key in dir(other):
152            value = getattr(other, key)160            value = getattr(other, key)
153            if type(value) is PotionEffect and not key in dir(self):161            if type(value) is PotionEffect and not key in dir(self):
154                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)162                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
155        # transfering the methods from the object on the left side to dict,163        # transfering the methods from the object on the left side to dict,
156        # and if there are matching methods in the right side, we subtract their intensity164        # and if there are matching methods in the right side, we subtract their intensity
157        for key in dir(self):165        for key in dir(self):
158            value = getattr(self, key)166            value = getattr(self, key)
n159            if type(value) is PotionEffect:n167            if not type(value) is PotionEffect:
168                continue
160                result_dict[key] = value.copy()169            result_dict[key] = value.copy()
161                if key in dir(other):170            if key in dir(other):
162                    other_value = getattr(other, key)171                other_value = getattr(other, key)
163                    if not other_value.used:172                if not other_value.used:
164                        result_dict[key] -= getattr(other, key)173                    result_dict[key] -= getattr(other, key)
165                        if result_dict[key].times <= 0:174                    if result_dict[key].times <= 0:
166                            result_dict.pop(key)175                        result_dict.pop(key)
167176
n168        result_dict["duration"] = self.durationn177        Potion.update_dict_with_class_funcs(result_dict)
169        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])178        result = meta("Potion", (object,), result_dict)({}, self.duration)
170        self.is_component = True179        self.is_component = True
171        other.is_component = True180        other.is_component = True
172        return result181        return result
173182
174    def __truediv__(self, other):183    def __truediv__(self, other):
175        if self.is_component:184        if self.is_component:
176            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)185            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
177        if self.is_used():186        if self.is_used():
178            raise TypeError(POTION_IS_USED_ERROR_TEXT)187            raise TypeError(POTION_IS_USED_ERROR_TEXT)
179        # spliting the object into equal parts, where the intensity is devided by the number188        # spliting the object into equal parts, where the intensity is devided by the number
180        result_list = []189        result_list = []
181        for _ in range(other):190        for _ in range(other):
182            result_dict = {}191            result_dict = {}
183            for key in dir(self):192            for key in dir(self):
184                value = getattr(self, key)193                value = getattr(self, key)
185                if type(value) is PotionEffect:194                if type(value) is PotionEffect:
186                    result_dict[key] = value.copy()195                    result_dict[key] = value.copy()
187                    result_dict[key] /= other196                    result_dict[key] /= other
188197
n189            result_dict["duration"] = self.durationn198            Potion.update_dict_with_class_funcs(result_dict)
190            result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])199            result = meta("Potion", (object,), result_dict)({}, self.duration)
191            result_list.append(result)200            result_list.append(result)
192201
193        self.is_component = True202        self.is_component = True
194        return tuple(result_list)203        return tuple(result_list)
195204
196    def __eq__(self, other):205    def __eq__(self, other):
197        for key in dir(self):206        for key in dir(self):
198            value = getattr(self, key)207            value = getattr(self, key)
199            if type(value) is PotionEffect:208            if type(value) is PotionEffect:
200                if not key in dir(other):209                if not key in dir(other):
201                    return False210                    return False
202                other_value = getattr(other, key)211                other_value = getattr(other, key)
203                if value.times != other_value.times or value.used != other_value.used:212                if value.times != other_value.times or value.used != other_value.used:
204                    return False213                    return False
205214
206        for key in dir(other):215        for key in dir(other):
207            value = getattr(other, key)216            value = getattr(other, key)
208            if type(value) is PotionEffect and not key in dir(self):217            if type(value) is PotionEffect and not key in dir(self):
209                return False218                return False
210219
211        return True220        return True
212221
213    def get_sum(self):222    def get_sum(self):
214        result = 0223        result = 0
215        for key in dir(self):224        for key in dir(self):
216            value = getattr(self, key)225            value = getattr(self, key)
217            if type(value) is PotionEffect:226            if type(value) is PotionEffect:
218                result += value.times227                result += value.times
219        return result228        return result
220229
221    def __gt__(self, other):230    def __gt__(self, other):
222        return self.get_sum() > other.get_sum()231        return self.get_sum() > other.get_sum()
223232
224    def __lt__(self, other):233    def __lt__(self, other):
225        return self.get_sum() < other.get_sum()234        return self.get_sum() < other.get_sum()
226235
227236
228class ГоспожатаПоХимия:237class ГоспожатаПоХимия:
nn238    @staticmethod
239    def calculate_molecular_mass(element):
240        return sum([ord(i) for i in element])
241 
229    def __init__(self):242    def __init__(self):
230        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values243        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
231        self.timer = {}244        self.timer = {}
232245
233    def apply_effect(self, target, effect):246    def apply_effect(self, target, effect):
234        # creating a revrse function to reverse the changes after the effect expires247        # creating a revrse function to reverse the changes after the effect expires
235        old_attributes = vars(target).copy()248        old_attributes = vars(target).copy()
236        effect(target)249        effect(target)
237        to_reverse = {}250        to_reverse = {}
nn251 
238        for key, value in old_attributes.items():252        for key, value in old_attributes.items():
239            new_value = getattr(target, key)253            new_value = getattr(target, key)
240            if new_value != value:254            if new_value != value:
241                to_reverse[key] = new_value - value255                to_reverse[key] = new_value - value
242256
243        def reverse_effect():257        def reverse_effect():
244            for key, value in to_reverse.items():258            for key, value in to_reverse.items():
245                new_value = getattr(target, key)259                new_value = getattr(target, key)
246                setattr(target, key, new_value - value)260                setattr(target, key, new_value - value)
247261
248        return reverse_effect262        return reverse_effect
249263
250    def apply(self, target, potion):264    def apply(self, target, potion):
251        if potion.is_used():265        if potion.is_used():
252            raise TypeError(POTION_IS_USED_ERROR_TEXT)266            raise TypeError(POTION_IS_USED_ERROR_TEXT)
253267
254        if potion.is_component:  # this is probably useless, but just to be sure268        if potion.is_component:  # this is probably useless, but just to be sure
255            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)269            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
t256        ordered_dir = sorted(dir(potion), key=calculate_molecular_mass, reverse=True)t270        ordered_dir = sorted(
271            dir(potion), key=ГоспожатаПоХимия.calculate_molecular_mass, reverse=True
272        )
257        for key in ordered_dir:273        for key in ordered_dir:
258            value = getattr(potion, key)274            value = getattr(potion, key)
259            if type(value) is PotionEffect and not value.used:275            if type(value) is PotionEffect and not value.used:
260                reverse_func = self.apply_effect(target, value)276                reverse_func = self.apply_effect(target, value)
261                self.timer[reverse_func] = potion.duration277                self.timer[reverse_func] = potion.duration
262278
263    def tick(self):279    def tick(self):
264        to_iterate = self.timer.copy().items()280        to_iterate = self.timer.copy().items()
265        for key, value in to_iterate:281        for key, value in to_iterate:
266            self.timer[key] -= 1282            self.timer[key] -= 1
267            if value <= 1:283            if value <= 1:
268                key()284                key()
269                self.timer.pop(key)285                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
77
88
9def fake_func(target):9def fake_func(target):
10    raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)10    raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
nn11 
12 
13def calculate_molecular_mass(element):
14    return sum([ord(i) for i in element])
1115
1216
13def custom_round(value):17def custom_round(value):
14    result = round(value)18    result = round(value)
15    if cmath.isclose(19    if cmath.isclose(
16        result - value, 0.520        result - value, 0.5
17    ):  # the edge case where x.5 should be rounded down21    ):  # the edge case where x.5 should be rounded down
18        result -= 122        result -= 1
19    return result23    return result
2024
2125
22class PotionEffect:26class PotionEffect:
23    def __init__(self, func):27    def __init__(self, func):
24        self.func = func28        self.func = func
25        self.times = 129        self.times = 1
26        self.used = False30        self.used = False
2731
28    def __iadd__(self, other):32    def __iadd__(self, other):
29        self.times += other.times33        self.times += other.times
30        return self34        return self
3135
32    def __isub__(self, other):36    def __isub__(self, other):
33        self.times -= other.times37        self.times -= other.times
34        return self38        return self
3539
36    def __imul__(self, other):40    def __imul__(self, other):
37        self.times = custom_round(self.times * other)41        self.times = custom_round(self.times * other)
38        return self42        return self
3943
40    def __itruediv__(self, other):44    def __itruediv__(self, other):
41        self.times = custom_round(self.times / other)45        self.times = custom_round(self.times / other)
42        return self46        return self
4347
44    def copy(self):48    def copy(self):
45        result = PotionEffect(self.func)49        result = PotionEffect(self.func)
46        result.times = self.times50        result.times = self.times
47        result.used = self.used51        result.used = self.used
48        return result52        return result
4953
50    def __call__(self, target):54    def __call__(self, target):
51        if self.used:55        if self.used:
52            raise TypeError(EFFECT_ERROR_TEXT)56            raise TypeError(EFFECT_ERROR_TEXT)
53        for _ in range(self.times):57        for _ in range(self.times):
54            self.func(target)58            self.func(target)
55        self.used = True59        self.used = True
5660
5761
58class meta(type):62class meta(type):
59    def __new__(cls, name, bases, attr_dict):63    def __new__(cls, name, bases, attr_dict):
60        attr_dict["is_component"] = False64        attr_dict["is_component"] = False
61        return type.__new__(cls, name, bases, attr_dict)65        return type.__new__(cls, name, bases, attr_dict)
6266
6367
64class Potion(metaclass=meta):68class Potion(metaclass=meta):
65    def __init__(self, effects, duration):69    def __init__(self, effects, duration):
66        for key, value in effects.items():70        for key, value in effects.items():
67            setattr(self, key, PotionEffect(value))71            setattr(self, key, PotionEffect(value))
68        self.duration = duration72        self.duration = duration
6973
70    def is_used(self):74    def is_used(self):
71        for key in dir(self):75        for key in dir(self):
72            value = getattr(self, key)76            value = getattr(self, key)
73            if type(value) is PotionEffect and not value.used:77            if type(value) is PotionEffect and not value.used:
74                return False78                return False
75        return True79        return True
7680
77    def __getattribute__(self, name):81    def __getattribute__(self, name):
78        result = object.__getattribute__(self, name)82        result = object.__getattribute__(self, name)
79        if (83        if (
80            object.__getattribute__(self, "is_component")84            object.__getattribute__(self, "is_component")
81            and type(result) is PotionEffect85            and type(result) is PotionEffect
82        ):86        ):
83            fake_result = PotionEffect(fake_func)87            fake_result = PotionEffect(fake_func)
84            fake_result.times = result.times88            fake_result.times = result.times
85            fake_result.used = result.used89            fake_result.used = result.used
86            return fake_result90            return fake_result
8791
88        return result92        return result
8993
90    def __add__(self, other):94    def __add__(self, other):
91        if self.is_component or other.is_component:95        if self.is_component or other.is_component:
92            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)96            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
93        if self.is_used() or other.is_used():97        if self.is_used() or other.is_used():
94            raise TypeError(POTION_IS_USED_ERROR_TEXT)98            raise TypeError(POTION_IS_USED_ERROR_TEXT)
9599
96        # transfering the methods from the object on the left side to dict,100        # transfering the methods from the object on the left side to dict,
97        # and if there are matching methods in the right side, we increace the intensity101        # and if there are matching methods in the right side, we increace the intensity
98        result_dict = {}102        result_dict = {}
99        for key in dir(self):103        for key in dir(self):
100            value = getattr(self, key)104            value = getattr(self, key)
101            if type(value) is PotionEffect and not value.used:105            if type(value) is PotionEffect and not value.used:
102                result_dict[key] = value.copy()106                result_dict[key] = value.copy()
103                if key in dir(other):107                if key in dir(other):
104                    other_value = getattr(other, key)108                    other_value = getattr(other, key)
105                    if not other_value.used:109                    if not other_value.used:
106                        result_dict[key] += other_value110                        result_dict[key] += other_value
107111
108        # transfering the methods that are only in the right side to the dict112        # transfering the methods that are only in the right side to the dict
109        for key in dir(other):113        for key in dir(other):
110            value = getattr(other, key)114            value = getattr(other, key)
111            if type(value) is PotionEffect and not key in dir(self) and not value.used:115            if type(value) is PotionEffect and not key in dir(self) and not value.used:
112                result_dict[key] = getattr(other, key).copy()116                result_dict[key] = getattr(other, key).copy()
113117
114        result_dict["duration"] = max(self.duration, other.duration)118        result_dict["duration"] = max(self.duration, other.duration)
115        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])119        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
116        self.is_component = True120        self.is_component = True
117        other.is_component = True121        other.is_component = True
118122
119        return result123        return result
120124
121    def __mul__(self, other):125    def __mul__(self, other):
122        if self.is_component:126        if self.is_component:
123            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)127            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
124        if self.is_used():128        if self.is_used():
125            raise TypeError(POTION_IS_USED_ERROR_TEXT)129            raise TypeError(POTION_IS_USED_ERROR_TEXT)
126        result_dict = {}130        result_dict = {}
127        # transfering the methods from the object to the dict and multiply them with the number131        # transfering the methods from the object to the dict and multiply them with the number
128        for key in dir(self):132        for key in dir(self):
129            value = getattr(self, key)133            value = getattr(self, key)
130            if type(value) is PotionEffect:134            if type(value) is PotionEffect:
131                result_dict[key] = value.copy()135                result_dict[key] = value.copy()
132                result_dict[key] *= other136                result_dict[key] *= other
133137
134        result_dict["duration"] = self.duration138        result_dict["duration"] = self.duration
135        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])139        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
136        self.is_component = True140        self.is_component = True
137141
138        return result142        return result
139143
140    def __sub__(self, other):144    def __sub__(self, other):
141        if self.is_component or other.is_component:145        if self.is_component or other.is_component:
142            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)146            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
143        if self.is_used() or other.is_used():147        if self.is_used() or other.is_used():
144            raise TypeError(POTION_IS_USED_ERROR_TEXT)148            raise TypeError(POTION_IS_USED_ERROR_TEXT)
145        result_dict = {}149        result_dict = {}
146        # validation that the substitution is valid150        # validation that the substitution is valid
147        for key in dir(other):151        for key in dir(other):
148            value = getattr(other, key)152            value = getattr(other, key)
149            if type(value) is PotionEffect and not key in dir(self):153            if type(value) is PotionEffect and not key in dir(self):
150                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)154                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
151        # transfering the methods from the object on the left side to dict,155        # transfering the methods from the object on the left side to dict,
152        # and if there are matching methods in the right side, we subtract their intensity156        # and if there are matching methods in the right side, we subtract their intensity
153        for key in dir(self):157        for key in dir(self):
154            value = getattr(self, key)158            value = getattr(self, key)
155            if type(value) is PotionEffect:159            if type(value) is PotionEffect:
156                result_dict[key] = value.copy()160                result_dict[key] = value.copy()
157                if key in dir(other):161                if key in dir(other):
158                    other_value = getattr(other, key)162                    other_value = getattr(other, key)
159                    if not other_value.used:163                    if not other_value.used:
160                        result_dict[key] -= getattr(other, key)164                        result_dict[key] -= getattr(other, key)
161                        if result_dict[key].times <= 0:165                        if result_dict[key].times <= 0:
162                            result_dict.pop(key)166                            result_dict.pop(key)
163167
164        result_dict["duration"] = self.duration168        result_dict["duration"] = self.duration
165        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])169        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
166        self.is_component = True170        self.is_component = True
167        other.is_component = True171        other.is_component = True
168        return result172        return result
169173
170    def __truediv__(self, other):174    def __truediv__(self, other):
171        if self.is_component:175        if self.is_component:
172            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)176            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
173        if self.is_used():177        if self.is_used():
174            raise TypeError(POTION_IS_USED_ERROR_TEXT)178            raise TypeError(POTION_IS_USED_ERROR_TEXT)
175        # spliting the object into equal parts, where the intensity is devided by the number179        # spliting the object into equal parts, where the intensity is devided by the number
176        result_list = []180        result_list = []
177        for _ in range(other):181        for _ in range(other):
178            result_dict = {}182            result_dict = {}
179            for key in dir(self):183            for key in dir(self):
180                value = getattr(self, key)184                value = getattr(self, key)
181                if type(value) is PotionEffect:185                if type(value) is PotionEffect:
182                    result_dict[key] = value.copy()186                    result_dict[key] = value.copy()
183                    result_dict[key] /= other187                    result_dict[key] /= other
184188
185            result_dict["duration"] = self.duration189            result_dict["duration"] = self.duration
186            result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])190            result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
187            result_list.append(result)191            result_list.append(result)
188192
189        self.is_component = True193        self.is_component = True
190        return tuple(result_list)194        return tuple(result_list)
191195
192    def __eq__(self, other):196    def __eq__(self, other):
193        for key in dir(self):197        for key in dir(self):
194            value = getattr(self, key)198            value = getattr(self, key)
195            if type(value) is PotionEffect:199            if type(value) is PotionEffect:
196                if not key in dir(other):200                if not key in dir(other):
197                    return False201                    return False
198                other_value = getattr(other, key)202                other_value = getattr(other, key)
199                if value.times != other_value.times or value.used != other_value.used:203                if value.times != other_value.times or value.used != other_value.used:
200                    return False204                    return False
201205
202        for key in dir(other):206        for key in dir(other):
203            value = getattr(other, key)207            value = getattr(other, key)
204            if type(value) is PotionEffect and not key in dir(self):208            if type(value) is PotionEffect and not key in dir(self):
205                return False209                return False
206210
207        return True211        return True
208212
209    def get_sum(self):213    def get_sum(self):
210        result = 0214        result = 0
211        for key in dir(self):215        for key in dir(self):
212            value = getattr(self, key)216            value = getattr(self, key)
213            if type(value) is PotionEffect:217            if type(value) is PotionEffect:
214                result += value.times218                result += value.times
215        return result219        return result
216220
217    def __gt__(self, other):221    def __gt__(self, other):
218        return self.get_sum() > other.get_sum()222        return self.get_sum() > other.get_sum()
219223
220    def __lt__(self, other):224    def __lt__(self, other):
221        return self.get_sum() < other.get_sum()225        return self.get_sum() < other.get_sum()
222226
223227
224class ГоспожатаПоХимия:228class ГоспожатаПоХимия:
225    def __init__(self):229    def __init__(self):
226        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values230        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
227        self.timer = {}231        self.timer = {}
228232
229    def apply_effect(self, target, effect):233    def apply_effect(self, target, effect):
230        # creating a revrse function to reverse the changes after the effect expires234        # creating a revrse function to reverse the changes after the effect expires
231        old_attributes = vars(target).copy()235        old_attributes = vars(target).copy()
232        effect(target)236        effect(target)
233        to_reverse = {}237        to_reverse = {}
234        for key, value in old_attributes.items():238        for key, value in old_attributes.items():
235            new_value = getattr(target, key)239            new_value = getattr(target, key)
236            if new_value != value:240            if new_value != value:
237                to_reverse[key] = new_value - value241                to_reverse[key] = new_value - value
238242
239        def reverse_effect():243        def reverse_effect():
240            for key, value in to_reverse.items():244            for key, value in to_reverse.items():
241                new_value = getattr(target, key)245                new_value = getattr(target, key)
242                setattr(target, key, new_value - value)246                setattr(target, key, new_value - value)
243247
244        return reverse_effect248        return reverse_effect
245249
246    def apply(self, target, potion):250    def apply(self, target, potion):
247        if potion.is_used():251        if potion.is_used():
248            raise TypeError(POTION_IS_USED_ERROR_TEXT)252            raise TypeError(POTION_IS_USED_ERROR_TEXT)
249253
250        if potion.is_component:  # this is probably useless, but just to be sure254        if potion.is_component:  # this is probably useless, but just to be sure
251            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)255            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
t252 t256        ordered_dir = sorted(dir(potion), key=calculate_molecular_mass, reverse=True)
253        for key in dir(potion):257        for key in ordered_dir:
254            value = getattr(potion, key)258            value = getattr(potion, key)
255            if type(value) is PotionEffect and not value.used:259            if type(value) is PotionEffect and not value.used:
256                reverse_func = self.apply_effect(target, value)260                reverse_func = self.apply_effect(target, value)
257                self.timer[reverse_func] = potion.duration261                self.timer[reverse_func] = potion.duration
258262
259    def tick(self):263    def tick(self):
260        to_iterate = self.timer.copy().items()264        to_iterate = self.timer.copy().items()
261        for key, value in to_iterate:265        for key, value in to_iterate:
262            self.timer[key] -= 1266            self.timer[key] -= 1
263            if value <= 1:267            if value <= 1:
264                key()268                key()
265                self.timer.pop(key)269                self.timer.pop(key)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
n3USED_INDICATOR_END = "_used"n
4TIMES_INDICATOR_END = "_times"
5EFFECT_ERROR_TEXT = "Effect is depleted."3EFFECT_ERROR_TEXT = "Effect is depleted."
6POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."4POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
7INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"5INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
8POTION_IS_USED_ERROR_TEXT = "Potion is depleted."6POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
97
108
11def fake_func(target):9def fake_func(target):
12    raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)10    raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
1311
1412
15def custom_round(value):13def custom_round(value):
16    result = round(value)14    result = round(value)
17    if cmath.isclose(15    if cmath.isclose(
18        result - value, 0.516        result - value, 0.5
19    ):  # the edge case where x.5 should be rounded down17    ):  # the edge case where x.5 should be rounded down
20        result -= 118        result -= 1
21    return result19    return result
2220
2321
24class PotionEffect:22class PotionEffect:
25    def __init__(self, func):23    def __init__(self, func):
26        self.func = func24        self.func = func
27        self.times = 125        self.times = 1
28        self.used = False26        self.used = False
2927
30    def __iadd__(self, other):28    def __iadd__(self, other):
31        self.times += other.times29        self.times += other.times
32        return self30        return self
3331
34    def __isub__(self, other):32    def __isub__(self, other):
35        self.times -= other.times33        self.times -= other.times
36        return self34        return self
3735
38    def __imul__(self, other):36    def __imul__(self, other):
39        self.times = custom_round(self.times * other)37        self.times = custom_round(self.times * other)
40        return self38        return self
4139
42    def __itruediv__(self, other):40    def __itruediv__(self, other):
43        self.times = custom_round(self.times / other)41        self.times = custom_round(self.times / other)
44        return self42        return self
4543
46    def copy(self):44    def copy(self):
47        result = PotionEffect(self.func)45        result = PotionEffect(self.func)
48        result.times = self.times46        result.times = self.times
49        result.used = self.used47        result.used = self.used
50        return result48        return result
5149
52    def __call__(self, target):50    def __call__(self, target):
53        if self.used:51        if self.used:
54            raise TypeError(EFFECT_ERROR_TEXT)52            raise TypeError(EFFECT_ERROR_TEXT)
55        for _ in range(self.times):53        for _ in range(self.times):
56            self.func(target)54            self.func(target)
57        self.used = True55        self.used = True
5856
5957
60class meta(type):58class meta(type):
61    def __new__(cls, name, bases, attr_dict):59    def __new__(cls, name, bases, attr_dict):
62        attr_dict["is_component"] = False60        attr_dict["is_component"] = False
63        return type.__new__(cls, name, bases, attr_dict)61        return type.__new__(cls, name, bases, attr_dict)
6462
6563
66class Potion(metaclass=meta):64class Potion(metaclass=meta):
67    def __init__(self, effects, duration):65    def __init__(self, effects, duration):
68        for key, value in effects.items():66        for key, value in effects.items():
69            setattr(self, key, PotionEffect(value))67            setattr(self, key, PotionEffect(value))
70        self.duration = duration68        self.duration = duration
7169
72    def is_used(self):70    def is_used(self):
73        for key in dir(self):71        for key in dir(self):
74            value = getattr(self, key)72            value = getattr(self, key)
75            if type(value) is PotionEffect and not value.used:73            if type(value) is PotionEffect and not value.used:
76                return False74                return False
77        return True75        return True
7876
79    def __getattribute__(self, name):77    def __getattribute__(self, name):
80        result = object.__getattribute__(self, name)78        result = object.__getattribute__(self, name)
81        if (79        if (
82            object.__getattribute__(self, "is_component")80            object.__getattribute__(self, "is_component")
83            and type(result) is PotionEffect81            and type(result) is PotionEffect
84        ):82        ):
85            fake_result = PotionEffect(fake_func)83            fake_result = PotionEffect(fake_func)
86            fake_result.times = result.times84            fake_result.times = result.times
87            fake_result.used = result.used85            fake_result.used = result.used
88            return fake_result86            return fake_result
8987
90        return result88        return result
9189
92    def __add__(self, other):90    def __add__(self, other):
93        if self.is_component or other.is_component:91        if self.is_component or other.is_component:
94            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)92            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
95        if self.is_used() or other.is_used():93        if self.is_used() or other.is_used():
96            raise TypeError(POTION_IS_USED_ERROR_TEXT)94            raise TypeError(POTION_IS_USED_ERROR_TEXT)
9795
98        # transfering the methods from the object on the left side to dict,96        # transfering the methods from the object on the left side to dict,
99        # and if there are matching methods in the right side, we increace the intensity97        # and if there are matching methods in the right side, we increace the intensity
100        result_dict = {}98        result_dict = {}
101        for key in dir(self):99        for key in dir(self):
102            value = getattr(self, key)100            value = getattr(self, key)
103            if type(value) is PotionEffect and not value.used:101            if type(value) is PotionEffect and not value.used:
104                result_dict[key] = value.copy()102                result_dict[key] = value.copy()
105                if key in dir(other):103                if key in dir(other):
106                    other_value = getattr(other, key)104                    other_value = getattr(other, key)
107                    if not other_value.used:105                    if not other_value.used:
108                        result_dict[key] += other_value106                        result_dict[key] += other_value
109107
110        # transfering the methods that are only in the right side to the dict108        # transfering the methods that are only in the right side to the dict
111        for key in dir(other):109        for key in dir(other):
112            value = getattr(other, key)110            value = getattr(other, key)
113            if type(value) is PotionEffect and not key in dir(self) and not value.used:111            if type(value) is PotionEffect and not key in dir(self) and not value.used:
114                result_dict[key] = getattr(other, key).copy()112                result_dict[key] = getattr(other, key).copy()
115113
116        result_dict["duration"] = max(self.duration, other.duration)114        result_dict["duration"] = max(self.duration, other.duration)
117        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])115        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
118        self.is_component = True116        self.is_component = True
119        other.is_component = True117        other.is_component = True
120118
121        return result119        return result
122120
123    def __mul__(self, other):121    def __mul__(self, other):
124        if self.is_component:122        if self.is_component:
125            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)123            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
126        if self.is_used():124        if self.is_used():
127            raise TypeError(POTION_IS_USED_ERROR_TEXT)125            raise TypeError(POTION_IS_USED_ERROR_TEXT)
128        result_dict = {}126        result_dict = {}
129        # transfering the methods from the object to the dict and multiply them with the number127        # transfering the methods from the object to the dict and multiply them with the number
130        for key in dir(self):128        for key in dir(self):
131            value = getattr(self, key)129            value = getattr(self, key)
132            if type(value) is PotionEffect:130            if type(value) is PotionEffect:
133                result_dict[key] = value.copy()131                result_dict[key] = value.copy()
134                result_dict[key] *= other132                result_dict[key] *= other
135133
136        result_dict["duration"] = self.duration134        result_dict["duration"] = self.duration
137        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])135        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
138        self.is_component = True136        self.is_component = True
139137
140        return result138        return result
141139
142    def __sub__(self, other):140    def __sub__(self, other):
143        if self.is_component or other.is_component:141        if self.is_component or other.is_component:
144            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)142            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
145        if self.is_used() or other.is_used():143        if self.is_used() or other.is_used():
146            raise TypeError(POTION_IS_USED_ERROR_TEXT)144            raise TypeError(POTION_IS_USED_ERROR_TEXT)
147        result_dict = {}145        result_dict = {}
148        # validation that the substitution is valid146        # validation that the substitution is valid
149        for key in dir(other):147        for key in dir(other):
150            value = getattr(other, key)148            value = getattr(other, key)
151            if type(value) is PotionEffect and not key in dir(self):149            if type(value) is PotionEffect and not key in dir(self):
152                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)150                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
153        # transfering the methods from the object on the left side to dict,151        # transfering the methods from the object on the left side to dict,
154        # and if there are matching methods in the right side, we subtract their intensity152        # and if there are matching methods in the right side, we subtract their intensity
155        for key in dir(self):153        for key in dir(self):
156            value = getattr(self, key)154            value = getattr(self, key)
157            if type(value) is PotionEffect:155            if type(value) is PotionEffect:
158                result_dict[key] = value.copy()156                result_dict[key] = value.copy()
159                if key in dir(other):157                if key in dir(other):
160                    other_value = getattr(other, key)158                    other_value = getattr(other, key)
161                    if not other_value.used:159                    if not other_value.used:
162                        result_dict[key] -= getattr(other, key)160                        result_dict[key] -= getattr(other, key)
163                        if result_dict[key].times <= 0:161                        if result_dict[key].times <= 0:
164                            result_dict.pop(key)162                            result_dict.pop(key)
165163
166        result_dict["duration"] = self.duration164        result_dict["duration"] = self.duration
167        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])165        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
168        self.is_component = True166        self.is_component = True
169        other.is_component = True167        other.is_component = True
170        return result168        return result
171169
172    def __truediv__(self, other):170    def __truediv__(self, other):
173        if self.is_component:171        if self.is_component:
174            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)172            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
175        if self.is_used():173        if self.is_used():
176            raise TypeError(POTION_IS_USED_ERROR_TEXT)174            raise TypeError(POTION_IS_USED_ERROR_TEXT)
177        # spliting the object into equal parts, where the intensity is devided by the number175        # spliting the object into equal parts, where the intensity is devided by the number
178        result_list = []176        result_list = []
179        for _ in range(other):177        for _ in range(other):
180            result_dict = {}178            result_dict = {}
181            for key in dir(self):179            for key in dir(self):
182                value = getattr(self, key)180                value = getattr(self, key)
183                if type(value) is PotionEffect:181                if type(value) is PotionEffect:
184                    result_dict[key] = value.copy()182                    result_dict[key] = value.copy()
185                    result_dict[key] /= other183                    result_dict[key] /= other
186184
187            result_dict["duration"] = self.duration185            result_dict["duration"] = self.duration
188            result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])186            result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
189            result_list.append(result)187            result_list.append(result)
190188
191        self.is_component = True189        self.is_component = True
192        return tuple(result_list)190        return tuple(result_list)
193191
194    def __eq__(self, other):192    def __eq__(self, other):
195        for key in dir(self):193        for key in dir(self):
196            value = getattr(self, key)194            value = getattr(self, key)
197            if type(value) is PotionEffect:195            if type(value) is PotionEffect:
198                if not key in dir(other):196                if not key in dir(other):
199                    return False197                    return False
200                other_value = getattr(other, key)198                other_value = getattr(other, key)
201                if value.times != other_value.times or value.used != other_value.used:199                if value.times != other_value.times or value.used != other_value.used:
202                    return False200                    return False
203201
204        for key in dir(other):202        for key in dir(other):
205            value = getattr(other, key)203            value = getattr(other, key)
206            if type(value) is PotionEffect and not key in dir(self):204            if type(value) is PotionEffect and not key in dir(self):
207                return False205                return False
208206
209        return True207        return True
210208
211    def get_sum(self):209    def get_sum(self):
212        result = 0210        result = 0
213        for key in dir(self):211        for key in dir(self):
214            value = getattr(self, key)212            value = getattr(self, key)
215            if type(value) is PotionEffect:213            if type(value) is PotionEffect:
216                result += value.times214                result += value.times
217        return result215        return result
218216
219    def __gt__(self, other):217    def __gt__(self, other):
220        return self.get_sum() > other.get_sum()218        return self.get_sum() > other.get_sum()
221219
222    def __lt__(self, other):220    def __lt__(self, other):
223        return self.get_sum() < other.get_sum()221        return self.get_sum() < other.get_sum()
224222
225223
226class ГоспожатаПоХимия:224class ГоспожатаПоХимия:
227    def __init__(self):225    def __init__(self):
228        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values226        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
229        self.timer = {}227        self.timer = {}
230228
231    def apply_effect(self, target, effect):229    def apply_effect(self, target, effect):
232        # creating a revrse function to reverse the changes after the effect expires230        # creating a revrse function to reverse the changes after the effect expires
233        old_attributes = vars(target).copy()231        old_attributes = vars(target).copy()
234        effect(target)232        effect(target)
235        to_reverse = {}233        to_reverse = {}
236        for key, value in old_attributes.items():234        for key, value in old_attributes.items():
237            new_value = getattr(target, key)235            new_value = getattr(target, key)
238            if new_value != value:236            if new_value != value:
239                to_reverse[key] = new_value - value237                to_reverse[key] = new_value - value
240238
241        def reverse_effect():239        def reverse_effect():
242            for key, value in to_reverse.items():240            for key, value in to_reverse.items():
243                new_value = getattr(target, key)241                new_value = getattr(target, key)
244                setattr(target, key, new_value - value)242                setattr(target, key, new_value - value)
245243
246        return reverse_effect244        return reverse_effect
247245
248    def apply(self, target, potion):246    def apply(self, target, potion):
249        if potion.is_used():247        if potion.is_used():
250            raise TypeError(POTION_IS_USED_ERROR_TEXT)248            raise TypeError(POTION_IS_USED_ERROR_TEXT)
251249
252        if potion.is_component:  # this is probably useless, but just to be sure250        if potion.is_component:  # this is probably useless, but just to be sure
253            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)251            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
254252
255        for key in dir(potion):253        for key in dir(potion):
256            value = getattr(potion, key)254            value = getattr(potion, key)
257            if type(value) is PotionEffect and not value.used:255            if type(value) is PotionEffect and not value.used:
258                reverse_func = self.apply_effect(target, value)256                reverse_func = self.apply_effect(target, value)
259                self.timer[reverse_func] = potion.duration257                self.timer[reverse_func] = potion.duration
260258
261    def tick(self):259    def tick(self):
262        to_iterate = self.timer.copy().items()260        to_iterate = self.timer.copy().items()
263        for key, value in to_iterate:261        for key, value in to_iterate:
nn262            self.timer[key] -= 1
264            if value == 0:263            if value <= 1:
265                key()264                key()
266                self.timer.pop(key)265                self.timer.pop(key)
t267            else:t
268                self.timer[key] -= 1
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import cmathf1import cmath
22
3USED_INDICATOR_END = "_used"3USED_INDICATOR_END = "_used"
4TIMES_INDICATOR_END = "_times"4TIMES_INDICATOR_END = "_times"
5EFFECT_ERROR_TEXT = "Effect is depleted."5EFFECT_ERROR_TEXT = "Effect is depleted."
6POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."6POTION_IS_COMPONENT_ERROR_TEXT = "Potion is now part of something bigger than itself."
7INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"7INVALID_SUBSTITUTION_ERROR_TEXT = "Invalid substitution"
8POTION_IS_USED_ERROR_TEXT = "Potion is depleted."8POTION_IS_USED_ERROR_TEXT = "Potion is depleted."
99
1010
11def fake_func(target):11def fake_func(target):
12    raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)12    raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
1313
1414
15def custom_round(value):15def custom_round(value):
16    result = round(value)16    result = round(value)
17    if cmath.isclose(17    if cmath.isclose(
18        result - value, 0.518        result - value, 0.5
19    ):  # the edge case where x.5 should be rounded down19    ):  # the edge case where x.5 should be rounded down
20        result -= 120        result -= 1
21    return result21    return result
2222
2323
24class PotionEffect:24class PotionEffect:
25    def __init__(self, func):25    def __init__(self, func):
26        self.func = func26        self.func = func
27        self.times = 127        self.times = 1
28        self.used = False28        self.used = False
2929
30    def __iadd__(self, other):30    def __iadd__(self, other):
31        self.times += other.times31        self.times += other.times
32        return self32        return self
3333
34    def __isub__(self, other):34    def __isub__(self, other):
35        self.times -= other.times35        self.times -= other.times
36        return self36        return self
3737
38    def __imul__(self, other):38    def __imul__(self, other):
39        self.times = custom_round(self.times * other)39        self.times = custom_round(self.times * other)
40        return self40        return self
4141
42    def __itruediv__(self, other):42    def __itruediv__(self, other):
43        self.times = custom_round(self.times / other)43        self.times = custom_round(self.times / other)
44        return self44        return self
4545
46    def copy(self):46    def copy(self):
47        result = PotionEffect(self.func)47        result = PotionEffect(self.func)
48        result.times = self.times48        result.times = self.times
49        result.used = self.used49        result.used = self.used
50        return result50        return result
5151
52    def __call__(self, target):52    def __call__(self, target):
53        if self.used:53        if self.used:
54            raise TypeError(EFFECT_ERROR_TEXT)54            raise TypeError(EFFECT_ERROR_TEXT)
55        for _ in range(self.times):55        for _ in range(self.times):
56            self.func(target)56            self.func(target)
57        self.used = True57        self.used = True
5858
5959
60class meta(type):60class meta(type):
61    def __new__(cls, name, bases, attr_dict):61    def __new__(cls, name, bases, attr_dict):
62        attr_dict["is_component"] = False62        attr_dict["is_component"] = False
63        return type.__new__(cls, name, bases, attr_dict)63        return type.__new__(cls, name, bases, attr_dict)
6464
6565
66class Potion(metaclass=meta):66class Potion(metaclass=meta):
67    def __init__(self, effects, duration):67    def __init__(self, effects, duration):
68        for key, value in effects.items():68        for key, value in effects.items():
69            setattr(self, key, PotionEffect(value))69            setattr(self, key, PotionEffect(value))
70        self.duration = duration70        self.duration = duration
7171
72    def is_used(self):72    def is_used(self):
73        for key in dir(self):73        for key in dir(self):
74            value = getattr(self, key)74            value = getattr(self, key)
75            if type(value) is PotionEffect and not value.used:75            if type(value) is PotionEffect and not value.used:
76                return False76                return False
77        return True77        return True
7878
79    def __getattribute__(self, name):79    def __getattribute__(self, name):
80        result = object.__getattribute__(self, name)80        result = object.__getattribute__(self, name)
81        if (81        if (
82            object.__getattribute__(self, "is_component")82            object.__getattribute__(self, "is_component")
83            and type(result) is PotionEffect83            and type(result) is PotionEffect
84        ):84        ):
85            fake_result = PotionEffect(fake_func)85            fake_result = PotionEffect(fake_func)
86            fake_result.times = result.times86            fake_result.times = result.times
87            fake_result.used = result.used87            fake_result.used = result.used
88            return fake_result88            return fake_result
8989
90        return result90        return result
9191
92    def __add__(self, other):92    def __add__(self, other):
93        if self.is_component or other.is_component:93        if self.is_component or other.is_component:
94            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)94            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
nn95        if self.is_used() or other.is_used():
96            raise TypeError(POTION_IS_USED_ERROR_TEXT)
9597
96        # transfering the methods from the object on the left side to dict,98        # transfering the methods from the object on the left side to dict,
97        # and if there are matching methods in the right side, we increace the intensity99        # and if there are matching methods in the right side, we increace the intensity
98        result_dict = {}100        result_dict = {}
99        for key in dir(self):101        for key in dir(self):
100            value = getattr(self, key)102            value = getattr(self, key)
101            if type(value) is PotionEffect and not value.used:103            if type(value) is PotionEffect and not value.used:
102                result_dict[key] = value.copy()104                result_dict[key] = value.copy()
103                if key in dir(other):105                if key in dir(other):
104                    other_value = getattr(other, key)106                    other_value = getattr(other, key)
105                    if not other_value.used:107                    if not other_value.used:
106                        result_dict[key] += other_value108                        result_dict[key] += other_value
107109
108        # transfering the methods that are only in the right side to the dict110        # transfering the methods that are only in the right side to the dict
109        for key in dir(other):111        for key in dir(other):
110            value = getattr(other, key)112            value = getattr(other, key)
111            if type(value) is PotionEffect and not key in dir(self) and not value.used:113            if type(value) is PotionEffect and not key in dir(self) and not value.used:
112                result_dict[key] = getattr(other, key).copy()114                result_dict[key] = getattr(other, key).copy()
113115
114        result_dict["duration"] = max(self.duration, other.duration)116        result_dict["duration"] = max(self.duration, other.duration)
115        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])117        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
116        self.is_component = True118        self.is_component = True
117        other.is_component = True119        other.is_component = True
118120
119        return result121        return result
120122
121    def __mul__(self, other):123    def __mul__(self, other):
122        if self.is_component:124        if self.is_component:
123            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)125            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
n124 n126        if self.is_used():
127            raise TypeError(POTION_IS_USED_ERROR_TEXT)
125        result_dict = {}128        result_dict = {}
126        # transfering the methods from the object to the dict and multiply them with the number129        # transfering the methods from the object to the dict and multiply them with the number
127        for key in dir(self):130        for key in dir(self):
128            value = getattr(self, key)131            value = getattr(self, key)
129            if type(value) is PotionEffect:132            if type(value) is PotionEffect:
130                result_dict[key] = value.copy()133                result_dict[key] = value.copy()
131                result_dict[key] *= other134                result_dict[key] *= other
132135
133        result_dict["duration"] = self.duration136        result_dict["duration"] = self.duration
134        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])137        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
135        self.is_component = True138        self.is_component = True
136139
137        return result140        return result
138141
139    def __sub__(self, other):142    def __sub__(self, other):
140        if self.is_component or other.is_component:143        if self.is_component or other.is_component:
141            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)144            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
n142 n145        if self.is_used() or other.is_used():
146            raise TypeError(POTION_IS_USED_ERROR_TEXT)
143        result_dict = {}147        result_dict = {}
144        # validation that the substitution is valid148        # validation that the substitution is valid
145        for key in dir(other):149        for key in dir(other):
146            value = getattr(other, key)150            value = getattr(other, key)
147            if type(value) is PotionEffect and not key in dir(self):151            if type(value) is PotionEffect and not key in dir(self):
148                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)152                raise TypeError(INVALID_SUBSTITUTION_ERROR_TEXT)
149        # transfering the methods from the object on the left side to dict,153        # transfering the methods from the object on the left side to dict,
150        # and if there are matching methods in the right side, we subtract their intensity154        # and if there are matching methods in the right side, we subtract their intensity
151        for key in dir(self):155        for key in dir(self):
152            value = getattr(self, key)156            value = getattr(self, key)
153            if type(value) is PotionEffect:157            if type(value) is PotionEffect:
154                result_dict[key] = value.copy()158                result_dict[key] = value.copy()
155                if key in dir(other):159                if key in dir(other):
156                    other_value = getattr(other, key)160                    other_value = getattr(other, key)
157                    if not other_value.used:161                    if not other_value.used:
158                        result_dict[key] -= getattr(other, key)162                        result_dict[key] -= getattr(other, key)
159                        if result_dict[key].times <= 0:163                        if result_dict[key].times <= 0:
160                            result_dict.pop(key)164                            result_dict.pop(key)
161165
162        result_dict["duration"] = self.duration166        result_dict["duration"] = self.duration
163        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])167        result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
164        self.is_component = True168        self.is_component = True
165        other.is_component = True169        other.is_component = True
166        return result170        return result
167171
168    def __truediv__(self, other):172    def __truediv__(self, other):
169        if self.is_component:173        if self.is_component:
170            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)174            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
tt175        if self.is_used():
176            raise TypeError(POTION_IS_USED_ERROR_TEXT)
171        # spliting the object into equal parts, where the intensity is devided by the number177        # spliting the object into equal parts, where the intensity is devided by the number
172        result_list = []178        result_list = []
173        for _ in range(other):179        for _ in range(other):
174            result_dict = {}180            result_dict = {}
175            for key in dir(self):181            for key in dir(self):
176                value = getattr(self, key)182                value = getattr(self, key)
177                if type(value) is PotionEffect:183                if type(value) is PotionEffect:
178                    result_dict[key] = value.copy()184                    result_dict[key] = value.copy()
179                    result_dict[key] /= other185                    result_dict[key] /= other
180186
181            result_dict["duration"] = self.duration187            result_dict["duration"] = self.duration
182            result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])188            result = meta("Potion", (Potion,), result_dict)({}, result_dict["duration"])
183            result_list.append(result)189            result_list.append(result)
184190
185        self.is_component = True191        self.is_component = True
186        return tuple(result_list)192        return tuple(result_list)
187193
188    def __eq__(self, other):194    def __eq__(self, other):
189        for key in dir(self):195        for key in dir(self):
190            value = getattr(self, key)196            value = getattr(self, key)
191            if type(value) is PotionEffect:197            if type(value) is PotionEffect:
192                if not key in dir(other):198                if not key in dir(other):
193                    return False199                    return False
194                other_value = getattr(other, key)200                other_value = getattr(other, key)
195                if value.times != other_value.times or value.used != other_value.used:201                if value.times != other_value.times or value.used != other_value.used:
196                    return False202                    return False
197203
198        for key in dir(other):204        for key in dir(other):
199            value = getattr(other, key)205            value = getattr(other, key)
200            if type(value) is PotionEffect and not key in dir(self):206            if type(value) is PotionEffect and not key in dir(self):
201                return False207                return False
202208
203        return True209        return True
204210
205    def get_sum(self):211    def get_sum(self):
206        result = 0212        result = 0
207        for key in dir(self):213        for key in dir(self):
208            value = getattr(self, key)214            value = getattr(self, key)
209            if type(value) is PotionEffect:215            if type(value) is PotionEffect:
210                result += value.times216                result += value.times
211        return result217        return result
212218
213    def __gt__(self, other):219    def __gt__(self, other):
214        return self.get_sum() > other.get_sum()220        return self.get_sum() > other.get_sum()
215221
216    def __lt__(self, other):222    def __lt__(self, other):
217        return self.get_sum() < other.get_sum()223        return self.get_sum() < other.get_sum()
218224
219225
220class ГоспожатаПоХимия:226class ГоспожатаПоХимия:
221    def __init__(self):227    def __init__(self):
222        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values228        # dictionary to store the reverse effectss of potions as a key, and when to be executed as values
223        self.timer = {}229        self.timer = {}
224230
225    def apply_effect(self, target, effect):231    def apply_effect(self, target, effect):
226        # creating a revrse function to reverse the changes after the effect expires232        # creating a revrse function to reverse the changes after the effect expires
227        old_attributes = vars(target).copy()233        old_attributes = vars(target).copy()
228        effect(target)234        effect(target)
229        to_reverse = {}235        to_reverse = {}
230        for key, value in old_attributes.items():236        for key, value in old_attributes.items():
231            new_value = getattr(target, key)237            new_value = getattr(target, key)
232            if new_value != value:238            if new_value != value:
233                to_reverse[key] = new_value - value239                to_reverse[key] = new_value - value
234240
235        def reverse_effect():241        def reverse_effect():
236            for key, value in to_reverse.items():242            for key, value in to_reverse.items():
237                new_value = getattr(target, key)243                new_value = getattr(target, key)
238                setattr(target, key, new_value - value)244                setattr(target, key, new_value - value)
239245
240        return reverse_effect246        return reverse_effect
241247
242    def apply(self, target, potion):248    def apply(self, target, potion):
243        if potion.is_used():249        if potion.is_used():
244            raise TypeError(POTION_IS_USED_ERROR_TEXT)250            raise TypeError(POTION_IS_USED_ERROR_TEXT)
245251
246        if potion.is_component:  # this is probably useless, but just to be sure252        if potion.is_component:  # this is probably useless, but just to be sure
247            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)253            raise TypeError(POTION_IS_COMPONENT_ERROR_TEXT)
248254
249        for key in dir(potion):255        for key in dir(potion):
250            value = getattr(potion, key)256            value = getattr(potion, key)
251            if type(value) is PotionEffect and not value.used:257            if type(value) is PotionEffect and not value.used:
252                reverse_func = self.apply_effect(target, value)258                reverse_func = self.apply_effect(target, value)
253                self.timer[reverse_func] = potion.duration259                self.timer[reverse_func] = potion.duration
254260
255    def tick(self):261    def tick(self):
256        to_iterate = self.timer.copy().items()262        to_iterate = self.timer.copy().items()
257        for key, value in to_iterate:263        for key, value in to_iterate:
258            if value == 0:264            if value == 0:
259                key()265                key()
260                self.timer.pop(key)266                self.timer.pop(key)
261            else:267            else:
262                self.timer[key] -= 1268                self.timer[key] -= 1
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op