1from copy import deepcopy, copy
2
3
4class Potion:
5 @staticmethod
6 def custom_round(number):
7 if number - int(number) > 0.5:
8 return int(number) + 1
9 return int(number)
10
11 def __init__(self, effects, duration):
12 self.effects = effects
13 self.used_effects = []
14 self.effects_intensity = {key: 1 for key in effects.keys()}
15 self.duration = duration
16 self.used = False
17
18 def __getattr__(self, item):
19 def decorator(func):
20 def wrapper(target):
21 for _ in range(self.effects_intensity[list(self.effects.keys())[list(self.effects.values()).index(func)]]):
22 func(target)
23 return wrapper
24
25 if self.used:
26 raise TypeError('Potion is now part of something bigger than itself.')
27
28 if item in self.effects.keys():
29 if item in self.used_effects:
30 raise TypeError('Effect is depleted.')
31 self.used_effects.append(item)
32 return decorator(self.effects[item])
33 else:
34 raise AttributeError('Effect not found.')
35
36 def __copy__(self):
37 new_potion = Potion({}, 0)
38 new_potion.effects = self.effects.copy()
39 new_potion.used_effects = self.used_effects.copy()
40 new_potion.effects_intensity = self.effects_intensity.copy()
41 new_potion.duration = self.duration
42 new_potion.used = self.used
43 return new_potion
44
45 def __add__(self, other):
46 if self.used or other.used:
47 raise TypeError('Potion is now part of something bigger than itself.')
48
49 new_potion = self.__copy__()
50
51 for key in other.effects.keys():
52 if key in new_potion.effects_intensity.keys():
53 new_potion.effects_intensity[key] += other.effects_intensity[key]
54 else:
55 new_potion.effects[key] = other.effects[key]
56 new_potion.effects_intensity[key] = other.effects_intensity[key]
57
58 self.used = True
59 other.used = True
60
61 return new_potion
62
63 def __mul__(self, num):
64 if self.used:
65 raise TypeError('Potion is now part of something bigger than itself.')
66
67 if num < 0:
68 raise ValueError('Multiplier must be non negative.')
69
70 new_potion = self.__copy__()
71 for key in new_potion.effects_intensity.keys():
72 if 0 < num < 1:
73 new_potion.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] * num)
74 else:
75 new_potion.effects_intensity[key] *= num
76
77 self.used = True
78
79 return new_potion
80
81 def __sub__(self, other):
82 if self.used or other.used:
83 raise TypeError('Potion is now part of something bigger than itself.')
84
85 if not isinstance(other, Potion):
86 raise TypeError('Cannot subtract non potion object.')
87
88 new_potion = self.__copy__()
89 for key in other.effects.keys():
90 if key not in self.effects.keys():
91 raise TypeError('Cannot subtract potion with different effects.')
92 if new_potion.effects_intensity[key] - other.effects_intensity[key] <= 0:
93 del new_potion.effects[key]
94 del new_potion.effects_intensity[key]
95 else:
96 new_potion.effects_intensity[key] -= other.effects_intensity[key]
97
98 self.used = True
99 other.used = True
100
101 return new_potion
102
103 def __truediv__(self, other):
104 if self.used:
105 raise TypeError('Potion is now part of something bigger than itself.')
106
107 if not isinstance(other, int):
108 raise TypeError('Cannot divide non potion object.')
109
110 new_potion = self.__copy__()
111 for key in new_potion.effects_intensity.keys():
112 self.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] / other)
113
114 self.used = True
115
116 return (new_potion,) * other
117
118 def __eq__(self, other):
119 if self.used or other.used:
120 raise TypeError('Potion is now part of something bigger than itself.')
121
122 if not isinstance(other, Potion):
123 raise TypeError('Cannot compare non potion object.')
124
125 return self.effects == other.effects and self.effects_intensity == other.effects_intensity
126
127 def __lt__(self, other):
128 if self.used or other.used:
129 raise TypeError('Potion is now part of something bigger than itself.')
130
131 if not isinstance(other, Potion):
132 raise TypeError('Cannot compare non potion object.')
133
134 lhs_sum = sum(self.effects_intensity.values())
135 rhs_sum = sum(other.effects_intensity.values())
136
137 return lhs_sum < rhs_sum
138
139 def __gt__(self, other):
140 if self.used or other.used:
141 raise TypeError('Potion is now part of something bigger than itself.')
142
143 if not isinstance(other, Potion):
144 raise TypeError('Cannot compare non potion object.')
145
146 lhs_sum = sum(self.effects_intensity.values())
147 rhs_sum = sum(other.effects_intensity.values())
148
149 return lhs_sum > rhs_sum
150
151
152class ГоспожатаПоХимия:
153 def __init__(self):
154 self.ticks = 0
155 self.applied_effects = []
156 self.used_potions = []
157
158 def apply(self, target, potion):
159 def get_moll_mass(name):
160 result = 0
161 for symbol in name:
162 result += ord(symbol)
163 return result
164
165 if potion in self.used_potions:
166 raise TypeError('Potion is depleted.')
167
168 self.used_potions.append(potion)
169
170 if potion.duration == 0:
171 return
172
173 effect_names = list(potion.effects.keys())
174 effect_names.sort(key=lambda x: get_moll_mass(x), reverse=True)
175
176 for key in effect_names:
177 try:
178 state = {attr: val for attr, val in target.__dict__.items() if not attr.startswith('__')}
179 potion.__getattr__(key)(target)
180 for attr in dir(target):
181 if attr.startswith('__'):
182 continue
183 state[attr] = getattr(target, attr) - state[attr]
184 self.applied_effects.append(
185 (potion.duration, self.ticks, target, state))
186 except TypeError:
187 raise TypeError('Potion is depleted.')
188
189 def tick(self):
190 self.ticks += 1
191
192 self.applied_effects.sort(key=lambda x: x[0])
193 for (duration, ticks_atm, target, obj_before) in self.applied_effects:
194 if self.ticks == ticks_atm + duration:
195 for attr, val in obj_before.items():
196 cur_value = getattr(target, attr)
197 setattr(target, attr, cur_value - val)
........E.EFEEEEEEEE
======================================================================
ERROR: test_dilution (test.TestPotionOperations)
Test dilution of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 122, in test_dilution
self._target = copy.deepcopy(self._target)
AttributeError: 'function' object has no attribute 'deepcopy'
======================================================================
ERROR: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 171, in test_purification
self._target = copy.deepcopy(self._target)
AttributeError: 'function' object has no attribute 'deepcopy'
======================================================================
ERROR: test_applying_depleted_potion (test.TestГоспожатаПоХимия)
Test applying a depleted potion or a potion that was used in a reaction.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 379, in test_applying_depleted_potion
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
ERROR: test_applying_normal_case (test.TestГоспожатаПоХимия)
Test applying a normal potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 350, in test_applying_normal_case
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
ERROR: test_applying_order (test.TestГоспожатаПоХимия)
Test applying order of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 404, in test_applying_order
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
ERROR: test_applying_part_of_potion (test.TestГоспожатаПоХимия)
Test applying only a part of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 365, in test_applying_part_of_potion
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
ERROR: test_ticking_immutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with immutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 424, in test_ticking_immutable
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
ERROR: test_ticking_multiple_potions (test.TestГоспожатаПоХимия)
Test ticking after applying multiple potions which affect the same attribute.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 454, in test_ticking_multiple_potions
self._dimitrichka.apply(self._target, potion1)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
ERROR: test_ticking_multiple_targets (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 485, in test_ticking_multiple_targets
self._dimitrichka.apply(target1, potion1)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
ERROR: test_ticking_mutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 183, in apply
state[attr] = getattr(target, attr) - state[attr]
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 438, in test_ticking_mutable
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 187, in apply
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
FAIL: test_separation (test.TestPotionOperations)
Test separation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 215, in test_separation
self.assertEqual(self._target.int_attr, 5 * (10 ** 3))
AssertionError: 5000000000 != 5000
----------------------------------------------------------------------
Ran 20 tests in 0.002s
FAILED (failures=1, errors=10)
Георги Илиев
05.12.2023 13:11Със стила не, ама с логиката има много, очаквайте нова версия!
|
Виктор Бечев
05.12.2023 12:10Отвъд дребните забележки - не виждам големи проблеми със стила.
|
| f | 1 | from copy import deepcopy, copy | f | 1 | from copy import deepcopy, copy |
| 2 | 2 | ||||
| 3 | 3 | ||||
| 4 | class Potion: | 4 | class Potion: | ||
| 5 | @staticmethod | 5 | @staticmethod | ||
| 6 | def custom_round(number): | 6 | def custom_round(number): | ||
| 7 | if number - int(number) > 0.5: | 7 | if number - int(number) > 0.5: | ||
| 8 | return int(number) + 1 | 8 | return int(number) + 1 | ||
| 9 | return int(number) | 9 | return int(number) | ||
| 10 | 10 | ||||
| 11 | def __init__(self, effects, duration): | 11 | def __init__(self, effects, duration): | ||
| 12 | self.effects = effects | 12 | self.effects = effects | ||
| 13 | self.used_effects = [] | 13 | self.used_effects = [] | ||
| 14 | self.effects_intensity = {key: 1 for key in effects.keys()} | 14 | self.effects_intensity = {key: 1 for key in effects.keys()} | ||
| 15 | self.duration = duration | 15 | self.duration = duration | ||
| 16 | self.used = False | 16 | self.used = False | ||
| 17 | 17 | ||||
| 18 | def __getattr__(self, item): | 18 | def __getattr__(self, item): | ||
| 19 | def decorator(func): | 19 | def decorator(func): | ||
| 20 | def wrapper(target): | 20 | def wrapper(target): | ||
| 21 | for _ in range(self.effects_intensity[list(self.effects.keys())[list(self.effects.values()).index(func)]]): | 21 | for _ in range(self.effects_intensity[list(self.effects.keys())[list(self.effects.values()).index(func)]]): | ||
| 22 | func(target) | 22 | func(target) | ||
| 23 | return wrapper | 23 | return wrapper | ||
| 24 | 24 | ||||
| 25 | if self.used: | 25 | if self.used: | ||
| 26 | raise TypeError('Potion is now part of something bigger than itself.') | 26 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 27 | 27 | ||||
| 28 | if item in self.effects.keys(): | 28 | if item in self.effects.keys(): | ||
| 29 | if item in self.used_effects: | 29 | if item in self.used_effects: | ||
| 30 | raise TypeError('Effect is depleted.') | 30 | raise TypeError('Effect is depleted.') | ||
| 31 | self.used_effects.append(item) | 31 | self.used_effects.append(item) | ||
| 32 | return decorator(self.effects[item]) | 32 | return decorator(self.effects[item]) | ||
| 33 | else: | 33 | else: | ||
| 34 | raise AttributeError('Effect not found.') | 34 | raise AttributeError('Effect not found.') | ||
| 35 | 35 | ||||
| 36 | def __copy__(self): | 36 | def __copy__(self): | ||
| 37 | new_potion = Potion({}, 0) | 37 | new_potion = Potion({}, 0) | ||
| 38 | new_potion.effects = self.effects.copy() | 38 | new_potion.effects = self.effects.copy() | ||
| 39 | new_potion.used_effects = self.used_effects.copy() | 39 | new_potion.used_effects = self.used_effects.copy() | ||
| 40 | new_potion.effects_intensity = self.effects_intensity.copy() | 40 | new_potion.effects_intensity = self.effects_intensity.copy() | ||
| 41 | new_potion.duration = self.duration | 41 | new_potion.duration = self.duration | ||
| 42 | new_potion.used = self.used | 42 | new_potion.used = self.used | ||
| 43 | return new_potion | 43 | return new_potion | ||
| 44 | 44 | ||||
| 45 | def __add__(self, other): | 45 | def __add__(self, other): | ||
| 46 | if self.used or other.used: | 46 | if self.used or other.used: | ||
| 47 | raise TypeError('Potion is now part of something bigger than itself.') | 47 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 48 | 48 | ||||
| 49 | new_potion = self.__copy__() | 49 | new_potion = self.__copy__() | ||
| 50 | 50 | ||||
| 51 | for key in other.effects.keys(): | 51 | for key in other.effects.keys(): | ||
| 52 | if key in new_potion.effects_intensity.keys(): | 52 | if key in new_potion.effects_intensity.keys(): | ||
| 53 | new_potion.effects_intensity[key] += other.effects_intensity[key] | 53 | new_potion.effects_intensity[key] += other.effects_intensity[key] | ||
| 54 | else: | 54 | else: | ||
| 55 | new_potion.effects[key] = other.effects[key] | 55 | new_potion.effects[key] = other.effects[key] | ||
| 56 | new_potion.effects_intensity[key] = other.effects_intensity[key] | 56 | new_potion.effects_intensity[key] = other.effects_intensity[key] | ||
| 57 | 57 | ||||
| 58 | self.used = True | 58 | self.used = True | ||
| 59 | other.used = True | 59 | other.used = True | ||
| 60 | 60 | ||||
| 61 | return new_potion | 61 | return new_potion | ||
| 62 | 62 | ||||
| 63 | def __mul__(self, num): | 63 | def __mul__(self, num): | ||
| 64 | if self.used: | 64 | if self.used: | ||
| 65 | raise TypeError('Potion is now part of something bigger than itself.') | 65 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 66 | 66 | ||||
| 67 | if num < 0: | 67 | if num < 0: | ||
| 68 | raise ValueError('Multiplier must be non negative.') | 68 | raise ValueError('Multiplier must be non negative.') | ||
| 69 | 69 | ||||
| 70 | new_potion = self.__copy__() | 70 | new_potion = self.__copy__() | ||
| 71 | for key in new_potion.effects_intensity.keys(): | 71 | for key in new_potion.effects_intensity.keys(): | ||
| 72 | if 0 < num < 1: | 72 | if 0 < num < 1: | ||
| 73 | new_potion.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] * num) | 73 | new_potion.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] * num) | ||
| 74 | else: | 74 | else: | ||
| 75 | new_potion.effects_intensity[key] *= num | 75 | new_potion.effects_intensity[key] *= num | ||
| 76 | 76 | ||||
| 77 | self.used = True | 77 | self.used = True | ||
| 78 | 78 | ||||
| 79 | return new_potion | 79 | return new_potion | ||
| 80 | 80 | ||||
| 81 | def __sub__(self, other): | 81 | def __sub__(self, other): | ||
| 82 | if self.used or other.used: | 82 | if self.used or other.used: | ||
| 83 | raise TypeError('Potion is now part of something bigger than itself.') | 83 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 84 | 84 | ||||
| 85 | if not isinstance(other, Potion): | 85 | if not isinstance(other, Potion): | ||
| 86 | raise TypeError('Cannot subtract non potion object.') | 86 | raise TypeError('Cannot subtract non potion object.') | ||
| 87 | 87 | ||||
| 88 | new_potion = self.__copy__() | 88 | new_potion = self.__copy__() | ||
| 89 | for key in other.effects.keys(): | 89 | for key in other.effects.keys(): | ||
| 90 | if key not in self.effects.keys(): | 90 | if key not in self.effects.keys(): | ||
| 91 | raise TypeError('Cannot subtract potion with different effects.') | 91 | raise TypeError('Cannot subtract potion with different effects.') | ||
| 92 | if new_potion.effects_intensity[key] - other.effects_intensity[key] <= 0: | 92 | if new_potion.effects_intensity[key] - other.effects_intensity[key] <= 0: | ||
| 93 | del new_potion.effects[key] | 93 | del new_potion.effects[key] | ||
| 94 | del new_potion.effects_intensity[key] | 94 | del new_potion.effects_intensity[key] | ||
| 95 | else: | 95 | else: | ||
| 96 | new_potion.effects_intensity[key] -= other.effects_intensity[key] | 96 | new_potion.effects_intensity[key] -= other.effects_intensity[key] | ||
| 97 | 97 | ||||
| 98 | self.used = True | 98 | self.used = True | ||
| 99 | other.used = True | 99 | other.used = True | ||
| 100 | 100 | ||||
| 101 | return new_potion | 101 | return new_potion | ||
| 102 | 102 | ||||
| 103 | def __truediv__(self, other): | 103 | def __truediv__(self, other): | ||
| 104 | if self.used: | 104 | if self.used: | ||
| 105 | raise TypeError('Potion is now part of something bigger than itself.') | 105 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 106 | 106 | ||||
| 107 | if not isinstance(other, int): | 107 | if not isinstance(other, int): | ||
| 108 | raise TypeError('Cannot divide non potion object.') | 108 | raise TypeError('Cannot divide non potion object.') | ||
| 109 | 109 | ||||
| 110 | new_potion = self.__copy__() | 110 | new_potion = self.__copy__() | ||
| 111 | for key in new_potion.effects_intensity.keys(): | 111 | for key in new_potion.effects_intensity.keys(): | ||
| 112 | self.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] / other) | 112 | self.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] / other) | ||
| 113 | 113 | ||||
| 114 | self.used = True | 114 | self.used = True | ||
| 115 | 115 | ||||
| 116 | return (new_potion,) * other | 116 | return (new_potion,) * other | ||
| 117 | 117 | ||||
| 118 | def __eq__(self, other): | 118 | def __eq__(self, other): | ||
| 119 | if self.used or other.used: | 119 | if self.used or other.used: | ||
| 120 | raise TypeError('Potion is now part of something bigger than itself.') | 120 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 121 | 121 | ||||
| 122 | if not isinstance(other, Potion): | 122 | if not isinstance(other, Potion): | ||
| 123 | raise TypeError('Cannot compare non potion object.') | 123 | raise TypeError('Cannot compare non potion object.') | ||
| 124 | 124 | ||||
| 125 | return self.effects == other.effects and self.effects_intensity == other.effects_intensity | 125 | return self.effects == other.effects and self.effects_intensity == other.effects_intensity | ||
| 126 | 126 | ||||
| 127 | def __lt__(self, other): | 127 | def __lt__(self, other): | ||
| 128 | if self.used or other.used: | 128 | if self.used or other.used: | ||
| 129 | raise TypeError('Potion is now part of something bigger than itself.') | 129 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 130 | 130 | ||||
| 131 | if not isinstance(other, Potion): | 131 | if not isinstance(other, Potion): | ||
| 132 | raise TypeError('Cannot compare non potion object.') | 132 | raise TypeError('Cannot compare non potion object.') | ||
| 133 | 133 | ||||
| 134 | lhs_sum = sum(self.effects_intensity.values()) | 134 | lhs_sum = sum(self.effects_intensity.values()) | ||
| 135 | rhs_sum = sum(other.effects_intensity.values()) | 135 | rhs_sum = sum(other.effects_intensity.values()) | ||
| 136 | 136 | ||||
| 137 | return lhs_sum < rhs_sum | 137 | return lhs_sum < rhs_sum | ||
| 138 | 138 | ||||
| 139 | def __gt__(self, other): | 139 | def __gt__(self, other): | ||
| 140 | if self.used or other.used: | 140 | if self.used or other.used: | ||
| 141 | raise TypeError('Potion is now part of something bigger than itself.') | 141 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 142 | 142 | ||||
| 143 | if not isinstance(other, Potion): | 143 | if not isinstance(other, Potion): | ||
| 144 | raise TypeError('Cannot compare non potion object.') | 144 | raise TypeError('Cannot compare non potion object.') | ||
| 145 | 145 | ||||
| 146 | lhs_sum = sum(self.effects_intensity.values()) | 146 | lhs_sum = sum(self.effects_intensity.values()) | ||
| 147 | rhs_sum = sum(other.effects_intensity.values()) | 147 | rhs_sum = sum(other.effects_intensity.values()) | ||
| 148 | 148 | ||||
| 149 | return lhs_sum > rhs_sum | 149 | return lhs_sum > rhs_sum | ||
| 150 | 150 | ||||
| 151 | 151 | ||||
| 152 | class ГоспожатаПоХимия: | 152 | class ГоспожатаПоХимия: | ||
| 153 | def __init__(self): | 153 | def __init__(self): | ||
| 154 | self.ticks = 0 | 154 | self.ticks = 0 | ||
| 155 | self.applied_effects = [] | 155 | self.applied_effects = [] | ||
| 156 | self.used_potions = [] | 156 | self.used_potions = [] | ||
| 157 | 157 | ||||
| 158 | def apply(self, target, potion): | 158 | def apply(self, target, potion): | ||
| 159 | def get_moll_mass(name): | 159 | def get_moll_mass(name): | ||
| 160 | result = 0 | 160 | result = 0 | ||
| 161 | for symbol in name: | 161 | for symbol in name: | ||
| 162 | result += ord(symbol) | 162 | result += ord(symbol) | ||
| 163 | return result | 163 | return result | ||
| 164 | 164 | ||||
| 165 | if potion in self.used_potions: | 165 | if potion in self.used_potions: | ||
| 166 | raise TypeError('Potion is depleted.') | 166 | raise TypeError('Potion is depleted.') | ||
| 167 | 167 | ||||
| 168 | self.used_potions.append(potion) | 168 | self.used_potions.append(potion) | ||
| 169 | 169 | ||||
| 170 | if potion.duration == 0: | 170 | if potion.duration == 0: | ||
| 171 | return | 171 | return | ||
| 172 | 172 | ||||
| 173 | effect_names = list(potion.effects.keys()) | 173 | effect_names = list(potion.effects.keys()) | ||
| 174 | effect_names.sort(key=lambda x: get_moll_mass(x), reverse=True) | 174 | effect_names.sort(key=lambda x: get_moll_mass(x), reverse=True) | ||
| 175 | 175 | ||||
| 176 | for key in effect_names: | 176 | for key in effect_names: | ||
| 177 | try: | 177 | try: | ||
| n | 178 | state = {(attr, val) for attr, val in target.__dict__.items() if not attr.startswith('__')} | n | 178 | state = {attr: val for attr, val in target.__dict__.items() if not attr.startswith('__')} |
| 179 | potion.__getattr__(key)(target) | 179 | potion.__getattr__(key)(target) | ||
| 180 | for attr in dir(target): | 180 | for attr in dir(target): | ||
| 181 | if attr.startswith('__'): | 181 | if attr.startswith('__'): | ||
| 182 | continue | 182 | continue | ||
| 183 | state[attr] = getattr(target, attr) - state[attr] | 183 | state[attr] = getattr(target, attr) - state[attr] | ||
| 184 | self.applied_effects.append( | 184 | self.applied_effects.append( | ||
| 185 | (potion.duration, self.ticks, target, state)) | 185 | (potion.duration, self.ticks, target, state)) | ||
| 186 | except TypeError: | 186 | except TypeError: | ||
| 187 | raise TypeError('Potion is depleted.') | 187 | raise TypeError('Potion is depleted.') | ||
| 188 | 188 | ||||
| 189 | def tick(self): | 189 | def tick(self): | ||
| 190 | self.ticks += 1 | 190 | self.ticks += 1 | ||
| 191 | 191 | ||||
| 192 | self.applied_effects.sort(key=lambda x: x[0]) | 192 | self.applied_effects.sort(key=lambda x: x[0]) | ||
| 193 | for (duration, ticks_atm, target, obj_before) in self.applied_effects: | 193 | for (duration, ticks_atm, target, obj_before) in self.applied_effects: | ||
| 194 | if self.ticks == ticks_atm + duration: | 194 | if self.ticks == ticks_atm + duration: | ||
| t | 195 | for attr, val in obj_before: | t | 195 | for attr, val in obj_before.items(): |
| 196 | cur_value = getattr(target, attr) | ||||
| 196 | setattr(target, attr, val * -1) | 197 | setattr(target, attr, cur_value - val) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| n | 1 | from copy import deepcopy | n | 1 | from copy import deepcopy, copy |
| 2 | 2 | ||||
| 3 | 3 | ||||
| 4 | class Potion: | 4 | class Potion: | ||
| 5 | @staticmethod | 5 | @staticmethod | ||
| 6 | def custom_round(number): | 6 | def custom_round(number): | ||
| n | 7 | if number - int(number) >= 0.5: | n | 7 | if number - int(number) > 0.5: |
| 8 | return int(number) + 1 | 8 | return int(number) + 1 | ||
| 9 | return int(number) | 9 | return int(number) | ||
| 10 | 10 | ||||
| 11 | def __init__(self, effects, duration): | 11 | def __init__(self, effects, duration): | ||
| 12 | self.effects = effects | 12 | self.effects = effects | ||
| 13 | self.used_effects = [] | 13 | self.used_effects = [] | ||
| 14 | self.effects_intensity = {key: 1 for key in effects.keys()} | 14 | self.effects_intensity = {key: 1 for key in effects.keys()} | ||
| 15 | self.duration = duration | 15 | self.duration = duration | ||
| 16 | self.used = False | 16 | self.used = False | ||
| 17 | 17 | ||||
| 18 | def __getattr__(self, item): | 18 | def __getattr__(self, item): | ||
| n | n | 19 | def decorator(func): | ||
| 20 | def wrapper(target): | ||||
| 21 | for _ in range(self.effects_intensity[list(self.effects.keys())[list(self.effects.values()).index(func)]]): | ||||
| 22 | func(target) | ||||
| 23 | return wrapper | ||||
| 24 | |||||
| 19 | if self.used: | 25 | if self.used: | ||
| 20 | raise TypeError('Potion is now part of something bigger than itself.') | 26 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 21 | 27 | ||||
| 22 | if item in self.effects.keys(): | 28 | if item in self.effects.keys(): | ||
| 23 | if item in self.used_effects: | 29 | if item in self.used_effects: | ||
| 24 | raise TypeError('Effect is depleted.') | 30 | raise TypeError('Effect is depleted.') | ||
| 25 | self.used_effects.append(item) | 31 | self.used_effects.append(item) | ||
| n | 26 | return self.effects[item] | n | 32 | return decorator(self.effects[item]) |
| 27 | else: | 33 | else: | ||
| n | 28 | raise TypeError('Effect not found.') | n | 34 | raise AttributeError('Effect not found.') |
| 35 | |||||
| 36 | def __copy__(self): | ||||
| 37 | new_potion = Potion({}, 0) | ||||
| 38 | new_potion.effects = self.effects.copy() | ||||
| 39 | new_potion.used_effects = self.used_effects.copy() | ||||
| 40 | new_potion.effects_intensity = self.effects_intensity.copy() | ||||
| 41 | new_potion.duration = self.duration | ||||
| 42 | new_potion.used = self.used | ||||
| 43 | return new_potion | ||||
| 29 | 44 | ||||
| 30 | def __add__(self, other): | 45 | def __add__(self, other): | ||
| 31 | if self.used or other.used: | 46 | if self.used or other.used: | ||
| 32 | raise TypeError('Potion is now part of something bigger than itself.') | 47 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 33 | 48 | ||||
| n | 34 | merged_effects = {} | n | 49 | new_potion = self.__copy__() |
| 35 | effects_intensity = {} | ||||
| 36 | 50 | ||||
| n | 37 | for (key, value) in self.effects.items(): | n | ||
| 38 | merged_effects[key] = value | ||||
| 39 | for (key, value) in other.effects.items(): | 51 | for key in other.effects.keys(): | ||
| 40 | if key in merged_effects: | 52 | if key in new_potion.effects_intensity.keys(): | ||
| 41 | effects_intensity[key] += 1 | 53 | new_potion.effects_intensity[key] += other.effects_intensity[key] | ||
| 42 | else: | 54 | else: | ||
| n | 43 | merged_effects[key] = value | n | 55 | new_potion.effects[key] = other.effects[key] |
| 44 | |||||
| 45 | new_potion = Potion(effects=merged_effects, duration=max(self.duration, other.duration)) | ||||
| 46 | new_potion.effects_intensity = effects_intensity.copy() | 56 | new_potion.effects_intensity[key] = other.effects_intensity[key] | ||
| 47 | 57 | ||||
| 48 | self.used = True | 58 | self.used = True | ||
| 49 | other.used = True | 59 | other.used = True | ||
| 50 | 60 | ||||
| 51 | return new_potion | 61 | return new_potion | ||
| 52 | 62 | ||||
| 53 | def __mul__(self, num): | 63 | def __mul__(self, num): | ||
| n | 54 | if self.used or other.used: | n | 64 | if self.used: |
| 55 | raise TypeError('Potion is now part of something bigger than itself.') | 65 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 56 | 66 | ||||
| 57 | if num < 0: | 67 | if num < 0: | ||
| 58 | raise ValueError('Multiplier must be non negative.') | 68 | raise ValueError('Multiplier must be non negative.') | ||
| 59 | 69 | ||||
| n | 60 | new_potion = Potion(effects=self.effects, duration=self.duration) | n | 70 | new_potion = self.__copy__() |
| 61 | for key in new_potion.effects_intensity.keys(): | 71 | for key in new_potion.effects_intensity.keys(): | ||
| n | 62 | if not isinstance(value, int) and 0 < num < 1: | n | 72 | if 0 < num < 1: |
| 63 | new_potion.effects_intensity[key] = custom_round(new_potion.effects_intensity[key] * num) | 73 | new_potion.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] * num) | ||
| 64 | else: | 74 | else: | ||
| n | 65 | raise TypeError('Cannot dissolve with number not between 0 and 1.') | n | ||
| 66 | new_potion.effects_intensity[key] *= num | 75 | new_potion.effects_intensity[key] *= num | ||
| 67 | 76 | ||||
| 68 | self.used = True | 77 | self.used = True | ||
| n | 69 | other.used = True | n | ||
| 70 | 78 | ||||
| 71 | return new_potion | 79 | return new_potion | ||
| 72 | 80 | ||||
| 73 | def __sub__(self, other): | 81 | def __sub__(self, other): | ||
| 74 | if self.used or other.used: | 82 | if self.used or other.used: | ||
| 75 | raise TypeError('Potion is now part of something bigger than itself.') | 83 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 76 | 84 | ||||
| 77 | if not isinstance(other, Potion): | 85 | if not isinstance(other, Potion): | ||
| 78 | raise TypeError('Cannot subtract non potion object.') | 86 | raise TypeError('Cannot subtract non potion object.') | ||
| 79 | 87 | ||||
| n | 80 | new_potion = Potion(effects=self.effects, duration=self.duration) | n | 88 | new_potion = self.__copy__() |
| 81 | for key in other.effects.keys(): | 89 | for key in other.effects.keys(): | ||
| n | 82 | if key not in new_potion.effects.items(): | n | 90 | if key not in self.effects.keys(): |
| 83 | raise TypeError('Cannot subtract potion with different effects.') | 91 | raise TypeError('Cannot subtract potion with different effects.') | ||
| n | 84 | if new_potion.effects_intensity[key] - other.effects_intensity[key] < 0: | n | 92 | if new_potion.effects_intensity[key] - other.effects_intensity[key] <= 0: |
| 85 | del new_potion.effects[key] | 93 | del new_potion.effects[key] | ||
| n | n | 94 | del new_potion.effects_intensity[key] | ||
| 86 | else: | 95 | else: | ||
| 87 | new_potion.effects_intensity[key] -= other.effects_intensity[key] | 96 | new_potion.effects_intensity[key] -= other.effects_intensity[key] | ||
| 88 | 97 | ||||
| 89 | self.used = True | 98 | self.used = True | ||
| 90 | other.used = True | 99 | other.used = True | ||
| 91 | 100 | ||||
| 92 | return new_potion | 101 | return new_potion | ||
| 93 | 102 | ||||
| 94 | def __truediv__(self, other): | 103 | def __truediv__(self, other): | ||
| n | 95 | if self.used or other.used: | n | 104 | if self.used: |
| 96 | raise TypeError('Potion is now part of something bigger than itself.') | 105 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 97 | 106 | ||||
| 98 | if not isinstance(other, int): | 107 | if not isinstance(other, int): | ||
| 99 | raise TypeError('Cannot divide non potion object.') | 108 | raise TypeError('Cannot divide non potion object.') | ||
| 100 | 109 | ||||
| n | 101 | new_potion = Potion(effects=self.effects, duration=self.duration) | n | 110 | new_potion = self.__copy__() |
| 102 | for key in new_potion.effects_intensity.keys(): | 111 | for key in new_potion.effects_intensity.keys(): | ||
| n | 103 | effects_intensity[key] = custom_round(new_potion.effects_intensity[key] / other) | n | 112 | self.effects_intensity[key] = Potion.custom_round(new_potion.effects_intensity[key] / other) |
| 104 | 113 | ||||
| 105 | self.used = True | 114 | self.used = True | ||
| n | 106 | other.used = True | n | ||
| 107 | 115 | ||||
| 108 | return (new_potion,) * other | 116 | return (new_potion,) * other | ||
| 109 | 117 | ||||
| 110 | def __eq__(self, other): | 118 | def __eq__(self, other): | ||
| 111 | if self.used or other.used: | 119 | if self.used or other.used: | ||
| 112 | raise TypeError('Potion is now part of something bigger than itself.') | 120 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 113 | 121 | ||||
| 114 | if not isinstance(other, Potion): | 122 | if not isinstance(other, Potion): | ||
| 115 | raise TypeError('Cannot compare non potion object.') | 123 | raise TypeError('Cannot compare non potion object.') | ||
| 116 | 124 | ||||
| 117 | return self.effects == other.effects and self.effects_intensity == other.effects_intensity | 125 | return self.effects == other.effects and self.effects_intensity == other.effects_intensity | ||
| 118 | 126 | ||||
| 119 | def __lt__(self, other): | 127 | def __lt__(self, other): | ||
| 120 | if self.used or other.used: | 128 | if self.used or other.used: | ||
| 121 | raise TypeError('Potion is now part of something bigger than itself.') | 129 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 122 | 130 | ||||
| 123 | if not isinstance(other, Potion): | 131 | if not isinstance(other, Potion): | ||
| 124 | raise TypeError('Cannot compare non potion object.') | 132 | raise TypeError('Cannot compare non potion object.') | ||
| 125 | 133 | ||||
| 126 | lhs_sum = sum(self.effects_intensity.values()) | 134 | lhs_sum = sum(self.effects_intensity.values()) | ||
| 127 | rhs_sum = sum(other.effects_intensity.values()) | 135 | rhs_sum = sum(other.effects_intensity.values()) | ||
| 128 | 136 | ||||
| 129 | return lhs_sum < rhs_sum | 137 | return lhs_sum < rhs_sum | ||
| 130 | 138 | ||||
| 131 | def __gt__(self, other): | 139 | def __gt__(self, other): | ||
| 132 | if self.used or other.used: | 140 | if self.used or other.used: | ||
| 133 | raise TypeError('Potion is now part of something bigger than itself.') | 141 | raise TypeError('Potion is now part of something bigger than itself.') | ||
| 134 | 142 | ||||
| 135 | if not isinstance(other, Potion): | 143 | if not isinstance(other, Potion): | ||
| 136 | raise TypeError('Cannot compare non potion object.') | 144 | raise TypeError('Cannot compare non potion object.') | ||
| 137 | 145 | ||||
| 138 | lhs_sum = sum(self.effects_intensity.values()) | 146 | lhs_sum = sum(self.effects_intensity.values()) | ||
| 139 | rhs_sum = sum(other.effects_intensity.values()) | 147 | rhs_sum = sum(other.effects_intensity.values()) | ||
| 140 | 148 | ||||
| 141 | return lhs_sum > rhs_sum | 149 | return lhs_sum > rhs_sum | ||
| 142 | 150 | ||||
| 143 | 151 | ||||
| 144 | class ГоспожатаПоХимия: | 152 | class ГоспожатаПоХимия: | ||
| 145 | def __init__(self): | 153 | def __init__(self): | ||
| 146 | self.ticks = 0 | 154 | self.ticks = 0 | ||
| 147 | self.applied_effects = [] | 155 | self.applied_effects = [] | ||
| 148 | self.used_potions = [] | 156 | self.used_potions = [] | ||
| 149 | 157 | ||||
| 150 | def apply(self, target, potion): | 158 | def apply(self, target, potion): | ||
| 151 | def get_moll_mass(name): | 159 | def get_moll_mass(name): | ||
| 152 | result = 0 | 160 | result = 0 | ||
| 153 | for symbol in name: | 161 | for symbol in name: | ||
| 154 | result += ord(symbol) | 162 | result += ord(symbol) | ||
| 155 | return result | 163 | return result | ||
| 156 | 164 | ||||
| 157 | if potion in self.used_potions: | 165 | if potion in self.used_potions: | ||
| 158 | raise TypeError('Potion is depleted.') | 166 | raise TypeError('Potion is depleted.') | ||
| 159 | 167 | ||||
| n | n | 168 | self.used_potions.append(potion) | ||
| 169 | |||||
| 170 | if potion.duration == 0: | ||||
| 171 | return | ||||
| 172 | |||||
| 160 | effect_names = list(potion.effects.keys()) | 173 | effect_names = list(potion.effects.keys()) | ||
| 161 | effect_names.sort(key=lambda x: get_moll_mass(x), reverse=True) | 174 | effect_names.sort(key=lambda x: get_moll_mass(x), reverse=True) | ||
| 162 | 175 | ||||
| 163 | for key in effect_names: | 176 | for key in effect_names: | ||
| n | 164 | for _ in range(potion.effects_intensity[key]): | n | ||
| 165 | try: | 177 | try: | ||
| 166 | obj_before = deepcopy(target) | 178 | state = {(attr, val) for attr, val in target.__dict__.items() if not attr.startswith('__')} | ||
| 167 | potion.__getattr__(key)(target) | 179 | potion.__getattr__(key)(target) | ||
| 180 | for attr in dir(target): | ||||
| 181 | if attr.startswith('__'): | ||||
| 182 | continue | ||||
| 183 | state[attr] = getattr(target, attr) - state[attr] | ||||
| 168 | self.applied_effects.append( | 184 | self.applied_effects.append( | ||
| 169 | (potion.duration, target, obj_before.__dict__.copy())) | 185 | (potion.duration, self.ticks, target, state)) | ||
| 170 | except TypeError: | 186 | except TypeError: | ||
| 171 | pass | 187 | raise TypeError('Potion is depleted.') | ||
| 172 | |||||
| 173 | self.used_potions.append(potion) | ||||
| 174 | 188 | ||||
| 175 | def tick(self): | 189 | def tick(self): | ||
| 176 | self.ticks += 1 | 190 | self.ticks += 1 | ||
| 177 | 191 | ||||
| t | t | 192 | self.applied_effects.sort(key=lambda x: x[0]) | ||
| 178 | for (duration, target, obj_before) in self.applied_effects: | 193 | for (duration, ticks_atm, target, obj_before) in self.applied_effects: | ||
| 179 | if duration == self.ticks: | 194 | if self.ticks == ticks_atm + duration: | ||
| 180 | target.__dict__ = obj_before.copy() | 195 | for attr, val in obj_before: | ||
| 196 | setattr(target, attr, val * -1) |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
08.12.2023 14:36
08.12.2023 14:37