Домашни > Работилница за отвари! > Решения > Решението на Веселина Велкова

Резултати
9 точки от тестове
1 точки от учител

10 точки общо

18 успешни теста
2 неуспешни теста
Код

  1import math
  2
  3
  4class Potion():
  5
  6    def __init__(self, effects, duration):
  7        self.duration = duration
  8        # self._effects will keep all of the effects that haven't been used.
  9        # self._intensity_effects will keep the intensities of all of the initial effects.
 10        self._effects = effects.copy()
 11        self.useless = False
 12        self._intensity_effects = {}
 13        self.potion_has_been_applied = False
 14        for name, effect in effects.items():
 15            self._intensity_effects[name] = 1
 16            setattr(self, name, staticmethod(self.multiplied_caller(name)))
 17
 18    def multiplied_caller(self, name):
 19        def wrapper(*args):
 20            for _ in range(self._intensity_effects[name]):
 21                self._effects[name](*args)
 22            self._intensity_effects[name] = 0
 23            del self._effects[name]
 24        return wrapper
 25
 26    def __getattribute__(self, name):
 27        checker_been_used = super().__getattribute__('_intensity_effects')
 28        if name not in checker_been_used.keys():
 29            return super().__getattribute__(name)
 30        elif super().__getattribute__('useless'):
 31            raise TypeError('Potion is now part of something bigger than itself.')
 32        elif super().__getattribute__('potion_has_been_applied'):
 33            raise TypeError('Potion is depleted.')
 34        elif name not in super().__getattribute__('_effects').keys():
 35            raise TypeError('Effect is depleted.')
 36        elif checker_been_used[name] >= 0:
 37            return super().__getattribute__(name)
 38
 39    def set_intensity_effects(self, intensity_dict):
 40        self._intensity_effects = intensity_dict.copy()
 41
 42    def __add__(self, other):
 43        if self.useless or other.useless:
 44            raise TypeError('Potion is now part of something bigger than itself.')
 45        if not self._effects or not other._effects:
 46            raise TypeError('Potion is depleted.')
 47
 48        combo_effects = {}
 49        new_intensity = {}
 50        for key, value in self._effects.items():
 51            if key in new_intensity.keys():
 52                new_intensity[key] += self._intensity_effects[key]
 53            else:
 54                combo_effects[key] = value
 55                new_intensity[key] = self._intensity_effects[key]
 56        for key, value in other._effects.items():
 57            if key in new_intensity.keys():
 58                new_intensity[key] += other._intensity_effects[key]
 59            else:
 60                combo_effects[key] = value
 61                new_intensity[key] = other._intensity_effects[key]
 62        self.useless = True
 63        other.useless = True
 64        result = Potion(combo_effects, max(self.duration, other.duration))
 65        result.set_intensity_effects(new_intensity)
 66        return result
 67
 68    def __mul__(self, num):
 69        if self.useless:
 70            raise TypeError('Potion is now part of something bigger than itself.')
 71        if not self._effects:
 72            raise TypeError('Potion is depleted.')
 73
 74        new_intensity = {}
 75        for key in self._effects.keys():
 76            new_intensity[key] = self._rounding(self._intensity_effects[key] * num)
 77        multiplied_potion = Potion(self._effects, self.duration)
 78        multiplied_potion.set_intensity_effects(new_intensity)
 79        self.useless = True
 80        return multiplied_potion
 81
 82    def __truediv__(self, num):
 83        if self.useless:
 84            raise TypeError('Potion is now part of something bigger than itself.')
 85        if not self._effects:
 86            raise TypeError('Potion is depleted.')
 87
 88        new_intensity = {}
 89        for key in self._effects.keys():
 90            new_intensity[key] = self._rounding(self._intensity_effects[key] / num)
 91        devided_tuple = tuple()
 92        for _ in range(num):
 93            devided_potion = Potion(self._effects, self.duration)
 94            devided_potion.set_intensity_effects(new_intensity)
 95            devided_tuple = devided_tuple + (devided_potion, )
 96        self.useless = True
 97        return devided_tuple
 98
 99    def __sub__(self, other):
