1import math
2import copy
3
4
5class Potion:
6
7 def __init__(self, effects, duration):
8 self.effects = effects
9 self.duration = duration
10 self.intensity = {key: 1.0 for key in effects.keys()}
11 self.used = False
12 self.used_effects = {key: False for key in effects.keys()}
13 self.start_duration = -1
14 self.end_duration = -1
15 for effect in effects.keys():
16 setattr(self, effect, lambda target, name=effect: self.apply_effect(target, name))
17
18 @staticmethod
19 def is_potion_used(*potions):
20 for potion in potions:
21 if potion.used:
22 raise TypeError("Potion is now part of something bigger than itself.")
23
24 def __add__(self, other):
25 Potion.is_potion_used(self, other)
26
27 combined_effects = dict(self.effects)
28 combined_intensity = dict(self.intensity)
29
30 for key, value in other.effects.items():
31 if key in combined_effects:
32 combined_intensity[key] += other.intensity.get(key,0)
33 else:
34 combined_effects[key] = value
35 combined_intensity[key] = other.intensity.get(key,0)
36
37 duration = max(self.duration, other.duration)
38 new_potion = Potion(combined_effects, duration)
39 new_potion.intensity = dict(combined_intensity)
40 self.used = True
41 other.used = True
42 return new_potion
43
44 def __mul__(self, coefficient):
45 Potion.is_potion_used(self)
46
47 multiplied_intensity = dict(self.intensity)
48
49 for key in self.intensity.keys():
50 result_intensity = multiplied_intensity[key]*coefficient
51 fraction, integer = math.modf(result_intensity)
52 if coefficient >= 1:
53 multiplied_intensity[key] = result_intensity
54 elif fraction <= 0.5:
55 multiplied_intensity[key] = float(math.floor(result_intensity))
56 else:
57 multiplied_intensity[key] = float(math.ceil(result_intensity))
58
59 new_potion = Potion(self.effects, self.duration)
60 new_potion.intensity = dict(multiplied_intensity)
61 self.used = True
62 return new_potion
63
64 def __sub__(self, other):
65 Potion.is_potion_used(self, other)
66
67 if not all(effect in self.effects for effect in other.effects):
68 raise TypeError("Cannot subtract potions with different effects")
69
70 subtracted_effects = dict(self.effects)
71 subtracted_intensity = dict(self.intensity)
72
73 to_delete_keys = []
74 for key in other.effects.keys():
75 if key in subtracted_effects:
76 subtracted_intensity[key] -= other.intensity.get(key,0)
77 if subtracted_intensity[key] <= 0:
78 to_delete_keys.append(key)
79
80 for key in to_delete_keys:
81 del subtracted_effects[key]
82 del subtracted_intensity[key]
83
84 new_potion = Potion(subtracted_effects, self.duration)
85 new_potion.intensity = dict(subtracted_intensity)
86 self.used = True
87 other.used = True
88 return new_potion
89
90 def __truediv__(self, divisor):
91 Potion.is_potion_used(self)
92
93 new_intensity = dict(self.intensity)
94 for key in self.intensity.keys():
95 result_intensity = new_intensity[key] / divisor
96 fraction, integer = math.modf(result_intensity)
97 if fraction <= 0.5:
98 new_intensity[key] = float(math.floor(result_intensity))
99 else:
100 new_intensity[key] = float(math.ceil(result_intensity))
101
102 new_potions = []
103 for _ in range(divisor):
104 new_potion = Potion(self.effects, self.duration)
105 new_potion.intensity = dict(new_intensity)
106 new_potions.append(new_potion)
107
108 self.used = True
109 return new_potions
110
111 def __eq__(self, other):
112 Potion.is_potion_used(self, other)
113
114 equal_intensities = True
115 for intensity_self_key, intensity_self_value in self.intensity.items():
116 for intensity_other_key, intensity_other_value in other.intensity.items():
117 if intensity_self_key == intensity_other_key:
118 if intensity_self_value != intensity_other_value:
119 equal_intensities = False
120 return (all(effect in self.effects for effect in other.effects) and
121 all(effect in other.effects for effect in self.effects) and
122 equal_intensities)
123
124 def __gt__(self, other):
125 Potion.is_potion_used(self, other)
126
127 sum_self = sum(self.intensity.values())
128 sum_other = sum(other.intensity.values())
129 return sum_self > sum_other
130
131 def __lt__(self, other):
132 Potion.is_potion_used(self, other)
133
134 sum_self = sum(self.intensity.values())
135 sum_other = sum(other.intensity.values())
136 return sum_self < sum_other
137
138 def apply_effect(self, target, effect):
139 Potion.is_potion_used(self)
140 if self.used_effects[effect]:
141 raise TypeError("Effect is depleted.")
142 for _ in range(int(self.intensity[effect])):
143 self.effects[effect](target)
144 self.used_effects[effect] = True
145
146
147class ГоспожатаПоХимия:
148
149 def __init__(self):
150 self.tick_count = 0
151 self.active_potions = {}
152 self.initial_states = {}
153
154 def apply(self, target, potion):
155 if potion.used:
156 raise TypeError("Potion is depleted.")
157
158 initial_state = copy.deepcopy(target)
159
160 sorted_by_molecular_mass = sorted(potion.intensity.items(),
161 key=lambda x: sum(ord(c) for c in x[0]), reverse=True)
162 for effect in sorted_by_molecular_mass:
163 for _ in range(int(effect[1])):
164 potion.apply_effect(target, effect[0])
165 potion.start_duration = self.tick_count
166 potion.end_duration = self.tick_count + potion.duration
167
168 """
169 if self.active_potions[id(target)]:
170 self.active_potions[id(target)] = potion
171 self.initial_states[id(target)] = initial_state, target
172 """
173
174 def tick(self):
175 #collect all applied (potions : target) in a list and subtract
176 #their potion.active variables every tick
177 #if a potion expires return to initial state of target
178 self.tick_count += 1
179
180 expired_potions = {target_id:potion for target_id, potion in self.active_potions.items()
181 if potion.end_duration <= self.tick_count}
182
183 sorted_by_start_time = sorted(expired_potions.items(), key=lambda x: x[1].start_duration)
184 """
185 for target_id, potion in sorted_by_start_time:
186 if potion.end_duration <= self.tick_count:
187
188 self.active_potions.pop()
189 initial_state, target = self.initial_states.pop(target_id)
190 self.reset_target_to_initial_state(target, initial_state)
191 """
192
193 def reset_target_to_initial_state(self, target, initial_state):
194 target.__dict__.update(initial_state.__dict__)
............F..EEFEF
======================================================================
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 164, in apply
potion.apply_effect(target, effect[0])
File "/tmp/solution.py", line 141, in apply_effect
raise TypeError("Effect is depleted.")
TypeError: Effect is depleted.
======================================================================
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 424, in test_ticking_immutable
self._dimitrichka.apply(self._target, potion)
File "/tmp/solution.py", line 164, in apply
potion.apply_effect(target, effect[0])
File "/tmp/solution.py", line 141, in apply_effect
raise TypeError("Effect is depleted.")
TypeError: Effect 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/test.py", line 485, in test_ticking_multiple_targets
self._dimitrichka.apply(target1, potion1)
File "/tmp/solution.py", line 164, in apply
potion.apply_effect(target, effect[0])
File "/tmp/solution.py", line 141, in apply_effect
raise TypeError("Effect is depleted.")
TypeError: Effect is depleted.
======================================================================
FAIL: test_applying_depleted_potion (test.TestГоспожатаПоХимия)
Test applying a depleted potion or a potion that was used in a reaction.
----------------------------------------------------------------------
TypeError: Effect is depleted.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/test.py", line 380, in test_applying_depleted_potion
with self.assertRaisesRegex(TypeError, 'Potion is depleted\.'):
AssertionError: "Potion is depleted\." does not match "Effect is depleted."
======================================================================
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_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=3, errors=3)
n | 1 | import math, copy | n | 1 | import math |
2 | import copy | ||||
2 | 3 | ||||
3 | 4 | ||||
4 | class Potion: | 5 | class Potion: | ||
n | 5 | n | 6 | ||
6 | def __init__(self, effects, duration): | 7 | def __init__(self, effects, duration): | ||
7 | self.effects = effects | 8 | self.effects = effects | ||
8 | self.duration = duration | 9 | self.duration = duration | ||
n | 9 | self.intensity = {key:1.0 for key in effects.keys()} | n | 10 | self.intensity = {key: 1.0 for key in effects.keys()} |
10 | self.used = False | 11 | self.used = False | ||
n | 11 | self.used_effects = {key:False for key in effects.keys()} | n | 12 | self.used_effects = {key: False for key in effects.keys()} |
12 | self.start_duration = -1 | 13 | self.start_duration = -1 | ||
13 | self.end_duration = -1 | 14 | self.end_duration = -1 | ||
14 | for effect in effects.keys(): | 15 | for effect in effects.keys(): | ||
15 | setattr(self, effect, lambda target, name=effect: self.apply_effect(target, name)) | 16 | setattr(self, effect, lambda target, name=effect: self.apply_effect(target, name)) | ||
16 | 17 | ||||
n | n | 18 | @staticmethod | ||
19 | def is_potion_used(*potions): | ||||
20 | for potion in potions: | ||||
21 | if potion.used: | ||||
22 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
23 | |||||
17 | def __add__(self, other): | 24 | def __add__(self, other): | ||
n | 18 | if self.used or other.used: | n | 25 | Potion.is_potion_used(self, other) |
19 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
20 | 26 | ||||
21 | combined_effects = dict(self.effects) | 27 | combined_effects = dict(self.effects) | ||
22 | combined_intensity = dict(self.intensity) | 28 | combined_intensity = dict(self.intensity) | ||
23 | 29 | ||||
24 | for key, value in other.effects.items(): | 30 | for key, value in other.effects.items(): | ||
25 | if key in combined_effects: | 31 | if key in combined_effects: | ||
26 | combined_intensity[key] += other.intensity.get(key,0) | 32 | combined_intensity[key] += other.intensity.get(key,0) | ||
27 | else: | 33 | else: | ||
28 | combined_effects[key] = value | 34 | combined_effects[key] = value | ||
29 | combined_intensity[key] = other.intensity.get(key,0) | 35 | combined_intensity[key] = other.intensity.get(key,0) | ||
30 | 36 | ||||
31 | duration = max(self.duration, other.duration) | 37 | duration = max(self.duration, other.duration) | ||
32 | new_potion = Potion(combined_effects, duration) | 38 | new_potion = Potion(combined_effects, duration) | ||
33 | new_potion.intensity = dict(combined_intensity) | 39 | new_potion.intensity = dict(combined_intensity) | ||
34 | self.used = True | 40 | self.used = True | ||
35 | other.used = True | 41 | other.used = True | ||
36 | return new_potion | 42 | return new_potion | ||
37 | 43 | ||||
38 | def __mul__(self, coefficient): | 44 | def __mul__(self, coefficient): | ||
n | 39 | if self.used: | n | 45 | Potion.is_potion_used(self) |
40 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
41 | 46 | ||||
42 | multiplied_intensity = dict(self.intensity) | 47 | multiplied_intensity = dict(self.intensity) | ||
43 | 48 | ||||
44 | for key in self.intensity.keys(): | 49 | for key in self.intensity.keys(): | ||
45 | result_intensity = multiplied_intensity[key]*coefficient | 50 | result_intensity = multiplied_intensity[key]*coefficient | ||
46 | fraction, integer = math.modf(result_intensity) | 51 | fraction, integer = math.modf(result_intensity) | ||
47 | if coefficient >= 1: | 52 | if coefficient >= 1: | ||
48 | multiplied_intensity[key] = result_intensity | 53 | multiplied_intensity[key] = result_intensity | ||
49 | elif fraction <= 0.5: | 54 | elif fraction <= 0.5: | ||
50 | multiplied_intensity[key] = float(math.floor(result_intensity)) | 55 | multiplied_intensity[key] = float(math.floor(result_intensity)) | ||
51 | else: | 56 | else: | ||
52 | multiplied_intensity[key] = float(math.ceil(result_intensity)) | 57 | multiplied_intensity[key] = float(math.ceil(result_intensity)) | ||
53 | 58 | ||||
54 | new_potion = Potion(self.effects, self.duration) | 59 | new_potion = Potion(self.effects, self.duration) | ||
55 | new_potion.intensity = dict(multiplied_intensity) | 60 | new_potion.intensity = dict(multiplied_intensity) | ||
56 | self.used = True | 61 | self.used = True | ||
57 | return new_potion | 62 | return new_potion | ||
58 | 63 | ||||
59 | def __sub__(self, other): | 64 | def __sub__(self, other): | ||
n | 60 | if self.used or other.used: | n | 65 | Potion.is_potion_used(self, other) |
61 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
62 | 66 | ||||
63 | if not all(effect in self.effects for effect in other.effects): | 67 | if not all(effect in self.effects for effect in other.effects): | ||
64 | raise TypeError("Cannot subtract potions with different effects") | 68 | raise TypeError("Cannot subtract potions with different effects") | ||
65 | 69 | ||||
66 | subtracted_effects = dict(self.effects) | 70 | subtracted_effects = dict(self.effects) | ||
67 | subtracted_intensity = dict(self.intensity) | 71 | subtracted_intensity = dict(self.intensity) | ||
68 | 72 | ||||
69 | to_delete_keys = [] | 73 | to_delete_keys = [] | ||
70 | for key in other.effects.keys(): | 74 | for key in other.effects.keys(): | ||
71 | if key in subtracted_effects: | 75 | if key in subtracted_effects: | ||
72 | subtracted_intensity[key] -= other.intensity.get(key,0) | 76 | subtracted_intensity[key] -= other.intensity.get(key,0) | ||
73 | if subtracted_intensity[key] <= 0: | 77 | if subtracted_intensity[key] <= 0: | ||
74 | to_delete_keys.append(key) | 78 | to_delete_keys.append(key) | ||
75 | 79 | ||||
76 | for key in to_delete_keys: | 80 | for key in to_delete_keys: | ||
77 | del subtracted_effects[key] | 81 | del subtracted_effects[key] | ||
78 | del subtracted_intensity[key] | 82 | del subtracted_intensity[key] | ||
79 | 83 | ||||
80 | new_potion = Potion(subtracted_effects, self.duration) | 84 | new_potion = Potion(subtracted_effects, self.duration) | ||
81 | new_potion.intensity = dict(subtracted_intensity) | 85 | new_potion.intensity = dict(subtracted_intensity) | ||
82 | self.used = True | 86 | self.used = True | ||
83 | other.used = True | 87 | other.used = True | ||
84 | return new_potion | 88 | return new_potion | ||
85 | 89 | ||||
86 | def __truediv__(self, divisor): | 90 | def __truediv__(self, divisor): | ||
n | 87 | if self.used: | n | 91 | Potion.is_potion_used(self) |
88 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
89 | 92 | ||||
90 | new_intensity = dict(self.intensity) | 93 | new_intensity = dict(self.intensity) | ||
91 | for key in self.intensity.keys(): | 94 | for key in self.intensity.keys(): | ||
n | 92 | result_intensity = new_intensity[key]/divisor | n | 95 | result_intensity = new_intensity[key] / divisor |
93 | fraction, integer = math.modf(result_intensity) | 96 | fraction, integer = math.modf(result_intensity) | ||
94 | if fraction <= 0.5: | 97 | if fraction <= 0.5: | ||
95 | new_intensity[key] = float(math.floor(result_intensity)) | 98 | new_intensity[key] = float(math.floor(result_intensity)) | ||
96 | else: | 99 | else: | ||
97 | new_intensity[key] = float(math.ceil(result_intensity)) | 100 | new_intensity[key] = float(math.ceil(result_intensity)) | ||
98 | 101 | ||||
99 | new_potions = [] | 102 | new_potions = [] | ||
100 | for _ in range(divisor): | 103 | for _ in range(divisor): | ||
101 | new_potion = Potion(self.effects, self.duration) | 104 | new_potion = Potion(self.effects, self.duration) | ||
102 | new_potion.intensity = dict(new_intensity) | 105 | new_potion.intensity = dict(new_intensity) | ||
103 | new_potions.append(new_potion) | 106 | new_potions.append(new_potion) | ||
104 | 107 | ||||
105 | self.used = True | 108 | self.used = True | ||
106 | return new_potions | 109 | return new_potions | ||
107 | 110 | ||||
108 | def __eq__(self, other): | 111 | def __eq__(self, other): | ||
n | 109 | if self.used or other.used: | n | 112 | Potion.is_potion_used(self, other) |
110 | raise TypeError("Potion is now part of something bigger than itself.") | 113 | |||
111 | equal_intensities = True | 114 | equal_intensities = True | ||
112 | for intensity_self_key, intensity_self_value in self.intensity.items(): | 115 | for intensity_self_key, intensity_self_value in self.intensity.items(): | ||
113 | for intensity_other_key, intensity_other_value in other.intensity.items(): | 116 | for intensity_other_key, intensity_other_value in other.intensity.items(): | ||
114 | if intensity_self_key == intensity_other_key: | 117 | if intensity_self_key == intensity_other_key: | ||
115 | if intensity_self_value != intensity_other_value: | 118 | if intensity_self_value != intensity_other_value: | ||
116 | equal_intensities = False | 119 | equal_intensities = False | ||
117 | return (all(effect in self.effects for effect in other.effects) and | 120 | return (all(effect in self.effects for effect in other.effects) and | ||
118 | all(effect in other.effects for effect in self.effects) and | 121 | all(effect in other.effects for effect in self.effects) and | ||
119 | equal_intensities) | 122 | equal_intensities) | ||
120 | 123 | ||||
121 | def __gt__(self, other): | 124 | def __gt__(self, other): | ||
n | 122 | if self.used or other.used: | n | 125 | Potion.is_potion_used(self, other) |
123 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
124 | 126 | ||||
125 | sum_self = sum(self.intensity.values()) | 127 | sum_self = sum(self.intensity.values()) | ||
126 | sum_other = sum(other.intensity.values()) | 128 | sum_other = sum(other.intensity.values()) | ||
127 | return sum_self > sum_other | 129 | return sum_self > sum_other | ||
128 | 130 | ||||
129 | def __lt__(self, other): | 131 | def __lt__(self, other): | ||
n | 130 | if self.used or other.used: | n | 132 | Potion.is_potion_used(self, other) |
131 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
132 | 133 | ||||
133 | sum_self = sum(self.intensity.values()) | 134 | sum_self = sum(self.intensity.values()) | ||
134 | sum_other = sum(other.intensity.values()) | 135 | sum_other = sum(other.intensity.values()) | ||
135 | return sum_self < sum_other | 136 | return sum_self < sum_other | ||
136 | 137 | ||||
137 | def apply_effect(self, target, effect): | 138 | def apply_effect(self, target, effect): | ||
t | 138 | if self.used: | t | 139 | Potion.is_potion_used(self) |
139 | raise TypeError("Potion is now part of something bigger than itself.") | ||||
140 | if self.used_effects[effect]: | 140 | if self.used_effects[effect]: | ||
141 | raise TypeError("Effect is depleted.") | 141 | raise TypeError("Effect is depleted.") | ||
142 | for _ in range(int(self.intensity[effect])): | 142 | for _ in range(int(self.intensity[effect])): | ||
143 | self.effects[effect](target) | 143 | self.effects[effect](target) | ||
144 | self.used_effects[effect] = True | 144 | self.used_effects[effect] = True | ||
145 | 145 | ||||
146 | 146 | ||||
147 | class ГоспожатаПоХимия: | 147 | class ГоспожатаПоХимия: | ||
148 | 148 | ||||
149 | def __init__(self): | 149 | def __init__(self): | ||
150 | self.tick_count = 0 | 150 | self.tick_count = 0 | ||
151 | self.active_potions = {} | 151 | self.active_potions = {} | ||
152 | self.initial_states = {} | 152 | self.initial_states = {} | ||
153 | 153 | ||||
154 | def apply(self, target, potion): | 154 | def apply(self, target, potion): | ||
155 | if potion.used: | 155 | if potion.used: | ||
156 | raise TypeError("Potion is depleted.") | 156 | raise TypeError("Potion is depleted.") | ||
157 | 157 | ||||
158 | initial_state = copy.deepcopy(target) | 158 | initial_state = copy.deepcopy(target) | ||
159 | 159 | ||||
160 | sorted_by_molecular_mass = sorted(potion.intensity.items(), | 160 | sorted_by_molecular_mass = sorted(potion.intensity.items(), | ||
161 | key=lambda x: sum(ord(c) for c in x[0]), reverse=True) | 161 | key=lambda x: sum(ord(c) for c in x[0]), reverse=True) | ||
162 | for effect in sorted_by_molecular_mass: | 162 | for effect in sorted_by_molecular_mass: | ||
163 | for _ in range(int(effect[1])): | 163 | for _ in range(int(effect[1])): | ||
164 | potion.apply_effect(target, effect[0]) | 164 | potion.apply_effect(target, effect[0]) | ||
165 | potion.start_duration = self.tick_count | 165 | potion.start_duration = self.tick_count | ||
166 | potion.end_duration = self.tick_count + potion.duration | 166 | potion.end_duration = self.tick_count + potion.duration | ||
167 | 167 | ||||
168 | """ | 168 | """ | ||
169 | if self.active_potions[id(target)]: | 169 | if self.active_potions[id(target)]: | ||
170 | self.active_potions[id(target)] = potion | 170 | self.active_potions[id(target)] = potion | ||
171 | self.initial_states[id(target)] = initial_state, target | 171 | self.initial_states[id(target)] = initial_state, target | ||
172 | """ | 172 | """ | ||
173 | 173 | ||||
174 | def tick(self): | 174 | def tick(self): | ||
175 | #collect all applied (potions : target) in a list and subtract | 175 | #collect all applied (potions : target) in a list and subtract | ||
176 | #their potion.active variables every tick | 176 | #their potion.active variables every tick | ||
177 | #if a potion expires return to initial state of target | 177 | #if a potion expires return to initial state of target | ||
178 | self.tick_count += 1 | 178 | self.tick_count += 1 | ||
179 | 179 | ||||
180 | expired_potions = {target_id:potion for target_id, potion in self.active_potions.items() | 180 | expired_potions = {target_id:potion for target_id, potion in self.active_potions.items() | ||
181 | if potion.end_duration <= self.tick_count} | 181 | if potion.end_duration <= self.tick_count} | ||
182 | 182 | ||||
183 | sorted_by_start_time = sorted(expired_potions.items(), key=lambda x: x[1].start_duration) | 183 | sorted_by_start_time = sorted(expired_potions.items(), key=lambda x: x[1].start_duration) | ||
184 | """ | 184 | """ | ||
185 | for target_id, potion in sorted_by_start_time: | 185 | for target_id, potion in sorted_by_start_time: | ||
186 | if potion.end_duration <= self.tick_count: | 186 | if potion.end_duration <= self.tick_count: | ||
187 | 187 | ||||
188 | self.active_potions.pop() | 188 | self.active_potions.pop() | ||
189 | initial_state, target = self.initial_states.pop(target_id) | 189 | initial_state, target = self.initial_states.pop(target_id) | ||
190 | self.reset_target_to_initial_state(target, initial_state) | 190 | self.reset_target_to_initial_state(target, initial_state) | ||
191 | """ | 191 | """ | ||
192 | 192 | ||||
193 | def reset_target_to_initial_state(self, target, initial_state): | 193 | def reset_target_to_initial_state(self, target, initial_state): | ||
194 | target.__dict__.update(initial_state.__dict__) | 194 | target.__dict__.update(initial_state.__dict__) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import math, copy | f | 1 | import math, copy |
2 | 2 | ||||
n | n | 3 | |||
3 | class Potion: | 4 | class Potion: | ||
n | n | 5 | |||
4 | def __init__(self, effects, duration): | 6 | def __init__(self, effects, duration): | ||
5 | self.effects = effects | 7 | self.effects = effects | ||
6 | self.duration = duration | 8 | self.duration = duration | ||
7 | self.intensity = {key:1.0 for key in effects.keys()} | 9 | self.intensity = {key:1.0 for key in effects.keys()} | ||
8 | self.used = False | 10 | self.used = False | ||
9 | self.used_effects = {key:False for key in effects.keys()} | 11 | self.used_effects = {key:False for key in effects.keys()} | ||
10 | self.start_duration = -1 | 12 | self.start_duration = -1 | ||
11 | self.end_duration = -1 | 13 | self.end_duration = -1 | ||
12 | for effect in effects.keys(): | 14 | for effect in effects.keys(): | ||
13 | setattr(self, effect, lambda target, name=effect: self.apply_effect(target, name)) | 15 | setattr(self, effect, lambda target, name=effect: self.apply_effect(target, name)) | ||
14 | 16 | ||||
15 | def __add__(self, other): | 17 | def __add__(self, other): | ||
16 | if self.used or other.used: | 18 | if self.used or other.used: | ||
17 | raise TypeError("Potion is now part of something bigger than itself.") | 19 | raise TypeError("Potion is now part of something bigger than itself.") | ||
n | 18 | n | 20 | ||
19 | combined_effects = dict(self.effects) | 21 | combined_effects = dict(self.effects) | ||
20 | combined_intensity = dict(self.intensity) | 22 | combined_intensity = dict(self.intensity) | ||
21 | 23 | ||||
22 | for key, value in other.effects.items(): | 24 | for key, value in other.effects.items(): | ||
23 | if key in combined_effects: | 25 | if key in combined_effects: | ||
24 | combined_intensity[key] += other.intensity.get(key,0) | 26 | combined_intensity[key] += other.intensity.get(key,0) | ||
25 | else: | 27 | else: | ||
26 | combined_effects[key] = value | 28 | combined_effects[key] = value | ||
27 | combined_intensity[key] = other.intensity.get(key,0) | 29 | combined_intensity[key] = other.intensity.get(key,0) | ||
28 | 30 | ||||
29 | duration = max(self.duration, other.duration) | 31 | duration = max(self.duration, other.duration) | ||
30 | new_potion = Potion(combined_effects, duration) | 32 | new_potion = Potion(combined_effects, duration) | ||
31 | new_potion.intensity = dict(combined_intensity) | 33 | new_potion.intensity = dict(combined_intensity) | ||
32 | self.used = True | 34 | self.used = True | ||
33 | other.used = True | 35 | other.used = True | ||
34 | return new_potion | 36 | return new_potion | ||
n | 35 | n | 37 | ||
36 | def __mul__(self, coefficient): | 38 | def __mul__(self, coefficient): | ||
37 | if self.used: | 39 | if self.used: | ||
38 | raise TypeError("Potion is now part of something bigger than itself.") | 40 | raise TypeError("Potion is now part of something bigger than itself.") | ||
n | 39 | n | 41 | ||
40 | multiplied_intensity = dict(self.intensity) | 42 | multiplied_intensity = dict(self.intensity) | ||
41 | 43 | ||||
42 | for key in self.intensity.keys(): | 44 | for key in self.intensity.keys(): | ||
43 | result_intensity = multiplied_intensity[key]*coefficient | 45 | result_intensity = multiplied_intensity[key]*coefficient | ||
44 | fraction, integer = math.modf(result_intensity) | 46 | fraction, integer = math.modf(result_intensity) | ||
45 | if coefficient >= 1: | 47 | if coefficient >= 1: | ||
46 | multiplied_intensity[key] = result_intensity | 48 | multiplied_intensity[key] = result_intensity | ||
47 | elif fraction <= 0.5: | 49 | elif fraction <= 0.5: | ||
48 | multiplied_intensity[key] = float(math.floor(result_intensity)) | 50 | multiplied_intensity[key] = float(math.floor(result_intensity)) | ||
49 | else: | 51 | else: | ||
50 | multiplied_intensity[key] = float(math.ceil(result_intensity)) | 52 | multiplied_intensity[key] = float(math.ceil(result_intensity)) | ||
n | 51 | n | 53 | ||
52 | new_potion = Potion(self.effects, self.duration) | 54 | new_potion = Potion(self.effects, self.duration) | ||
53 | new_potion.intensity = dict(multiplied_intensity) | 55 | new_potion.intensity = dict(multiplied_intensity) | ||
54 | self.used = True | 56 | self.used = True | ||
55 | return new_potion | 57 | return new_potion | ||
n | 56 | n | 58 | ||
57 | def __sub__(self, other): | 59 | def __sub__(self, other): | ||
58 | if self.used or other.used: | 60 | if self.used or other.used: | ||
59 | raise TypeError("Potion is now part of something bigger than itself.") | 61 | raise TypeError("Potion is now part of something bigger than itself.") | ||
n | 60 | n | 62 | ||
61 | if not all(effect in self.effects for effect in other.effects): | 63 | if not all(effect in self.effects for effect in other.effects): | ||
62 | raise TypeError("Cannot subtract potions with different effects") | 64 | raise TypeError("Cannot subtract potions with different effects") | ||
n | 63 | n | 65 | ||
64 | subtracted_effects = dict(self.effects) | 66 | subtracted_effects = dict(self.effects) | ||
65 | subtracted_intensity = dict(self.intensity) | 67 | subtracted_intensity = dict(self.intensity) | ||
n | 66 | n | 68 | ||
67 | to_delete_keys = [] | 69 | to_delete_keys = [] | ||
n | 68 | for key, value in other.effects.items(): | n | 70 | for key in other.effects.keys(): |
69 | if key in subtracted_effects: | 71 | if key in subtracted_effects: | ||
70 | subtracted_intensity[key] -= other.intensity.get(key,0) | 72 | subtracted_intensity[key] -= other.intensity.get(key,0) | ||
71 | if subtracted_intensity[key] <= 0: | 73 | if subtracted_intensity[key] <= 0: | ||
72 | to_delete_keys.append(key) | 74 | to_delete_keys.append(key) | ||
73 | 75 | ||||
74 | for key in to_delete_keys: | 76 | for key in to_delete_keys: | ||
75 | del subtracted_effects[key] | 77 | del subtracted_effects[key] | ||
76 | del subtracted_intensity[key] | 78 | del subtracted_intensity[key] | ||
77 | 79 | ||||
78 | new_potion = Potion(subtracted_effects, self.duration) | 80 | new_potion = Potion(subtracted_effects, self.duration) | ||
79 | new_potion.intensity = dict(subtracted_intensity) | 81 | new_potion.intensity = dict(subtracted_intensity) | ||
80 | self.used = True | 82 | self.used = True | ||
81 | other.used = True | 83 | other.used = True | ||
82 | return new_potion | 84 | return new_potion | ||
n | 83 | n | 85 | ||
84 | def __truediv__(self, divisor): | 86 | def __truediv__(self, divisor): | ||
85 | if self.used: | 87 | if self.used: | ||
86 | raise TypeError("Potion is now part of something bigger than itself.") | 88 | raise TypeError("Potion is now part of something bigger than itself.") | ||
87 | 89 | ||||
88 | new_intensity = dict(self.intensity) | 90 | new_intensity = dict(self.intensity) | ||
89 | for key in self.intensity.keys(): | 91 | for key in self.intensity.keys(): | ||
90 | result_intensity = new_intensity[key]/divisor | 92 | result_intensity = new_intensity[key]/divisor | ||
91 | fraction, integer = math.modf(result_intensity) | 93 | fraction, integer = math.modf(result_intensity) | ||
92 | if fraction <= 0.5: | 94 | if fraction <= 0.5: | ||
93 | new_intensity[key] = float(math.floor(result_intensity)) | 95 | new_intensity[key] = float(math.floor(result_intensity)) | ||
94 | else: | 96 | else: | ||
95 | new_intensity[key] = float(math.ceil(result_intensity)) | 97 | new_intensity[key] = float(math.ceil(result_intensity)) | ||
96 | 98 | ||||
97 | new_potions = [] | 99 | new_potions = [] | ||
98 | for _ in range(divisor): | 100 | for _ in range(divisor): | ||
99 | new_potion = Potion(self.effects, self.duration) | 101 | new_potion = Potion(self.effects, self.duration) | ||
100 | new_potion.intensity = dict(new_intensity) | 102 | new_potion.intensity = dict(new_intensity) | ||
101 | new_potions.append(new_potion) | 103 | new_potions.append(new_potion) | ||
n | 102 | n | 104 | ||
103 | self.used = True | 105 | self.used = True | ||
104 | return new_potions | 106 | return new_potions | ||
n | 105 | n | 107 | ||
106 | def __eq__(self, other): | 108 | def __eq__(self, other): | ||
107 | if self.used or other.used: | 109 | if self.used or other.used: | ||
108 | raise TypeError("Potion is now part of something bigger than itself.") | 110 | raise TypeError("Potion is now part of something bigger than itself.") | ||
109 | equal_intensities = True | 111 | equal_intensities = True | ||
110 | for intensity_self_key, intensity_self_value in self.intensity.items(): | 112 | for intensity_self_key, intensity_self_value in self.intensity.items(): | ||
111 | for intensity_other_key, intensity_other_value in other.intensity.items(): | 113 | for intensity_other_key, intensity_other_value in other.intensity.items(): | ||
112 | if intensity_self_key == intensity_other_key: | 114 | if intensity_self_key == intensity_other_key: | ||
113 | if intensity_self_value != intensity_other_value: | 115 | if intensity_self_value != intensity_other_value: | ||
114 | equal_intensities = False | 116 | equal_intensities = False | ||
115 | return (all(effect in self.effects for effect in other.effects) and | 117 | return (all(effect in self.effects for effect in other.effects) and | ||
116 | all(effect in other.effects for effect in self.effects) and | 118 | all(effect in other.effects for effect in self.effects) and | ||
117 | equal_intensities) | 119 | equal_intensities) | ||
n | 118 | n | 120 | ||
119 | def __gt__(self, other): | 121 | def __gt__(self, other): | ||
120 | if self.used or other.used: | 122 | if self.used or other.used: | ||
121 | raise TypeError("Potion is now part of something bigger than itself.") | 123 | raise TypeError("Potion is now part of something bigger than itself.") | ||
n | 122 | n | 124 | ||
123 | sum_self = sum(self.intensity.values()) | 125 | sum_self = sum(self.intensity.values()) | ||
124 | sum_other = sum(other.intensity.values()) | 126 | sum_other = sum(other.intensity.values()) | ||
125 | return sum_self > sum_other | 127 | return sum_self > sum_other | ||
n | 126 | n | 128 | ||
127 | def __lt__(self, other): | 129 | def __lt__(self, other): | ||
128 | if self.used or other.used: | 130 | if self.used or other.used: | ||
129 | raise TypeError("Potion is now part of something bigger than itself.") | 131 | raise TypeError("Potion is now part of something bigger than itself.") | ||
n | 130 | n | 132 | ||
131 | sum_self = sum(self.intensity.values()) | 133 | sum_self = sum(self.intensity.values()) | ||
132 | sum_other = sum(other.intensity.values()) | 134 | sum_other = sum(other.intensity.values()) | ||
133 | return sum_self < sum_other | 135 | return sum_self < sum_other | ||
n | 134 | n | 136 | ||
135 | def apply_effect(self, target, effect): | 137 | def apply_effect(self, target, effect): | ||
136 | if self.used: | 138 | if self.used: | ||
137 | raise TypeError("Potion is now part of something bigger than itself.") | 139 | raise TypeError("Potion is now part of something bigger than itself.") | ||
138 | if self.used_effects[effect]: | 140 | if self.used_effects[effect]: | ||
139 | raise TypeError("Effect is depleted.") | 141 | raise TypeError("Effect is depleted.") | ||
n | 140 | for _ in range(int(self.intensity[effect])): | n | 142 | for _ in range(int(self.intensity[effect])): |
141 | self.effects[effect](target) | 143 | self.effects[effect](target) | ||
142 | self.used_effects[effect] = True | 144 | self.used_effects[effect] = True | ||
n | n | 145 | |||
143 | 146 | ||||
144 | class ГоспожатаПоХимия: | 147 | class ГоспожатаПоХимия: | ||
145 | 148 | ||||
146 | def __init__(self): | 149 | def __init__(self): | ||
147 | self.tick_count = 0 | 150 | self.tick_count = 0 | ||
148 | self.active_potions = {} | 151 | self.active_potions = {} | ||
149 | self.initial_states = {} | 152 | self.initial_states = {} | ||
150 | 153 | ||||
151 | def apply(self, target, potion): | 154 | def apply(self, target, potion): | ||
152 | if potion.used: | 155 | if potion.used: | ||
153 | raise TypeError("Potion is depleted.") | 156 | raise TypeError("Potion is depleted.") | ||
n | 154 | n | 157 | ||
155 | initial_state = copy.deepcopy(target) | 158 | initial_state = copy.deepcopy(target) | ||
156 | 159 | ||||
n | 157 | sorted_by_molecular_mass = sorted(potion.intensity.items(), key=lambda x: sum(ord(c) for c in x[0]), reverse=True) | n | 160 | sorted_by_molecular_mass = sorted(potion.intensity.items(), |
161 | key=lambda x: sum(ord(c) for c in x[0]), reverse=True) | ||||
158 | for effect in sorted_by_molecular_mass: | 162 | for effect in sorted_by_molecular_mass: | ||
159 | for _ in range(int(effect[1])): | 163 | for _ in range(int(effect[1])): | ||
160 | potion.apply_effect(target, effect[0]) | 164 | potion.apply_effect(target, effect[0]) | ||
161 | potion.start_duration = self.tick_count | 165 | potion.start_duration = self.tick_count | ||
162 | potion.end_duration = self.tick_count + potion.duration | 166 | potion.end_duration = self.tick_count + potion.duration | ||
n | 163 | n | 167 | ||
164 | """ | 168 | """ | ||
165 | if self.active_potions[id(target)]: | 169 | if self.active_potions[id(target)]: | ||
166 | self.active_potions[id(target)] = potion | 170 | self.active_potions[id(target)] = potion | ||
167 | self.initial_states[id(target)] = initial_state, target | 171 | self.initial_states[id(target)] = initial_state, target | ||
168 | """ | 172 | """ | ||
n | 169 | n | 173 | ||
170 | |||||
171 | def tick(self): | 174 | def tick(self): | ||
n | 172 | #collect all applied (potions : target) in a list and subtract their potion.active variables every tick | n | 175 | #collect all applied (potions : target) in a list and subtract |
176 | #their potion.active variables every tick | ||||
173 | #if a potion expires return to initial state of target | 177 | #if a potion expires return to initial state of target | ||
174 | self.tick_count += 1 | 178 | self.tick_count += 1 | ||
175 | 179 | ||||
n | 176 | expired_potions = {target_id:potion for target_id, potion in self.active_potions.items() | n | 180 | expired_potions = {target_id:potion for target_id, potion in self.active_potions.items() |
177 | if potion.end_duration <= self.tick_count} | 181 | if potion.end_duration <= self.tick_count} | ||
178 | 182 | ||||
t | 179 | t | |||
180 | sorted_by_start_time = sorted(expired_potions.items(), key=lambda x: x[1].start_duration) | 183 | sorted_by_start_time = sorted(expired_potions.items(), key=lambda x: x[1].start_duration) | ||
181 | """ | 184 | """ | ||
182 | for target_id, potion in sorted_by_start_time: | 185 | for target_id, potion in sorted_by_start_time: | ||
183 | if potion.end_duration <= self.tick_count: | 186 | if potion.end_duration <= self.tick_count: | ||
184 | 187 | ||||
185 | self.active_potions.pop() | 188 | self.active_potions.pop() | ||
186 | initial_state, target = self.initial_states.pop(target_id) | 189 | initial_state, target = self.initial_states.pop(target_id) | ||
187 | self.reset_target_to_initial_state(target, initial_state) | 190 | self.reset_target_to_initial_state(target, initial_state) | ||
188 | """ | 191 | """ | ||
189 | 192 | ||||
190 | def reset_target_to_initial_state(self, target, initial_state): | 193 | def reset_target_to_initial_state(self, target, initial_state): | ||
191 | target.__dict__.update(initial_state.__dict__) | 194 | target.__dict__.update(initial_state.__dict__) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|