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