100        if self.useless or other.useless:
101            raise TypeError('Potion is now part of something bigger than itself.')
102        if not self._effects or not other._effects:
103            raise TypeError('Potion is depleted.')
104
105        new_effects = self._effects.copy()
106        new_intensity = self._intensity_effects.copy()
107        for effect in other._intensity_effects.keys():
108            if effect not in self._intensity_effects:
109                raise TypeError("Upssie! You can't take from me something I don't have :)")
110            else:
111                new_intensity[effect] -= other._intensity_effects[effect]
112                if new_intensity[effect] <= 0:
113                    del new_intensity[effect]
114                    try:
115                        del new_effects[effect]
116                    except KeyError:
117                        # If the effect has been used it no longer exists in self._effects
118                        pass
119        self.useless = True
120        other.useless = True
121        result = Potion(new_effects, self.duration)
122        result.set_intensity_effects(new_intensity)
123        return result
124
125    def get_sum_intensities(self):
126        sum_intensity = 0
127        for value in self._intensity_effects.values():
128            sum_intensity += value
129        return sum_intensity
130
131    def __lt__(self, other):
132        self_sum = self.get_sum_intensities()
133        other_sum = other.get_sum_intensities()
134        if not self._effects or not other._effects:
135            raise TypeError('Potion is depleted.')
136        if self.useless or other.useless:
137            raise TypeError('Potion is now part of something bigger than itself.')
138        return self_sum < other_sum
139
140    def __gt__(self, other):
141        self_sum = self.get_sum_intensities()
142        other_sum = other.get_sum_intensities()
143        if not self._effects or not other._effects:
144            raise TypeError('Potion is depleted.')
145        if self.useless or other.useless:
146            raise TypeError('Potion is now part of something bigger than itself.')
147        return self_sum > other_sum
148
149    def __eq__(self, other):
150        if not self._effects or not other._effects:
151            raise TypeError('Potion is depleted.')
152        if self.useless or other.useless:
153            raise TypeError('Potion is now part of something bigger than itself.')
154        return self._intensity_effects == other._intensity_effects
155
156    @staticmethod
157    def _get_mass(name):
158        mass = 0
159        for chr in name:
160            mass += ord(chr)
161        return mass
162
163    def _order_effect_keys_by_mass(self):
164        sorted_effects = sorted(self._effects.keys(), key=self._get_mass, reverse=True)
165        return sorted_effects
166
167    @staticmethod
168    def _rounding(num):
169        return math.ceil(num - 0.5)
170
171    __rmul__ = __mul__
172    __radd__ = __add__
173
174
175class ГоспожатаПоХимия:
176
177    def __init__(self):
178        self.effects_duration = []
179        self.test_bunnies = []
180        self.future_effects = []
181        self.future_intensities = []
182        self.backup = []
183
184    def apply(self, target, potion):
185        if potion.useless:
186            raise TypeError('Potion is now part of something bigger than itself.')
187        if not potion._effects:
188            raise TypeError('Potion is depleted.')
189        potion.potion_has_been_applied = True
190
191        if potion.duration == 0:
192            potion._effects = {}
193            for key in potion._intensity_effects.keys():
194                potion._intensity_effects[key] = 0
195            return
196
197        # Create a backup of the current state of the target,
198        # so that we can restore it after the duration of the potion.
199        self.backup.append(target.__dict__.copy())
200
201        effects = potion._order_effect_keys_by_mass()
202        self.future_effects.append([potion._effects[effect] for effect in effects])
203        self.future_intensities.append([potion._intensity_effects[effect] for effect in effects])
204        for effect in effects:
205            potion.multiplied_caller(effect)(target)
206        self.effects_duration.append(potion.duration)
207        self.test_bunnies.append(target)
208
209    def tick(self):
210        for index in range(len(self.test_bunnies)):
211            self.effects_duration[index] -= 1
212            if self.effects_duration[index] < 0:
213                pass
214            elif self.effects_duration[index] == 0:
215                self.test_bunnies[index].__dict__ = self.backup[index]
216                self.redo_damaged_targets(index)
217
218    def redo_damaged_targets(self, reverted_index):
219        for index in range(len(self.effects_duration)):
220            if index != reverted_index and self.effects_duration[index] > 0:
221                # Make the current state basis for the effects.
222                self.backup[index] = self.test_bunnies[reverted_index].__dict__.copy()
223                for effect, intensity in zip(self.future_effects[index], self.future_intensities[index]):
224                    for _ in range(intensity):
225                        effect(self.test_bunnies[reverted_index])

