1import math
2
3def normal_round(n):
4 if n - math.floor(n) <= 0.5:
5 return math.floor(n)
6 return math.ceil(n)
7
8class Potion:
9
10 def __init__(self, effects: dict, duration: int):
11 self.effects = effects
12 self.potency = dict.fromkeys(effects, 1)
13 self.duration = duration
14 self.active_effects = set(effects.keys())
15 self.is_used = False
16
17 def __eq__(self, other) -> bool:
18 return self.effects.keys() == other.effects.keys() and self.potency == other.potency
19
20 def __gt__(self, other) -> bool:
21 itensity_first = 0
22 itensity_second = 0
23 for effect in self.potency:
24 itensity_first += self.potency[effect]
25 for effect in other.potency:
26 itensity_second += other.potency[effect]
27
28 return itensity_first > itensity_second
29
30 def __lt__(self, other) -> bool:
31 itensity_first = 0
32 itensity_second = 0
33 for effect in self.potency:
34 itensity_first += self.potency[effect]
35 for effect in other.potency:
36 itensity_second += other.potency[effect]
37
38 return itensity_first < itensity_second
39
40 def __add__(self, other):
41 if self.is_used or other.is_used:
42 raise TypeError("Potion is now part of something bigger than itself.")
43
44 combined_potion = Potion(self.effects, self.duration)
45 combined_potion.potency = self.potency
46 combined_potion.active_effects = self.active_effects
47 for effect in other.effects:
48 if effect in combined_potion.effects:
49 combined_potion.potency[effect] += other.potency[effect]
50 else:
51 combined_potion.effects[effect] = other.effects[effect]
52 combined_potion.potency[effect] = other.potency[effect]
53 combined_potion.active_effects.add(effect)
54 combined_potion.duration = max(combined_potion.duration, other.duration)
55
56 self.is_used = True
57 other.is_used = True
58 return combined_potion
59
60 def __sub__(self, other):
61 if self.is_used or other.is_used:
62 raise TypeError("Potion is now part of something bigger than itself.")
63
64 diluted_potion = Potion(self.effects, self.duration)
65 diluted_potion.potency = self.potency
66 diluted_potion.active_effects = self.active_effects
67 try:
68 for effect in other.effects:
69 diluted_potion.potency[effect] -= other.potency[effect]
70 if diluted_potion.potency[effect] <= 0:
71 diluted_potion.effects.pop(effect)
72 diluted_potion.potency.pop(effect)
73 diluted_potion.active_effects.remove(effect)
74 self.is_used = True
75 other.is_used = True
76 return diluted_potion
77 except:
78 raise TypeError("Potion cannot be diluted")
79
80 def __mul__(self, value):
81 if self.is_used:
82 raise TypeError("Potion is now part of something bigger than itself.")
83
84 new_potion = Potion(self.effects, self.duration)
85 new_potion.potency = self.potency
86 new_potion.active_effects = self.active_effects
87 if value < 1:
88 for effect in new_potion.potency:
89 new_potion.potency[effect] = int(normal_round(new_potion.potency[effect] * value))
90 else:
91 for effect in new_potion.potency:
92 new_potion.potency[effect] *= value
93
94 self.is_used = True
95 return new_potion
96
97 def __truediv__(self, value):
98 if self.is_used:
99 raise TypeError("Potion is now part of something bigger than itself.")
100
101 new_potion = Potion(self.effects, self.duration)
102 new_potion.potency = self.potency
103 new_potion.active_effects = self.active_effects
104
105 for effect in new_potion.potency:
106 new_potion.potency[effect] = int(normal_round(new_potion.potency[effect] / value))
107
108 self.is_used = True
109
110 potions = []
111 for _ in range(0, value):
112 copy_potion = Potion(new_potion.effects, new_potion.duration)
113 copy_potion.potency = new_potion.potency.copy()
114 copy_potion.active_effects = new_potion.active_effects.copy()
115 potions.append(copy_potion)
116
117 return tuple(potions)
118
119 def __getattr__(self, effect):
120 try:
121 self.active_effects.remove(effect)
122 return self.apply_potency(effect)
123 except:
124 raise TypeError("Effect is depleted.")
125
126 def apply_potency(self, effect):
127 def apply_effect(target):
128 for _ in range(self.potency[effect]):
129 self.effects[effect](target)
130 return apply_effect
131
132
133class ГоспожатаПоХимия:
134
135 def apply(self, target, potion: Potion):
136 if potion.is_used or not potion.active_effects:
137 raise TypeError("Potion is depleted.")
138
139 sorted_effects = sorted(list(potion.active_effects),
140 key = lambda effect : sum(ord(ch) for ch in effect), reverse=True)
141 for effect in sorted_effects:
142 potion.__getattr__(effect)(target)
143
144 potion.is_used = True
145
146 def tick(self):
147 pass
.......F..E.F...FFFF
======================================================================
ERROR: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 121, in __getattr__
self.active_effects.remove(effect)
KeyError: 'int_attr_fun'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 169, in test_purification
potion.int_attr_fun(self._target)
File "/tmp/solution.py", line 124, in __getattr__
raise TypeError("Effect is depleted.")
TypeError: Effect is depleted.
======================================================================
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
======================================================================
FAIL: test_applying_depleted_potion (test.TestГоспожатаПоХимия)
Test applying a depleted potion or a potion that was used in a reaction.
----------------------------------------------------------------------
TypeError: Potion is now part of something bigger than itself.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 382, in test_applying_depleted_potion
with self.assertRaisesRegex(TypeError, 'Potion is depleted\.'):
AssertionError: "Potion is depleted\." does not match "Potion is now part of something bigger than itself."
======================================================================
FAIL: test_ticking_immutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with immutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 429, in test_ticking_immutable
self.assertEqual(self._target.int_attr, 5)
AssertionError: 500 != 5
======================================================================
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: 500 != 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 490, in test_ticking_multiple_targets
self.assertEqual(target1.int_attr, 5)
AssertionError: 500 != 5
======================================================================
FAIL: test_ticking_mutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 444, in test_ticking_mutable
self.assertEqual(self._target.int_attr, 5)
AssertionError: 50 != 5
----------------------------------------------------------------------
Ran 20 tests in 0.002s
FAILED (failures=6, errors=1)
Виктор Бечев
08.12.2023 13:56Отвъд прекалено за моя вкус либералната употреба на нови редове - добре структуриран и четим код, браво.
|
08.12.2023 13:55
08.12.2023 14:32