1import copy
2
3
4class Potion:
5 @staticmethod
6 def effect_decorator(name, func):
7 def params_holder(self, target):
8 if not name in self.intenzity:
9 raise AttributeError(
10 '\'Potion\' object has no attribute \'' + name + '\'')
11 if self.used:
12 raise TypeError(
13 'Potion is now part of something bigger than itself.')
14 if self.depleted:
15 raise TypeError('Potion is depleted.')
16 if self.intenzity[name] == -1 and not self.inAppliance:
17 raise TypeError('Effect is depleted.')
18 result = None
19 for _ in range(self.intenzity[name]):
20 result = func(target)
21 self.count_effects_executed += 1
22 if self.count_effects_executed == len(self.intenzity):
23 self.depleted = True
24 self.intenzity[name] = -1
25 return result
26 return params_holder
27
28 def __init__(self, effects, duration):
29 self.count_effects_executed = 0
30 self.used = False
31 self.depleted = False
32 self.inAppliance = False
33 self.intenzity = {}
34 self.duration = duration
35
36 for name in effects:
37 self.intenzity[name] = 1
38 if not hasattr(Potion, name):
39 decorated_func = Potion.effect_decorator(name, effects[name])
40 setattr(Potion, name, decorated_func)
41
42 def __add__(self, other_potion):
43 if self.used or other_potion.used:
44 raise TypeError(
45 'Potion is now part of something bigger than itself.')
46 if self.depleted or other_potion.depleted:
47 raise TypeError('Potion is depleted.')
48 new_potion = copy.deepcopy(self)
49 new_potion.duration = max(
50 self.duration, other_potion.duration)
51
52 self.used = True
53 other_potion.used = True
54
55 for name in other_potion.intenzity:
56 if name in new_potion.intenzity:
57 if other_potion.intenzity[name] != -1:
58 new_potion.intenzity[name] = other_potion.intenzity[name]
59 if self.intenzity[name] != -1:
60 new_potion.intenzity[name] += self.intenzity[name]
61 else:
62 new_potion.intenzity[name] = other_potion.intenzity[name]
63 return new_potion
64
65 def __mul__(self, number):
66 if self.used:
67 raise TypeError(
68 'Potion is now part of something bigger than itself.')
69 if self.depleted:
70 raise TypeError('Potion is depleted.')
71 newPotion = copy.deepcopy(self)
72 self.used = True
73 for name in newPotion.intenzity:
74 if newPotion.intenzity[name] != -1:
75 newPotion.intenzity[name] *= number
76 if number < 1:
77 wholePart, decimalPart = divmod(
78 newPotion.intenzity[name], 1)
79 if decimalPart <= 0.5:
80 newPotion.intenzity[name] = int(wholePart)
81 else:
82 newPotion.intenzity[name] = int(wholePart)+1
83 return newPotion
84
85 def __sub__(self, other_potion):
86 if self.used or other_potion.used:
87 raise TypeError(
88 'Potion is now part of something bigger than itself.')
89 if self.depleted or other_potion.depleted:
90 raise TypeError('Potion is depleted.')
91 for name in other_potion.intenzity:
92 if not name in self.intenzity:
93 raise TypeError(
94 'The first potion should have all of the effects of the second one')
95 cleared_potion = copy.deepcopy(self)
96 self.used = True
97 other_potion.used = True
98 for name in other_potion.intenzity:
99 if cleared_potion.intenzity[name] != -1:
100 if cleared_potion.intenzity[name] < other_potion.intenzity[name]:
101 del cleared_potion.intenzity[name]
102 else:
103 cleared_potion.intenzity[name] -= other_potion.intenzity[name]
104 return cleared_potion
105
106 def __truediv__(self, coef):
107 if self.used:
108 raise TypeError(
109 'Potion is now part of something bigger than itself.')
110 if self.depleted:
111 raise TypeError('Potion is depleted.')
112 divided_potion = copy.deepcopy(self)
113 self.used = True
114 for name in divided_potion.intenzity:
115 if divided_potion.intenzity[name] != -1:
116 divided_potion.intenzity[name] /= coef
117 wholePart, decimalPart = divmod(
118 divided_potion.intenzity[name], 1)
119 if decimalPart <= 0.5:
120 divided_potion.intenzity[name] = int(wholePart)
121 else:
122 divided_potion.intenzity[name] = int(wholePart) + 1
123 return (divided_potion,)*coef
124
125 def __eq__(self, other_potion):
126 if not len(self.intenzity) == len(other_potion.intenzity):
127 return False
128 for name in self.intenzity:
129 if not name in other_potion.intenzity:
130 return False
131 if self.intenzity[name] != other_potion.intenzity[name]:
132 return False
133 return True
134
135 def get_sum_potion(self):
136 sum = 0
137 for name in self.intenzity:
138 if self.intenzity[name] != -1:
139 sum += self.intenzity[name]
140 return sum
141
142 def __lt__(self, other_potion):
143 return self.get_sum_potion() < other_potion.get_sum_potion()
144
145 def __gt__(self, other_potion):
146 return self.get_sum_potion() > other_potion.get_sum_potion()
147
148
149class ГоспожатаПоХимия:
150 def __init__(self):
151 self.affected_objects = {}
152 self.duration = 0
153
154 def apply(self, target, potion):
155 if potion.used:
156 raise TypeError(
157 'Potion is now part of something bigger than itself.')
158 if potion.depleted:
159 raise TypeError('Potion is depleted.')
160
161 if potion.duration != 0:
162 object_ref = copy.deepcopy(target)
163 self.affected_objects[object_ref] = (target, potion)
164
165 sorted_intenzity = sorted(potion.intenzity, key=lambda k: sum(
166 map(ord, list(k))), reverse=True)
167
168 for name in sorted_intenzity:
169 getattr(potion, name)(target)
170
171 def tick(self):
172 found = False
173
174 for object in self.affected_objects:
175 self.affected_objects[object][1].duration-=1
176 if self.affected_objects[object][1].duration == 0:
177 self.affected_objects[object][0].__dict__ = object.__dict__
178 found = True
179 break
180 if found:
181 del self.affected_objects[object]
.F........FE...E.FF.
======================================================================
ERROR: test_separation (test.TestPotionOperations)
Test separation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 218, in test_separation
potion2.int_attr_fun(self._target)
File "/tmp/solution.py", line 15, in params_holder
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/test.py", line 365, in test_applying_part_of_potion
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 169, in apply
getattr(potion, name)(target)
File "/tmp/solution.py", line 15, in params_holder
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.
======================================================================
FAIL: test_depletion (test.TestBasicPotion)
Test depletion of a potion effect.
----------------------------------------------------------------------
TypeError: Potion is depleted.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 78, in test_depletion
with self.assertRaisesRegex(TypeError, 'Effect is depleted\.'):
AssertionError: "Effect is depleted\." does not match "Potion is depleted."
======================================================================
FAIL: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 168, in test_purification
with self.assertRaises(AttributeError):
AssertionError: AttributeError not raised
======================================================================
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: 5 != 50
======================================================================
FAIL: test_ticking_multiple_targets (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 494, in test_ticking_multiple_targets
self.assertEqual(target2.int_attr, 5)
AssertionError: 50 != 5
----------------------------------------------------------------------
Ran 20 tests in 0.002s
FAILED (failures=4, errors=2)
05.12.2023 18:28
05.12.2023 18:28
05.12.2023 18:29
05.12.2023 18:30
05.12.2023 18:31