..................FF
======================================================================
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: 50 != 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 446, in test_ticking_mutable
self.assertEqual(self._target.list_attr, [1, 2, 3])
AssertionError: Lists differ: [1, 2, 3, 4] != [1, 2, 3]

First list contains 1 additional elements.
First extra element 3:
4

- [1, 2, 3, 4]
? ---

+ [1, 2, 3]

----------------------------------------------------------------------
Ran 20 tests in 0.003s

FAILED (failures=2)

Дискусия
Георги Кунчев
05.12.2023 18:47

Нямам забележки. Добра работа!
История

f1import mathf1import math
22
33
4class Potion():4class Potion():
55
6    def __init__(self, effects, duration):6    def __init__(self, effects, duration):
7        self.duration = duration7        self.duration = duration
8        # self._effects will keep all of the effects that haven't been used.8        # self._effects will keep all of the effects that haven't been used.
9        # self._intensity_effects will keep the intensities of all of the initial effects.9        # self._intensity_effects will keep the intensities of all of the initial effects.
10        self._effects = effects.copy()10        self._effects = effects.copy()
11        self.useless = False11        self.useless = False
12        self._intensity_effects = {}12        self._intensity_effects = {}
13        self.potion_has_been_applied = False13        self.potion_has_been_applied = False
14        for name, effect in effects.items():14        for name, effect in effects.items():
15            self._intensity_effects[name] = 115            self._intensity_effects[name] = 1
16            setattr(self, name, staticmethod(self.multiplied_caller(name)))16            setattr(self, name, staticmethod(self.multiplied_caller(name)))
1717
18    def multiplied_caller(self, name):18    def multiplied_caller(self, name):
19        def wrapper(*args):19        def wrapper(*args):
20            for _ in range(self._intensity_effects[name]):20            for _ in range(self._intensity_effects[name]):
21                self._effects[name](*args)21                self._effects[name](*args)
22            self._intensity_effects[name] = 022            self._intensity_effects[name] = 0
23            del self._effects[name]23            del self._effects[name]
24        return wrapper24        return wrapper
2525
26    def __getattribute__(self, name):26    def __getattribute__(self, name):
27        checker_been_used = super().__getattribute__('_intensity_effects')27        checker_been_used = super().__getattribute__('_intensity_effects')
28        if name not in checker_been_used.keys():28        if name not in checker_been_used.keys():
29            return super().__getattribute__(name)29            return super().__getattribute__(name)
30        elif super().__getattribute__('useless'):30        elif super().__getattribute__('useless'):
31            raise TypeError('Potion is now part of something bigger than itself.')31            raise TypeError('Potion is now part of something bigger than itself.')
32        elif super().__getattribute__('potion_has_been_applied'):32        elif super().__getattribute__('potion_has_been_applied'):
33            raise TypeError('Potion is depleted.')33            raise TypeError('Potion is depleted.')
34        elif name not in super().__getattribute__('_effects').keys():34        elif name not in super().__getattribute__('_effects').keys():
35            raise TypeError('Effect is depleted.')35            raise TypeError('Effect is depleted.')
36        elif checker_been_used[name] >= 0:36        elif checker_been_used[name] >= 0:
37            return super().__getattribute__(name)37            return super().__getattribute__(name)
3838
39    def set_intensity_effects(self, intensity_dict):39    def set_intensity_effects(self, intensity_dict):
40        self._intensity_effects = intensity_dict.copy()40        self._intensity_effects = intensity_dict.copy()
4141
42    def __add__(self, other):42    def __add__(self, other):
43        if self.useless or other.useless:43        if self.useless or other.useless:
44            raise TypeError('Potion is now part of something bigger than itself.')44            raise TypeError('Potion is now part of something bigger than itself.')
45        if not self._effects or not other._effects:45        if not self._effects or not other._effects:
46            raise TypeError('Potion is depleted.')46            raise TypeError('Potion is depleted.')
4747
48        combo_effects = {}48        combo_effects = {}
49        new_intensity = {}49        new_intensity = {}
50        for key, value in self._effects.items():50        for key, value in self._effects.items():
51            if key in new_intensity.keys():51            if key in new_intensity.keys():
52                new_intensity[key] += self._intensity_effects[key]52                new_intensity[key] += self._intensity_effects[key]
53            else:53            else:
54                combo_effects[key] = value54                combo_effects[key] = value
55                new_intensity[key] = self._intensity_effects[key]55                new_intensity[key] = self._intensity_effects[key]
56        for key, value in other._effects.items():56        for key, value in other._effects.items():
57            if key in new_intensity.keys():57            if key in new_intensity.keys():
58                new_intensity[key] += other._intensity_effects[key]58                new_intensity[key] += other._intensity_effects[key]
59            else:59            else:
60                combo_effects[key] = value60                combo_effects[key] = value
61                new_intensity[key] = other._intensity_effects[key]61                new_intensity[key] = other._intensity_effects[key]
62        self.useless = True62        self.useless = True
63        other.useless = True63        other.useless = True
64        result = Potion(combo_effects, max(self.duration, other.duration))64        result = Potion(combo_effects, max(self.duration, other.duration))
65        result.set_intensity_effects(new_intensity)65        result.set_intensity_effects(new_intensity)
66        return result66        return result
6767
68    def __mul__(self, num):68    def __mul__(self, num):
69        if self.useless:69        if self.useless:
70            raise TypeError('Potion is now part of something bigger than itself.')70            raise TypeError('Potion is now part of something bigger than itself.')
71        if not self._effects:71        if not self._effects:
72            raise TypeError('Potion is depleted.')72            raise TypeError('Potion is depleted.')
7373
74        new_intensity = {}74        new_intensity = {}
75        for key in self._effects.keys():75        for key in self._effects.keys():
76            new_intensity[key] = self._rounding(self._intensity_effects[key] * num)76            new_intensity[key] = self._rounding(self._intensity_effects[key] * num)
77        multiplied_potion = Potion(self._effects, self.duration)77        multiplied_potion = Potion(self._effects, self.duration)
78        multiplied_potion.set_intensity_effects(new_intensity)78        multiplied_potion.set_intensity_effects(new_intensity)
79        self.useless = True79        self.useless = True
80        return multiplied_potion80        return multiplied_potion
8181
82    def __truediv__(self, num):82    def __truediv__(self, num):
83        if self.useless:83        if self.useless:
84            raise TypeError('Potion is now part of something bigger than itself.')84            raise TypeError('Potion is now part of something bigger than itself.')
85        if not self._effects:85        if not self._effects:
86            raise TypeError('Potion is depleted.')86            raise TypeError('Potion is depleted.')
8787
88        new_intensity = {}88        new_intensity = {}
89        for key in self._effects.keys():89        for key in self._effects.keys():
90            new_intensity[key] = self._rounding(self._intensity_effects[key] / num)90            new_intensity[key] = self._rounding(self._intensity_effects[key] / num)
91        devided_tuple = tuple()91        devided_tuple = tuple()
92        for _ in range(num):92        for _ in range(num):
93            devided_potion = Potion(self._effects, self.duration)93            devided_potion = Potion(self._effects, self.duration)
94            devided_potion.set_intensity_effects(new_intensity)94            devided_potion.set_intensity_effects(new_intensity)
95            devided_tuple = devided_tuple + (devided_potion, )95            devided_tuple = devided_tuple + (devided_potion, )
96        self.useless = True96        self.useless = True
97        return devided_tuple97        return devided_tuple
9898
99    def __sub__(self, other):99    def __sub__(self, other):
100        if self.useless or other.useless:100        if self.useless or other.useless:
101            raise TypeError('Potion is now part of something bigger than itself.')101            raise TypeError('Potion is now part of something bigger than itself.')
102        if not self._effects or not other._effects:102        if not self._effects or not other._effects:
103            raise TypeError('Potion is depleted.')103            raise TypeError('Potion is depleted.')
104104
105        new_effects = self._effects.copy()105        new_effects = self._effects.copy()
106        new_intensity = self._intensity_effects.copy()106        new_intensity = self._intensity_effects.copy()
107        for effect in other._intensity_effects.keys():107        for effect in other._intensity_effects.keys():
108            if effect not in self._intensity_effects:108            if effect not in self._intensity_effects:
109                raise TypeError("Upssie! You can't take from me something I don't have :)")109                raise TypeError("Upssie! You can't take from me something I don't have :)")
110            else:110            else:
111                new_intensity[effect] -= other._intensity_effects[effect]111                new_intensity[effect] -= other._intensity_effects[effect]
112                if new_intensity[effect] <= 0:112                if new_intensity[effect] <= 0:
113                    del new_intensity[effect]113                    del new_intensity[effect]
114                    try:114                    try:
115                        del new_effects[effect]115                        del new_effects[effect]
116                    except KeyError:116                    except KeyError:
117                        # If the effect has been used it no longer exists in self._effects117                        # If the effect has been used it no longer exists in self._effects
118                        pass118                        pass
119        self.useless = True119        self.useless = True
120        other.useless = True120        other.useless = True
121        result = Potion(new_effects, self.duration)121        result = Potion(new_effects, self.duration)
122        result.set_intensity_effects(new_intensity)122        result.set_intensity_effects(new_intensity)
123        return result123        return result
124124
125    def get_sum_intensities(self):125    def get_sum_intensities(self):
126        sum_intensity = 0126        sum_intensity = 0
127        for value in self._intensity_effects.values():127        for value in self._intensity_effects.values():
128            sum_intensity += value128            sum_intensity += value
129        return sum_intensity129        return sum_intensity
130130
131    def __lt__(self, other):131    def __lt__(self, other):
132        self_sum = self.get_sum_intensities()132        self_sum = self.get_sum_intensities()
133        other_sum = other.get_sum_intensities()133        other_sum = other.get_sum_intensities()
134        if not self._effects or not other._effects:134        if not self._effects or not other._effects:
135            raise TypeError('Potion is depleted.')135            raise TypeError('Potion is depleted.')
136        if self.useless or other.useless:136        if self.useless or other.useless:
137            raise TypeError('Potion is now part of something bigger than itself.')137            raise TypeError('Potion is now part of something bigger than itself.')
138        return self_sum < other_sum138        return self_sum < other_sum
139139
140    def __gt__(self, other):140    def __gt__(self, other):
141        self_sum = self.get_sum_intensities()141        self_sum = self.get_sum_intensities()
142        other_sum = other.get_sum_intensities()142        other_sum = other.get_sum_intensities()
143        if not self._effects or not other._effects:143        if not self._effects or not other._effects:
144            raise TypeError('Potion is depleted.')144            raise TypeError('Potion is depleted.')
145        if self.useless or other.useless:145        if self.useless or other.useless:
146            raise TypeError('Potion is now part of something bigger than itself.')146            raise TypeError('Potion is now part of something bigger than itself.')
147        return self_sum > other_sum147        return self_sum > other_sum
148148
149    def __eq__(self, other):149    def __eq__(self, other):
150        if not self._effects or not other._effects:150        if not self._effects or not other._effects:
151            raise TypeError('Potion is depleted.')151            raise TypeError('Potion is depleted.')
152        if self.useless or other.useless:152        if self.useless or other.useless:
153            raise TypeError('Potion is now part of something bigger than itself.')153            raise TypeError('Potion is now part of something bigger than itself.')
154        return self._intensity_effects == other._intensity_effects154        return self._intensity_effects == other._intensity_effects
155155
156    @staticmethod156    @staticmethod
157    def _get_mass(name):157    def _get_mass(name):
158        mass = 0158        mass = 0
159        for chr in name:159        for chr in name:
160            mass += ord(chr)160            mass += ord(chr)
161        return mass161        return mass
162162
163    def _order_effect_keys_by_mass(self):163    def _order_effect_keys_by_mass(self):
164        sorted_effects = sorted(self._effects.keys(), key=self._get_mass, reverse=True)164        sorted_effects = sorted(self._effects.keys(), key=self._get_mass, reverse=True)
165        return sorted_effects165        return sorted_effects
166166
167    @staticmethod167    @staticmethod
168    def _rounding(num):168    def _rounding(num):
169        return math.ceil(num - 0.5)169        return math.ceil(num - 0.5)
170170
171    __rmul__ = __mul__171    __rmul__ = __mul__
172    __radd__ = __add__172    __radd__ = __add__
173173
174174
175class ГоспожатаПоХимия:175class ГоспожатаПоХимия:
176176
177    def __init__(self):177    def __init__(self):
178        self.effects_duration = []178        self.effects_duration = []
179        self.test_bunnies = []179        self.test_bunnies = []
180        self.future_effects = []180        self.future_effects = []
181        self.future_intensities = []181        self.future_intensities = []
182        self.backup = []182        self.backup = []
183183
184    def apply(self, target, potion):184    def apply(self, target, potion):
n185        # Create a backup of the current state of the target,n
186        # so that we can restore it after the duration of the potion.
187        if potion.useless:185        if potion.useless:
188            raise TypeError('Potion is now part of something bigger than itself.')186            raise TypeError('Potion is now part of something bigger than itself.')
189        if not potion._effects:187        if not potion._effects:
190            raise TypeError('Potion is depleted.')188            raise TypeError('Potion is depleted.')
191        potion.potion_has_been_applied = True189        potion.potion_has_been_applied = True
192190
193        if potion.duration == 0:191        if potion.duration == 0:
194            potion._effects = {}192            potion._effects = {}
195            for key in potion._intensity_effects.keys():193            for key in potion._intensity_effects.keys():
196                potion._intensity_effects[key] = 0194                potion._intensity_effects[key] = 0
197            return195            return
198196
nn197        # Create a backup of the current state of the target,
198        # so that we can restore it after the duration of the potion.
199        self.backup.append(target.__dict__.copy())199        self.backup.append(target.__dict__.copy())
200200
201        effects = potion._order_effect_keys_by_mass()201        effects = potion._order_effect_keys_by_mass()
202        self.future_effects.append([potion._effects[effect] for effect in effects])202        self.future_effects.append([potion._effects[effect] for effect in effects])
203        self.future_intensities.append([potion._intensity_effects[effect] for effect in effects])203        self.future_intensities.append([potion._intensity_effects[effect] for effect in effects])
204        for effect in effects:204        for effect in effects:
205            potion.multiplied_caller(effect)(target)205            potion.multiplied_caller(effect)(target)
206        self.effects_duration.append(potion.duration)206        self.effects_duration.append(potion.duration)
207        self.test_bunnies.append(target)207        self.test_bunnies.append(target)
208208
209    def tick(self):209    def tick(self):
210        for index in range(len(self.test_bunnies)):210        for index in range(len(self.test_bunnies)):
211            self.effects_duration[index] -= 1211            self.effects_duration[index] -= 1
212            if self.effects_duration[index] < 0:212            if self.effects_duration[index] < 0:
213                pass213                pass
214            elif self.effects_duration[index] == 0:214            elif self.effects_duration[index] == 0:
215                self.test_bunnies[index].__dict__ = self.backup[index]215                self.test_bunnies[index].__dict__ = self.backup[index]
216                self.redo_damaged_targets(index)216                self.redo_damaged_targets(index)
217217
218    def redo_damaged_targets(self, reverted_index):218    def redo_damaged_targets(self, reverted_index):
219        for index in range(len(self.effects_duration)):219        for index in range(len(self.effects_duration)):
220            if index != reverted_index and self.effects_duration[index] > 0:220            if index != reverted_index and self.effects_duration[index] > 0:
tt221                # Make the current state basis for the effects.
221                self.backup[index] = self.test_bunnies[reverted_index].__dict__.copy()222                self.backup[index] = self.test_bunnies[reverted_index].__dict__.copy()
222                for effect, intensity in zip(self.future_effects[index], self.future_intensities[index]):223                for effect, intensity in zip(self.future_effects[index], self.future_intensities[index]):
223                    for _ in range(intensity):224                    for _ in range(intensity):
224                        effect(self.test_bunnies[reverted_index])225                        effect(self.test_bunnies[reverted_index])
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op