1from functools import reduce
2from copy import copy, deepcopy
3
4class Potion:
5 def __init__(self, effects: dict, duration: int):
6 self.effects = effects
7 self.duration = duration
8 self.used_effects = set()
9 self.intensity = dict.fromkeys(effects, 1)
10 self.used_in_the_bigger_picture = False
11 self.applied = False
12
13 def __getattr__(self, attr):
14
15 if attr in self.effects:
16 if attr in self.used_effects:
17 raise TypeError("Effect is depleted.")
18 else:
19 self.used_effects.add(attr)
20 intensity = self.intensity[attr]
21 self.intensity[attr] = 0
22 return self.apply_intensity(self.effects[attr], intensity)
23 else:
24 raise AttributeError("Effect not found.")
25
26 def apply_intensity(self, effect, intensity):
27 def potion_effect(target):
28 for _ in range(intensity):
29 effect(target)
30 return potion_effect
31
32
33 def copy(self):
34 new = Potion(deepcopy(self.effects), self.duration)
35 new.intensity = deepcopy(self.intensity)
36 new.used_in_the_bigger_picture = False
37 new.used_effects = deepcopy(self.used_effect)
38 return new
39
40 def __mul__(self, number):
41 if self.used_in_the_bigger_picture:
42 raise TypeError("Potion is now part of something bigger than itself.")
43 self.used_in_the_bigger_picture = True
44
45
46 if number > 1:
47 self._potenciirane(number)
48 elif number > 0 and number < 1:
49 self._razrejdane(number)
50
51 return self.copy()
52
53 def _potenciirane(self, times):
54
55 for effect in self.effects:
56 self.intensity[effect] *= times
57 return self
58
59 def _razrejdane(self, percent):
60 for effect in self.effects:
61 self.intensity[effect] = int(self.intensity[effect] * percent) + 1 * (self.intensity[effect] * percent - int(self.intensity[effect] * percent) > 0.5)
62 return self.copy()
63
64 def __add__(self, other_potion):
65 if self.used_in_the_bigger_picture or other_potion.used_in_the_bigger_picture:
66 raise TypeError("Potion is now part of something bigger than itself.")
67 self.used_in_the_bigger_picture = True
68 other_potion.used_in_the_bigger_picture = True
69
70 if self.applied or self.applied:
71 raise TypeError("Potion is depleted.")
72
73 self.duration = max(self.duration, other_potion.duration)
74 self.used_effect = self.used_effects.union(other_potion.used_effects)
75
76 for other_potion_effect in other_potion.effects:
77 if other_potion_effect in self.effects:
78 self.intensity[other_potion_effect] += other_potion.intensity[other_potion_effect]
79 else:
80 self.effects[other_potion_effect] = other_potion.effects[other_potion_effect]
81 self.intensity[other_potion_effect] = other_potion.intensity[other_potion_effect]
82
83 return self.copy()
84
85 def __sub__(self, other_potion):
86 if self.used_in_the_bigger_picture or other_potion.used_in_the_bigger_picture:
87 raise TypeError("Potion is now part of something bigger than itself.")
88 self.used_in_the_bigger_picture = True
89 other_potion.used_in_the_bigger_picture = True
90
91 if self.applied or self.applied:
92 raise TypeError("Potion is depleted.")
93
94 effects_to_remove = set()
95 for effect_name in other_potion.effects:
96 if effect_name not in self.effects:
97 raise TypeError("No potion effect as the left potion.")
98 if self.intensity[effect_name] >= other_potion.intensity[effect_name]:
99 self.intensity[effect_name] = max(self.intensity[effect_name] - other_potion.intensity[effect_name], 0)
100 if self.intensity[effect_name] == 0:
101 effects_to_remove.add(effect_name)
102
103 for effect_name in effects_to_remove:
104 self.effects.pop(effect_name)
105 self.intensity.pop(effect_name)
106
107 self.duration = other_potion.duration
108 return self.copy()
109
110 def __truediv__(self, divisor):
111
112 if self.used_in_the_bigger_picture:
113 raise TypeError("Potion is now part of something bigger than itself.")
114 self.used_in_the_bigger_picture = True
115
116 for effect in self.intensity:
117 self.intensity[effect] = round(self.intensity[effect] / divisor)
118
119 resulting_pots = []
120 for _ in range(divisor):
121 resulting_pots.append(self.copy())
122
123 return resulting_pots
124
125 def __eq__(self, other):
126 if not set(self.effects.keys()) == set(other.effects.keys()):
127 return False
128
129 for effect in self.intensity:
130 if self.intensity[effect] != other.intensity[effect]:
131 return False
132
133 return True
134
135 def __lt__(self, other):
136 return other > self
137
138 def __gt__(self, other):
139
140 total_intensity = 0
141 for effect in self.intensity:
142 total_intensity += self.intensity[effect]
143
144 for effect in other.intensity:
145 total_intensity -= other.intensity[effect]
146
147 return total_intensity > 0
148
149
150
151class ГоспожатаПоХимия:
152
153 def __init__(self):
154 self.targets = []
155 self.app_potions = {}
156
157 def apply(self, target, potion):
158 self.targets.append(target)
159 # self.app_potions[]
160
161 if potion.used_in_the_bigger_picture:
162 raise TypeError("Potion is now part of something bigger than itself.")
163
164 if potion.applied or len(potion.used_effects) == len(potion.effects.keys()):
165 raise TypeError("Potion is depleted.")
166 potion.applied = True
167
168 list_order = []
169 dict_order = {}
170
171 for effect in potion.effects:
172 list_order.append(sum(map(ord, effect)))
173 dict_order[sum(map(ord, effect))] = effect
174
175 list_order.sort()
176 list_order = list_order[::-1]
177
178 for order in list_order:
179 try:
180 potion.__getattr__(dict_order[order])(target)
181 except TypeError:
182 continue
183
184 def tick(self):
185 for target in self.targets:
186 target.duration = max(0, target.duration - 1)
...EE..FEEEEE.E.EEEE
======================================================================
ERROR: test_equal (test.TestPotionComparison)
Test equality of potions.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 296, in test_equal
potion3 = Potion({'int_attr_fun': int_attr_fun}, duration=1) * 2
File "/tmp/solution.py", line 51, in __mul__
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
ERROR: test_superbness (test.TestPotionComparison)
Test superbness of potions.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 316, in test_superbness
potion2 = Potion({'int_attr_fun': int_attr_fun}, duration=1) * 2
File "/tmp/solution.py", line 51, in __mul__
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
ERROR: test_dilution (test.TestPotionOperations)
Test dilution of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 118, in test_dilution
half_potion = base_potion * 0.5
File "/tmp/solution.py", line 49, in __mul__
self._razrejdane(number)
File "/tmp/solution.py", line 62, in _razrejdane
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
ERROR: test_potentiation (test.TestPotionOperations)
Test potentiation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 110, in test_potentiation
potion = potion * 3
File "/tmp/solution.py", line 51, in __mul__
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
ERROR: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 165, in test_purification
potion = potion1 - potion2
File "/tmp/solution.py", line 108, in __sub__
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
ERROR: test_separation (test.TestPotionOperations)
Test separation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 212, in test_separation
potion = Potion({'int_attr_fun': int_attr_fun}, duration=1) * 9
File "/tmp/solution.py", line 51, in __mul__
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
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/test.py", line 383, in test_applying_depleted_potion
potion = potion * 2
File "/tmp/solution.py", line 51, in __mul__
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
ERROR: test_applying_order (test.TestГоспожатаПоХимия)
Test applying order of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 407, in test_applying_order
self._target = copy.deepcopy(self._target)
AttributeError: 'function' object has no attribute 'deepcopy'
======================================================================
ERROR: test_ticking_immutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with immutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 426, in test_ticking_immutable
self._dimitrichka.tick()
File "/tmp/solution.py", line 186, in tick
target.duration = max(0, target.duration - 1)
AttributeError: 'Target' object has no attribute 'duration'
======================================================================
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/test.py", line 457, in test_ticking_multiple_potions
self._dimitrichka.tick()
File "/tmp/solution.py", line 186, in tick
target.duration = max(0, target.duration - 1)
AttributeError: 'Target' object has no attribute 'duration'
======================================================================
ERROR: 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 479, in test_ticking_multiple_targets
potion1 = Potion({'int_attr_fun': int_attr_fun}, duration=1) * 2
File "/tmp/solution.py", line 51, in __mul__
return self.copy()
File "/tmp/solution.py", line 37, in copy
new.used_effects = deepcopy(self.used_effect)
File "/tmp/solution.py", line 24, in __getattr__
raise AttributeError("Effect not found.")
AttributeError: Effect not found.
======================================================================
ERROR: test_ticking_mutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 443, in test_ticking_mutable
self._dimitrichka.tick()
File "/tmp/solution.py", line 186, in tick
target.duration = max(0, target.duration - 1)
AttributeError: 'Target' object has no attribute 'duration'
======================================================================
FAIL: test_deprecation (test.TestPotionOperations)
Test deprecation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 257, in test_deprecation
with self.assertRaisesRegex(TypeError, 'Potion is now part of something bigger than itself\.'):
AssertionError: TypeError not raised
----------------------------------------------------------------------
Ran 20 tests in 0.002s
FAILED (failures=1, errors=12)
Виктор Бечев
06.12.2023 09:22Масово смятам за празните редове за излишни, then again, PEP8 не заема супер стриктна позиция:
```
Extra blank lines may be used (sparingly) to separate groups of related functions. Blank lines may be omitted between a bunch of related one-liners (e.g. a set of dummy implementations).
Use blank lines in functions, sparingly, to indicate logical sections.
```
|
06.12.2023 09:17
06.12.2023 09:17
06.12.2023 09:18
06.12.2023 09:20