1import math
2import copy
3import re
4
5class Potion:
6 @staticmethod
7 def round_down(n):
8 temp = math.floor(n)
9 if n - temp <= 0.5:
10 return math.floor(n)
11 return math.ceil(n)
12
13 def _wholeness_check(self, func):
14 def check(args):
15 self._validate_not_depleted()
16 self._validate_not_used()
17 return func(args)
18 return check
19
20 def _depleted_check(self, effect, func):
21 def check(args):
22 if effect in self.depleted_effects:
23 if self.depleted_effects[effect]:
24 raise TypeError("Effect is depleted.")
25 self.depleted_effects[effect] = True
26 return func(args)
27 return check
28
29 def _apply_intensity(self, effect, func):
30 def apply(args):
31 if effect in self.intensity:
32 for _ in range(self.intensity[effect]):
33 func(args)
34 return apply
35
36 def _copy(self):
37 copy_potion = Potion({}, self.duration)
38 for effect in self.effects:
39 copy_potion.effects[effect] = self.effects[effect]
40 copy_potion.depleted_effects[effect] = self.depleted_effects[effect]
41 copy_potion.intensity[effect] = self.intensity[effect]
42 setattr(copy_potion, effect, copy_potion._wholeness_check(
43 copy_potion._depleted_check(
44 effect, copy_potion._apply_intensity(
45 effect, copy_potion.effects.get(effect)))))
46 return copy_potion
47
48 def _validate_not_used(self):
49 if self.used:
50 raise TypeError("Potion is now part of something bigger than itself.")
51
52 def _validate_not_depleted(self):
53 if self.depleted:
54 raise TypeError("Potion is depleted.")
55
56 def _increase_potential(self, scale):
57 multiplied_potion = self._copy()
58 for effect in multiplied_potion.intensity:
59 multiplied_potion.intensity[effect] *= scale
60 self.used = True
61 return multiplied_potion
62
63 def _decrease_potential(self, scale):
64 divided_potion = self._copy()
65 for effect in divided_potion.intensity:
66 divided_potion.intensity[effect] = Potion.round_down(
67 divided_potion.intensity[effect] * scale)
68 self.used = True
69 return divided_potion
70
71 def __init__(self, effects, duration):
72 self.used = False
73 self.depleted = False
74 self.effects = effects
75 self.depleted_effects = {}
76 self.intensity = {}
77 for effect in effects:
78 self.depleted_effects[effect] = False
79 self.intensity[effect] = 1
80 setattr(self, effect, self._wholeness_check(
81 self._depleted_check(
82 effect, self._apply_intensity(
83 effect, effects.get(effect)))))
84 self.duration = duration
85
86 def apply(self, target):
87 self._validate_not_depleted()
88 self._validate_not_used()
89 for effect in sorted(self.effects.keys(),
90 key=lambda name: sum(ord(c) for c in name),
91 reverse=True):
92 if not self.depleted_effects[effect]:
93 getattr(self, effect)(target)
94 self.depleted = True
95
96 def __add__(self, other):
97 self._validate_not_depleted()
98 self._validate_not_used()
99 other._validate_not_depleted()
100 other._validate_not_used()
101 compound = self._copy()
102 for effect in other.effects:
103 if effect in compound.effects:
104 compound.intensity[effect] += other.intensity[effect]
105 else:
106 compound.effects[effect] = other.effects[effect]
107 compound.depleted_effects[effect] = other.depleted_effects[effect]
108 compound.intensity[effect] = other.intensity[effect]
109 setattr(compound, effect, compound._wholeness_check(
110 compound._depleted_check(
111 effect, compound._apply_intensity(
112 effect, compound.effects.get(effect)))))
113 self.used = True
114 other.used = True
115 return compound
116
117 def __mul__(self, scale):
118 self._validate_not_depleted()
119 self._validate_not_used()
120 if scale > 1:
121 return self._increase_potential(scale)
122 return self._decrease_potential(scale)
123
124 def __sub__(self, other):
125 self._validate_not_depleted()
126 self._validate_not_used()
127 other._validate_not_depleted()
128 other._validate_not_used()
129 purified_potion = self._copy()
130 for effect in other.effects:
131 if effect in purified_potion.effects:
132 if purified_potion.intensity[effect] > other.intensity[effect]:
133 purified_potion.intensity[effect] -= other.intensity[effect]
134 else:
135 purified_potion.depleted_effects.pop(effect)
136 purified_potion.intensity.pop(effect)
137 purified_potion.effects.pop(effect)
138 delattr(purified_potion, effect)
139 else:
140 raise TypeError("Cannot remove non-existent effect.")
141 self.used = True
142 other.used = True
143 return purified_potion
144
145 def __truediv__(self, scale):
146 self._validate_not_depleted()
147 self._validate_not_used()
148 potions = []
149 for _ in range(scale):
150 potion = self._copy()
151 for effect in potion.intensity:
152 potion.intensity[effect] //= scale
153 potions.append(potion)
154 self.used = True
155 return tuple(potions)
156
157 def __eq__(self, other):
158 return (self.effects == other.effects and self.intensity == other.intensity)
159
160 def __lt__(self, other):
161 return sum(self.intensity.values()) < sum(other.intensity.values())
162
163 def __gt__(self, other):
164 return sum(self.intensity.values()) > sum(other.intensity.values())
165
166
167class ГоспожатаПоХимия:
168 def __init__(self):
169 self.durations = {}
170 self.targets = {}
171 self.effects = {}
172
173 def apply(self, target, potion):
174 old_target = copy.deepcopy(target)
175 potion.apply(target)
176 self.durations[id(potion)] = potion.duration
177 if id(target) not in self.targets:
178 self.targets[id(target)] = old_target
179 self.effects[id(potion)] = [target, self.targets[id(target)]]
180
181 def tick(self):
182 for effect in self.durations:
183 self.durations[effect] -= 1
184 if self.durations[effect] == 0:
185 target, old_target = self.effects[effect]
186 for attrib in target.__dir__():
187 if re.search("^__[A-Za-z_0-9]+__$", attrib):
188 continue
189 setattr(target, attrib, getattr(old_target, attrib))
................FF..
======================================================================
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 427, in test_ticking_immutable
self.assertEqual(self._target.int_attr, 500)
AssertionError: 5 != 500
======================================================================
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
----------------------------------------------------------------------
Ran 20 tests in 0.003s
FAILED (failures=2)
f | 1 | import math | f | 1 | import math |
2 | import copy | 2 | import copy | ||
3 | import re | 3 | import re | ||
4 | 4 | ||||
5 | class Potion: | 5 | class Potion: | ||
6 | @staticmethod | 6 | @staticmethod | ||
7 | def round_down(n): | 7 | def round_down(n): | ||
8 | temp = math.floor(n) | 8 | temp = math.floor(n) | ||
9 | if n - temp <= 0.5: | 9 | if n - temp <= 0.5: | ||
10 | return math.floor(n) | 10 | return math.floor(n) | ||
11 | return math.ceil(n) | 11 | return math.ceil(n) | ||
12 | 12 | ||||
13 | def _wholeness_check(self, func): | 13 | def _wholeness_check(self, func): | ||
14 | def check(args): | 14 | def check(args): | ||
15 | self._validate_not_depleted() | 15 | self._validate_not_depleted() | ||
16 | self._validate_not_used() | 16 | self._validate_not_used() | ||
17 | return func(args) | 17 | return func(args) | ||
18 | return check | 18 | return check | ||
19 | 19 | ||||
20 | def _depleted_check(self, effect, func): | 20 | def _depleted_check(self, effect, func): | ||
21 | def check(args): | 21 | def check(args): | ||
22 | if effect in self.depleted_effects: | 22 | if effect in self.depleted_effects: | ||
23 | if self.depleted_effects[effect]: | 23 | if self.depleted_effects[effect]: | ||
24 | raise TypeError("Effect is depleted.") | 24 | raise TypeError("Effect is depleted.") | ||
25 | self.depleted_effects[effect] = True | 25 | self.depleted_effects[effect] = True | ||
26 | return func(args) | 26 | return func(args) | ||
27 | return check | 27 | return check | ||
28 | 28 | ||||
29 | def _apply_intensity(self, effect, func): | 29 | def _apply_intensity(self, effect, func): | ||
30 | def apply(args): | 30 | def apply(args): | ||
31 | if effect in self.intensity: | 31 | if effect in self.intensity: | ||
32 | for _ in range(self.intensity[effect]): | 32 | for _ in range(self.intensity[effect]): | ||
33 | func(args) | 33 | func(args) | ||
34 | return apply | 34 | return apply | ||
35 | 35 | ||||
36 | def _copy(self): | 36 | def _copy(self): | ||
37 | copy_potion = Potion({}, self.duration) | 37 | copy_potion = Potion({}, self.duration) | ||
38 | for effect in self.effects: | 38 | for effect in self.effects: | ||
39 | copy_potion.effects[effect] = self.effects[effect] | 39 | copy_potion.effects[effect] = self.effects[effect] | ||
40 | copy_potion.depleted_effects[effect] = self.depleted_effects[effect] | 40 | copy_potion.depleted_effects[effect] = self.depleted_effects[effect] | ||
41 | copy_potion.intensity[effect] = self.intensity[effect] | 41 | copy_potion.intensity[effect] = self.intensity[effect] | ||
42 | setattr(copy_potion, effect, copy_potion._wholeness_check( | 42 | setattr(copy_potion, effect, copy_potion._wholeness_check( | ||
43 | copy_potion._depleted_check( | 43 | copy_potion._depleted_check( | ||
44 | effect, copy_potion._apply_intensity( | 44 | effect, copy_potion._apply_intensity( | ||
45 | effect, copy_potion.effects.get(effect))))) | 45 | effect, copy_potion.effects.get(effect))))) | ||
46 | return copy_potion | 46 | return copy_potion | ||
47 | 47 | ||||
48 | def _validate_not_used(self): | 48 | def _validate_not_used(self): | ||
49 | if self.used: | 49 | if self.used: | ||
50 | raise TypeError("Potion is now part of something bigger than itself.") | 50 | raise TypeError("Potion is now part of something bigger than itself.") | ||
51 | 51 | ||||
52 | def _validate_not_depleted(self): | 52 | def _validate_not_depleted(self): | ||
53 | if self.depleted: | 53 | if self.depleted: | ||
54 | raise TypeError("Potion is depleted.") | 54 | raise TypeError("Potion is depleted.") | ||
55 | 55 | ||||
56 | def _increase_potential(self, scale): | 56 | def _increase_potential(self, scale): | ||
57 | multiplied_potion = self._copy() | 57 | multiplied_potion = self._copy() | ||
58 | for effect in multiplied_potion.intensity: | 58 | for effect in multiplied_potion.intensity: | ||
59 | multiplied_potion.intensity[effect] *= scale | 59 | multiplied_potion.intensity[effect] *= scale | ||
60 | self.used = True | 60 | self.used = True | ||
61 | return multiplied_potion | 61 | return multiplied_potion | ||
62 | 62 | ||||
63 | def _decrease_potential(self, scale): | 63 | def _decrease_potential(self, scale): | ||
64 | divided_potion = self._copy() | 64 | divided_potion = self._copy() | ||
65 | for effect in divided_potion.intensity: | 65 | for effect in divided_potion.intensity: | ||
66 | divided_potion.intensity[effect] = Potion.round_down( | 66 | divided_potion.intensity[effect] = Potion.round_down( | ||
67 | divided_potion.intensity[effect] * scale) | 67 | divided_potion.intensity[effect] * scale) | ||
68 | self.used = True | 68 | self.used = True | ||
69 | return divided_potion | 69 | return divided_potion | ||
70 | 70 | ||||
71 | def __init__(self, effects, duration): | 71 | def __init__(self, effects, duration): | ||
72 | self.used = False | 72 | self.used = False | ||
73 | self.depleted = False | 73 | self.depleted = False | ||
74 | self.effects = effects | 74 | self.effects = effects | ||
75 | self.depleted_effects = {} | 75 | self.depleted_effects = {} | ||
76 | self.intensity = {} | 76 | self.intensity = {} | ||
77 | for effect in effects: | 77 | for effect in effects: | ||
78 | self.depleted_effects[effect] = False | 78 | self.depleted_effects[effect] = False | ||
79 | self.intensity[effect] = 1 | 79 | self.intensity[effect] = 1 | ||
80 | setattr(self, effect, self._wholeness_check( | 80 | setattr(self, effect, self._wholeness_check( | ||
81 | self._depleted_check( | 81 | self._depleted_check( | ||
82 | effect, self._apply_intensity( | 82 | effect, self._apply_intensity( | ||
83 | effect, effects.get(effect))))) | 83 | effect, effects.get(effect))))) | ||
84 | self.duration = duration | 84 | self.duration = duration | ||
85 | 85 | ||||
86 | def apply(self, target): | 86 | def apply(self, target): | ||
87 | self._validate_not_depleted() | 87 | self._validate_not_depleted() | ||
88 | self._validate_not_used() | 88 | self._validate_not_used() | ||
89 | for effect in sorted(self.effects.keys(), | 89 | for effect in sorted(self.effects.keys(), | ||
90 | key=lambda name: sum(ord(c) for c in name), | 90 | key=lambda name: sum(ord(c) for c in name), | ||
91 | reverse=True): | 91 | reverse=True): | ||
92 | if not self.depleted_effects[effect]: | 92 | if not self.depleted_effects[effect]: | ||
93 | getattr(self, effect)(target) | 93 | getattr(self, effect)(target) | ||
94 | self.depleted = True | 94 | self.depleted = True | ||
95 | 95 | ||||
96 | def __add__(self, other): | 96 | def __add__(self, other): | ||
97 | self._validate_not_depleted() | 97 | self._validate_not_depleted() | ||
98 | self._validate_not_used() | 98 | self._validate_not_used() | ||
99 | other._validate_not_depleted() | 99 | other._validate_not_depleted() | ||
100 | other._validate_not_used() | 100 | other._validate_not_used() | ||
101 | compound = self._copy() | 101 | compound = self._copy() | ||
102 | for effect in other.effects: | 102 | for effect in other.effects: | ||
103 | if effect in compound.effects: | 103 | if effect in compound.effects: | ||
104 | compound.intensity[effect] += other.intensity[effect] | 104 | compound.intensity[effect] += other.intensity[effect] | ||
105 | else: | 105 | else: | ||
106 | compound.effects[effect] = other.effects[effect] | 106 | compound.effects[effect] = other.effects[effect] | ||
107 | compound.depleted_effects[effect] = other.depleted_effects[effect] | 107 | compound.depleted_effects[effect] = other.depleted_effects[effect] | ||
108 | compound.intensity[effect] = other.intensity[effect] | 108 | compound.intensity[effect] = other.intensity[effect] | ||
109 | setattr(compound, effect, compound._wholeness_check( | 109 | setattr(compound, effect, compound._wholeness_check( | ||
110 | compound._depleted_check( | 110 | compound._depleted_check( | ||
111 | effect, compound._apply_intensity( | 111 | effect, compound._apply_intensity( | ||
112 | effect, compound.effects.get(effect))))) | 112 | effect, compound.effects.get(effect))))) | ||
113 | self.used = True | 113 | self.used = True | ||
114 | other.used = True | 114 | other.used = True | ||
115 | return compound | 115 | return compound | ||
116 | 116 | ||||
117 | def __mul__(self, scale): | 117 | def __mul__(self, scale): | ||
118 | self._validate_not_depleted() | 118 | self._validate_not_depleted() | ||
119 | self._validate_not_used() | 119 | self._validate_not_used() | ||
120 | if scale > 1: | 120 | if scale > 1: | ||
121 | return self._increase_potential(scale) | 121 | return self._increase_potential(scale) | ||
122 | return self._decrease_potential(scale) | 122 | return self._decrease_potential(scale) | ||
123 | 123 | ||||
124 | def __sub__(self, other): | 124 | def __sub__(self, other): | ||
125 | self._validate_not_depleted() | 125 | self._validate_not_depleted() | ||
126 | self._validate_not_used() | 126 | self._validate_not_used() | ||
127 | other._validate_not_depleted() | 127 | other._validate_not_depleted() | ||
128 | other._validate_not_used() | 128 | other._validate_not_used() | ||
129 | purified_potion = self._copy() | 129 | purified_potion = self._copy() | ||
130 | for effect in other.effects: | 130 | for effect in other.effects: | ||
131 | if effect in purified_potion.effects: | 131 | if effect in purified_potion.effects: | ||
132 | if purified_potion.intensity[effect] > other.intensity[effect]: | 132 | if purified_potion.intensity[effect] > other.intensity[effect]: | ||
133 | purified_potion.intensity[effect] -= other.intensity[effect] | 133 | purified_potion.intensity[effect] -= other.intensity[effect] | ||
134 | else: | 134 | else: | ||
135 | purified_potion.depleted_effects.pop(effect) | 135 | purified_potion.depleted_effects.pop(effect) | ||
136 | purified_potion.intensity.pop(effect) | 136 | purified_potion.intensity.pop(effect) | ||
137 | purified_potion.effects.pop(effect) | 137 | purified_potion.effects.pop(effect) | ||
138 | delattr(purified_potion, effect) | 138 | delattr(purified_potion, effect) | ||
139 | else: | 139 | else: | ||
140 | raise TypeError("Cannot remove non-existent effect.") | 140 | raise TypeError("Cannot remove non-existent effect.") | ||
141 | self.used = True | 141 | self.used = True | ||
142 | other.used = True | 142 | other.used = True | ||
143 | return purified_potion | 143 | return purified_potion | ||
144 | 144 | ||||
145 | def __truediv__(self, scale): | 145 | def __truediv__(self, scale): | ||
146 | self._validate_not_depleted() | 146 | self._validate_not_depleted() | ||
147 | self._validate_not_used() | 147 | self._validate_not_used() | ||
148 | potions = [] | 148 | potions = [] | ||
149 | for _ in range(scale): | 149 | for _ in range(scale): | ||
150 | potion = self._copy() | 150 | potion = self._copy() | ||
151 | for effect in potion.intensity: | 151 | for effect in potion.intensity: | ||
152 | potion.intensity[effect] //= scale | 152 | potion.intensity[effect] //= scale | ||
153 | potions.append(potion) | 153 | potions.append(potion) | ||
154 | self.used = True | 154 | self.used = True | ||
155 | return tuple(potions) | 155 | return tuple(potions) | ||
156 | 156 | ||||
157 | def __eq__(self, other): | 157 | def __eq__(self, other): | ||
158 | return (self.effects == other.effects and self.intensity == other.intensity) | 158 | return (self.effects == other.effects and self.intensity == other.intensity) | ||
159 | 159 | ||||
160 | def __lt__(self, other): | 160 | def __lt__(self, other): | ||
161 | return sum(self.intensity.values()) < sum(other.intensity.values()) | 161 | return sum(self.intensity.values()) < sum(other.intensity.values()) | ||
162 | 162 | ||||
163 | def __gt__(self, other): | 163 | def __gt__(self, other): | ||
164 | return sum(self.intensity.values()) > sum(other.intensity.values()) | 164 | return sum(self.intensity.values()) > sum(other.intensity.values()) | ||
165 | 165 | ||||
166 | 166 | ||||
167 | class ГоспожатаПоХимия: | 167 | class ГоспожатаПоХимия: | ||
168 | def __init__(self): | 168 | def __init__(self): | ||
n | 169 | self.durations = [] | n | 169 | self.durations = {} |
170 | self.targets = {} | ||||
171 | self.effects = {} | ||||
170 | 172 | ||||
171 | def apply(self, target, potion): | 173 | def apply(self, target, potion): | ||
172 | old_target = copy.deepcopy(target) | 174 | old_target = copy.deepcopy(target) | ||
173 | potion.apply(target) | 175 | potion.apply(target) | ||
n | 174 | self.durations.append([potion.duration, target, old_target]) | n | 176 | self.durations[id(potion)] = potion.duration |
177 | if id(target) not in self.targets: | ||||
178 | self.targets[id(target)] = old_target | ||||
179 | self.effects[id(potion)] = [target, self.targets[id(target)]] | ||||
175 | 180 | ||||
176 | def tick(self): | 181 | def tick(self): | ||
n | 177 | for triplet in self.durations: | n | 182 | for effect in self.durations: |
178 | target, old_target = triplet[1], triplet[2] | 183 | self.durations[effect] -= 1 | ||
179 | triplet[0] -= 1 | 184 | if self.durations[effect] == 0: | ||
180 | if triplet[0] == 0: | 185 | target, old_target = self.effects[effect] | ||
181 | for attrib in old_target.__dir__(): | 186 | for attrib in target.__dir__(): | ||
182 | if re.search("^__[A-Za-z_0-9]+__$", attrib): | 187 | if re.search("^__[A-Za-z_0-9]+__$", attrib): | ||
183 | continue | 188 | continue | ||
184 | setattr(target, attrib, getattr(old_target, attrib)) | 189 | setattr(target, attrib, getattr(old_target, attrib)) | ||
t | 185 | self.durations.remove(triplet) | t |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import math | f | 1 | import math |
2 | import copy | 2 | import copy | ||
3 | import re | 3 | import re | ||
4 | 4 | ||||
5 | class Potion: | 5 | class Potion: | ||
6 | @staticmethod | 6 | @staticmethod | ||
7 | def round_down(n): | 7 | def round_down(n): | ||
8 | temp = math.floor(n) | 8 | temp = math.floor(n) | ||
9 | if n - temp <= 0.5: | 9 | if n - temp <= 0.5: | ||
10 | return math.floor(n) | 10 | return math.floor(n) | ||
11 | return math.ceil(n) | 11 | return math.ceil(n) | ||
12 | 12 | ||||
13 | def _wholeness_check(self, func): | 13 | def _wholeness_check(self, func): | ||
14 | def check(args): | 14 | def check(args): | ||
15 | self._validate_not_depleted() | 15 | self._validate_not_depleted() | ||
16 | self._validate_not_used() | 16 | self._validate_not_used() | ||
17 | return func(args) | 17 | return func(args) | ||
18 | return check | 18 | return check | ||
19 | 19 | ||||
20 | def _depleted_check(self, effect, func): | 20 | def _depleted_check(self, effect, func): | ||
21 | def check(args): | 21 | def check(args): | ||
22 | if effect in self.depleted_effects: | 22 | if effect in self.depleted_effects: | ||
23 | if self.depleted_effects[effect]: | 23 | if self.depleted_effects[effect]: | ||
24 | raise TypeError("Effect is depleted.") | 24 | raise TypeError("Effect is depleted.") | ||
25 | self.depleted_effects[effect] = True | 25 | self.depleted_effects[effect] = True | ||
26 | return func(args) | 26 | return func(args) | ||
27 | return check | 27 | return check | ||
28 | 28 | ||||
29 | def _apply_intensity(self, effect, func): | 29 | def _apply_intensity(self, effect, func): | ||
30 | def apply(args): | 30 | def apply(args): | ||
31 | if effect in self.intensity: | 31 | if effect in self.intensity: | ||
32 | for _ in range(self.intensity[effect]): | 32 | for _ in range(self.intensity[effect]): | ||
33 | func(args) | 33 | func(args) | ||
34 | return apply | 34 | return apply | ||
35 | 35 | ||||
36 | def _copy(self): | 36 | def _copy(self): | ||
37 | copy_potion = Potion({}, self.duration) | 37 | copy_potion = Potion({}, self.duration) | ||
38 | for effect in self.effects: | 38 | for effect in self.effects: | ||
39 | copy_potion.effects[effect] = self.effects[effect] | 39 | copy_potion.effects[effect] = self.effects[effect] | ||
40 | copy_potion.depleted_effects[effect] = self.depleted_effects[effect] | 40 | copy_potion.depleted_effects[effect] = self.depleted_effects[effect] | ||
41 | copy_potion.intensity[effect] = self.intensity[effect] | 41 | copy_potion.intensity[effect] = self.intensity[effect] | ||
42 | setattr(copy_potion, effect, copy_potion._wholeness_check( | 42 | setattr(copy_potion, effect, copy_potion._wholeness_check( | ||
43 | copy_potion._depleted_check( | 43 | copy_potion._depleted_check( | ||
44 | effect, copy_potion._apply_intensity( | 44 | effect, copy_potion._apply_intensity( | ||
45 | effect, copy_potion.effects.get(effect))))) | 45 | effect, copy_potion.effects.get(effect))))) | ||
46 | return copy_potion | 46 | return copy_potion | ||
47 | 47 | ||||
48 | def _validate_not_used(self): | 48 | def _validate_not_used(self): | ||
49 | if self.used: | 49 | if self.used: | ||
50 | raise TypeError("Potion is now part of something bigger than itself.") | 50 | raise TypeError("Potion is now part of something bigger than itself.") | ||
51 | 51 | ||||
52 | def _validate_not_depleted(self): | 52 | def _validate_not_depleted(self): | ||
53 | if self.depleted: | 53 | if self.depleted: | ||
54 | raise TypeError("Potion is depleted.") | 54 | raise TypeError("Potion is depleted.") | ||
55 | 55 | ||||
56 | def _increase_potential(self, scale): | 56 | def _increase_potential(self, scale): | ||
57 | multiplied_potion = self._copy() | 57 | multiplied_potion = self._copy() | ||
58 | for effect in multiplied_potion.intensity: | 58 | for effect in multiplied_potion.intensity: | ||
59 | multiplied_potion.intensity[effect] *= scale | 59 | multiplied_potion.intensity[effect] *= scale | ||
60 | self.used = True | 60 | self.used = True | ||
61 | return multiplied_potion | 61 | return multiplied_potion | ||
62 | 62 | ||||
63 | def _decrease_potential(self, scale): | 63 | def _decrease_potential(self, scale): | ||
64 | divided_potion = self._copy() | 64 | divided_potion = self._copy() | ||
65 | for effect in divided_potion.intensity: | 65 | for effect in divided_potion.intensity: | ||
66 | divided_potion.intensity[effect] = Potion.round_down( | 66 | divided_potion.intensity[effect] = Potion.round_down( | ||
67 | divided_potion.intensity[effect] * scale) | 67 | divided_potion.intensity[effect] * scale) | ||
68 | self.used = True | 68 | self.used = True | ||
69 | return divided_potion | 69 | return divided_potion | ||
70 | 70 | ||||
71 | def __init__(self, effects, duration): | 71 | def __init__(self, effects, duration): | ||
72 | self.used = False | 72 | self.used = False | ||
73 | self.depleted = False | 73 | self.depleted = False | ||
74 | self.effects = effects | 74 | self.effects = effects | ||
75 | self.depleted_effects = {} | 75 | self.depleted_effects = {} | ||
76 | self.intensity = {} | 76 | self.intensity = {} | ||
77 | for effect in effects: | 77 | for effect in effects: | ||
78 | self.depleted_effects[effect] = False | 78 | self.depleted_effects[effect] = False | ||
79 | self.intensity[effect] = 1 | 79 | self.intensity[effect] = 1 | ||
80 | setattr(self, effect, self._wholeness_check( | 80 | setattr(self, effect, self._wholeness_check( | ||
81 | self._depleted_check( | 81 | self._depleted_check( | ||
82 | effect, self._apply_intensity( | 82 | effect, self._apply_intensity( | ||
83 | effect, effects.get(effect))))) | 83 | effect, effects.get(effect))))) | ||
84 | self.duration = duration | 84 | self.duration = duration | ||
85 | 85 | ||||
86 | def apply(self, target): | 86 | def apply(self, target): | ||
87 | self._validate_not_depleted() | 87 | self._validate_not_depleted() | ||
88 | self._validate_not_used() | 88 | self._validate_not_used() | ||
89 | for effect in sorted(self.effects.keys(), | 89 | for effect in sorted(self.effects.keys(), | ||
90 | key=lambda name: sum(ord(c) for c in name), | 90 | key=lambda name: sum(ord(c) for c in name), | ||
91 | reverse=True): | 91 | reverse=True): | ||
92 | if not self.depleted_effects[effect]: | 92 | if not self.depleted_effects[effect]: | ||
93 | getattr(self, effect)(target) | 93 | getattr(self, effect)(target) | ||
94 | self.depleted = True | 94 | self.depleted = True | ||
95 | 95 | ||||
n | 96 | def __add__(self, o_potion): | n | 96 | def __add__(self, other): |
97 | self._validate_not_depleted() | 97 | self._validate_not_depleted() | ||
98 | self._validate_not_used() | 98 | self._validate_not_used() | ||
n | 99 | o_potion._validate_not_depleted() | n | 99 | other._validate_not_depleted() |
100 | o_potion._validate_not_used() | 100 | other._validate_not_used() | ||
101 | compound = self._copy() | 101 | compound = self._copy() | ||
n | 102 | for effect in o_potion.effects: | n | 102 | for effect in other.effects: |
103 | if effect in compound.effects: | 103 | if effect in compound.effects: | ||
n | 104 | compound.intensity[effect] += o_potion.intensity[effect] | n | 104 | compound.intensity[effect] += other.intensity[effect] |
105 | else: | 105 | else: | ||
n | 106 | compound.effects[effect] = o_potion.effects[effect] | n | 106 | compound.effects[effect] = other.effects[effect] |
107 | compound.depleted_effects[effect] = o_potion.depleted_effects[effect] | 107 | compound.depleted_effects[effect] = other.depleted_effects[effect] | ||
108 | compound.intensity[effect] = o_potion.intensity[effect] | 108 | compound.intensity[effect] = other.intensity[effect] | ||
109 | setattr(compound, effect, compound._wholeness_check( | 109 | setattr(compound, effect, compound._wholeness_check( | ||
110 | compound._depleted_check( | 110 | compound._depleted_check( | ||
111 | effect, compound._apply_intensity( | 111 | effect, compound._apply_intensity( | ||
112 | effect, compound.effects.get(effect))))) | 112 | effect, compound.effects.get(effect))))) | ||
113 | self.used = True | 113 | self.used = True | ||
n | 114 | o_potion.used = True | n | 114 | other.used = True |
115 | return compound | 115 | return compound | ||
116 | 116 | ||||
117 | def __mul__(self, scale): | 117 | def __mul__(self, scale): | ||
118 | self._validate_not_depleted() | 118 | self._validate_not_depleted() | ||
119 | self._validate_not_used() | 119 | self._validate_not_used() | ||
120 | if scale > 1: | 120 | if scale > 1: | ||
121 | return self._increase_potential(scale) | 121 | return self._increase_potential(scale) | ||
122 | return self._decrease_potential(scale) | 122 | return self._decrease_potential(scale) | ||
123 | 123 | ||||
n | 124 | def __sub__(self, o_potion): | n | 124 | def __sub__(self, other): |
125 | self._validate_not_depleted() | 125 | self._validate_not_depleted() | ||
126 | self._validate_not_used() | 126 | self._validate_not_used() | ||
n | 127 | o_potion._validate_not_depleted() | n | 127 | other._validate_not_depleted() |
128 | o_potion._validate_not_used() | 128 | other._validate_not_used() | ||
129 | purified_potion = self._copy() | 129 | purified_potion = self._copy() | ||
n | 130 | for effect in o_potion.effects: | n | 130 | for effect in other.effects: |
131 | if effect in purified_potion.effects: | 131 | if effect in purified_potion.effects: | ||
n | 132 | if purified_potion.intensity[effect] > o_potion.intensity[effect]: | n | 132 | if purified_potion.intensity[effect] > other.intensity[effect]: |
133 | purified_potion.intensity[effect] -= o_potion.intensity[effect] | 133 | purified_potion.intensity[effect] -= other.intensity[effect] | ||
134 | else: | 134 | else: | ||
135 | purified_potion.depleted_effects.pop(effect) | 135 | purified_potion.depleted_effects.pop(effect) | ||
136 | purified_potion.intensity.pop(effect) | 136 | purified_potion.intensity.pop(effect) | ||
137 | purified_potion.effects.pop(effect) | 137 | purified_potion.effects.pop(effect) | ||
138 | delattr(purified_potion, effect) | 138 | delattr(purified_potion, effect) | ||
139 | else: | 139 | else: | ||
140 | raise TypeError("Cannot remove non-existent effect.") | 140 | raise TypeError("Cannot remove non-existent effect.") | ||
141 | self.used = True | 141 | self.used = True | ||
n | 142 | o_potion.used = True | n | 142 | other.used = True |
143 | return purified_potion | 143 | return purified_potion | ||
144 | 144 | ||||
145 | def __truediv__(self, scale): | 145 | def __truediv__(self, scale): | ||
146 | self._validate_not_depleted() | 146 | self._validate_not_depleted() | ||
147 | self._validate_not_used() | 147 | self._validate_not_used() | ||
148 | potions = [] | 148 | potions = [] | ||
149 | for _ in range(scale): | 149 | for _ in range(scale): | ||
150 | potion = self._copy() | 150 | potion = self._copy() | ||
151 | for effect in potion.intensity: | 151 | for effect in potion.intensity: | ||
152 | potion.intensity[effect] //= scale | 152 | potion.intensity[effect] //= scale | ||
153 | potions.append(potion) | 153 | potions.append(potion) | ||
154 | self.used = True | 154 | self.used = True | ||
155 | return tuple(potions) | 155 | return tuple(potions) | ||
156 | 156 | ||||
n | 157 | def __eq__(self, o_potion): | n | 157 | def __eq__(self, other): |
158 | return (self.effects == o_potion.effects | 158 | return (self.effects == other.effects and self.intensity == other.intensity) | ||
159 | and self.intensity == o_potion.intensity) | ||||
160 | 159 | ||||
n | 161 | def __lt__(self, o_potion): | n | 160 | def __lt__(self, other): |
162 | i1 = 0 | 161 | return sum(self.intensity.values()) < sum(other.intensity.values()) | ||
163 | for intensity in self.intensity.values(): | ||||
164 | i1 += intensity | ||||
165 | i2 = 0 | ||||
166 | for intensity in o_potion.intensity.values(): | ||||
167 | i2 += intensity | ||||
168 | return i1 < i2 | ||||
169 | 162 | ||||
n | 170 | def __gt__(self, o_potion): | n | 163 | def __gt__(self, other): |
171 | i1 = 0 | 164 | return sum(self.intensity.values()) > sum(other.intensity.values()) | ||
172 | for intensity in self.intensity.values(): | ||||
173 | i1 += intensity | ||||
174 | i2 = 0 | ||||
175 | for intensity in o_potion.intensity.values(): | ||||
176 | i2 += intensity | ||||
177 | return i1 > i2 | ||||
178 | 165 | ||||
179 | 166 | ||||
180 | class ГоспожатаПоХимия: | 167 | class ГоспожатаПоХимия: | ||
181 | def __init__(self): | 168 | def __init__(self): | ||
182 | self.durations = [] | 169 | self.durations = [] | ||
183 | 170 | ||||
184 | def apply(self, target, potion): | 171 | def apply(self, target, potion): | ||
185 | old_target = copy.deepcopy(target) | 172 | old_target = copy.deepcopy(target) | ||
186 | potion.apply(target) | 173 | potion.apply(target) | ||
187 | self.durations.append([potion.duration, target, old_target]) | 174 | self.durations.append([potion.duration, target, old_target]) | ||
188 | 175 | ||||
189 | def tick(self): | 176 | def tick(self): | ||
190 | for triplet in self.durations: | 177 | for triplet in self.durations: | ||
n | n | 178 | target, old_target = triplet[1], triplet[2] | ||
191 | triplet[0] -= 1 | 179 | triplet[0] -= 1 | ||
192 | if triplet[0] == 0: | 180 | if triplet[0] == 0: | ||
n | 193 | for attrib in triplet[2].__dir__(): | n | 181 | for attrib in old_target.__dir__(): |
194 | if re.search("^__[A-Za-z_0-9]+__$", attrib): | 182 | if re.search("^__[A-Za-z_0-9]+__$", attrib): | ||
195 | continue | 183 | continue | ||
t | 196 | triplet[1].__setattr__(attrib, triplet[2].__getattribute__(attrib)) | t | 184 | setattr(target, attrib, getattr(old_target, attrib)) |
197 | self.durations.remove(triplet) | 185 | self.durations.remove(triplet) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|