Домашни > Работилница за отвари! > Решения > Решението на Николай Георгиев

Резултати
7 точки от тестове
0 точки от учител

7 точки общо

14 успешни теста
6 неуспешни теста
Код
Скрий всички коментари

  1class Effect:
  2    def __init__(self, effect):
  3        self.effect = effect
  4        self.intensity = 1
  5    
  6    def __call__(self, target):
  7        effect = self.effect
  8        result = None
  9        
 10        while self.intensity > 0:
 11            result = effect(target)
 12            self.intensity -= 1
 13        self.intensity = -1
 14        return result
 15
 16
 17class Potion:
 18    def __init__(self, effects, duration):
 19        self.duration = duration
 20        self.used = False
 21        self.is_depleted = False
 22        if isinstance(next(iter(effects.values())), Effect):
 23            self.effects = effects
 24        else:
 25            effects_object = {}
 26            for effect_name, effect in effects.items():
 27                effects_object[effect_name] = Effect(effect)
 28            self.effects = effects_object
 29    
 30    def _create_effects(self, effects):
 31        effects_object = {}
 32        for effect_name, effect in effects.items():
 33            effects_object[effect_name] = Effect(effect.effect) if (isinstance(effect, Effect)) else Effect(effect)
 34        return effects_object
 35
 36    def __add__(self, potion):
 37        combined_effects = self._create_effects(self.effects)
 38        for effect_name, effect in potion.effects.items():
 39            if effect_name in combined_effects:
 40                combined_effects[effect_name].intensity += 1
 41            else:
 42                combined_effects[effect_name] = Effect(effect)
 43        self.used = True
 44        potion.used =True
 45        return Potion(combined_effects, max(self.duration, potion.duration))
 46    
 47    def __mul__(self, intensity):
 48        def enchance(effect):
 49            effect.intensity *= intensity
 50
 51        def downgrade(effect):
 52            new_intesity = effect.intensity * intensity
 53            effect.intensity = int(new_intesity) if new_intesity % 1 <= 0.5 else int(new_intesity + 1)
 54        
 55        enchanced_effects = self._create_effects(self.effects)
 56
 57        if intensity <= 1:
 58            for effect_name, effect in enchanced_effects.items():
 59                effect.intensity = self.effects[effect_name].intensity
 60
 61        action = enchance if intensity > 1 else downgrade
 62        for effect in enchanced_effects.values():
 63            action(effect)
 64        self.used = True
 65        return Potion(enchanced_effects, self.duration)
 66    
 67    def __sub__(self, potion):
 68        def is_valid_effect(effect_name, effect):
 69            if effect_name in potion.effects.keys():
 70                if effect.intensity > 1:
 71                    effect.intensity -= potion.effects[effect_name].intensity
 72                    return effect.intensity > 0
 73                return False
 74            return True
 75        
 76        if any(map(lambda effect: effect not in self.effects.keys(), potion.effects.keys())):
 77            raise TypeError("Ко? Не.")
 78        
 79        effects = self._create_effects(self.effects)
 80        filtered_effects = {effect_name: effect for effect_name, effect in effects.items() if is_valid_effect(effect_name, effect)}
 81        self.used = True
 82        potion.used =True
 83        return Potion(filtered_effects, self.duration)
 84
 85    def __truediv__(self, divider):
 86        new_potions = []
 87        intensity_coefficient = 1 / divider
 88        self.is_divided = True
 89        for _ in range(divider):
 90            new_potions.append(self * intensity_coefficient)
 91        self.used = True
 92        return new_potions
 93    
 94    def __eq__(self, potion):
 95        return all(
 96            list(map(
 97                lambda effect: effect in self.effects.keys() and potion.effects[effect].intensity == self.effects[effect].intensity, 
 98                potion.effects.keys()
 99            ))
100        )
101    
102    def __gt__(self, other_potion):
103        return self.get_score() > other_potion.get_score()
104    
105    def __lt__(self, other_potion):
106        return self.get_score() < other_potion.get_score()
107    
108    def __getattribute__(self, name):
109        effects = object.__getattribute__(self, 'effects')
110        if name in effects:
111            if effects[name].intensity < 0:
112                raise TypeError("Effect is depleted.")
113            self.check_validity()
114            return effects[name]
115        return object.__getattribute__(self, name)
116    
117    def check_validity(self):
118        if self.used:
119                raise TypeError("Potion is now part of something bigger than itself.")
120        is_depleted = True
121        for effect in self.effects.values():
122            if (effect.intensity >= 0):
123                is_depleted = False
124                break
125        if is_depleted:
126            self.is_depleted = is_depleted
127            raise TypeError("Potion is depleted.")
128    
129    def get_score(potion):
130        return sum(getattr(potion, effect).intensity for effect in potion.effects if getattr(potion, effect, False))
131    
132
133class ГоспожатаПоХимия:
134    def __init__(self):
135        self.ticks_effects_end = {}
136        self.timer = 0
137
138    def tick(self):
139        self.timer += 1
140        if self.timer not in self.ticks_effects_end:
141            return
142        
143        for target_data in self.ticks_effects_end[self.timer]:
144            target = target_data["target"]
145            for state_name, state in target_data["target_changes"].items():
146                setattr(target, state_name, state)
147    
148    def apply(self, target, potion):
149        potion.check_validity()
150
151        effects_tuples = sorted(potion.effects.items(), key = lambda item: sum([ord(char) for char in item[0]]), reverse = True)
152        effects = {effect_tuple[0]: effect_tuple[1] for effect_tuple in effects_tuples}
153
154        for effect in effects.values():
155            end_time = self.timer + potion.duration
156            if end_time not in self.ticks_effects_end:
157                self.ticks_effects_end[end_time] = []
158            target_dict = dict(target.__dict__)
159            try:
160                for _ in range(effect.intensity):
161                    effect(target)
162                target_changes = {key: target_dict[key] for key, value in target.__dict__.items() if target_dict[key] != value}
163                target_changes.update({key: 0 for key in target.__dict__.keys() if key not in target_dict})
164
165                self.ticks_effects_end[end_time].append({
166                    "target": target,
167                    "target_changes": target_changes
168                })
169            except TypeError:
170                raise TypeError("Potion is depleted.")

..E....E..E.F....F.F
======================================================================
ERROR: test_empty (test.TestBasicPotion)
Test initialization with empty effects.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 53, in test_empty
potion = Potion({}, duration=0)
File "/tmp/solution.py", line 22, in __init__
if isinstance(next(iter(effects.values())), Effect):
StopIteration

======================================================================
ERROR: test_deprecation (test.TestPotionOperations)
Test deprecation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 269, in test_deprecation
potion = potion1 - potion2
File "/tmp/solution.py", line 83, in __sub__
return Potion(filtered_effects, self.duration)
File "/tmp/solution.py", line 22, in __init__
if isinstance(next(iter(effects.values())), Effect):
StopIteration

======================================================================
ERROR: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 190, in test_purification
potion.int_attr_fun(self._target)
File "/tmp/solution.py", line 115, in __getattribute__
return object.__getattribute__(self, name)
AttributeError: 'Potion' object has no attribute 'int_attr_fun'

======================================================================
FAIL: test_applying_depleted_potion (test.TestГоспожатаПоХимия)
Test applying a depleted potion or a potion that was used in a reaction.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 382, in test_applying_depleted_potion
with self.assertRaisesRegex(TypeError, 'Potion is depleted\.'):
AssertionError: TypeError not raised

======================================================================
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

======================================================================
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.002s

FAILED (failures=3, errors=3)

Дискусия
Виктор Бечев
04.12.2023 15:09

Нямам стилови забележки. Има тук таме някой друг ред който се чете по-трудно, но на повечето места е чисто визуално, а не непременно защото е сложна логика.
История

f1class Effect:f1class Effect:
2    def __init__(self, effect):2    def __init__(self, effect):
3        self.effect = effect3        self.effect = effect
4        self.intensity = 14        self.intensity = 1
5    5    
6    def __call__(self, target):6    def __call__(self, target):
7        effect = self.effect7        effect = self.effect
8        result = None8        result = None
9        9        
10        while self.intensity > 0:10        while self.intensity > 0:
11            result = effect(target)11            result = effect(target)
12            self.intensity -= 112            self.intensity -= 1
13        self.intensity = -113        self.intensity = -1
14        return result14        return result
1515
1616
17class Potion:17class Potion:
18    def __init__(self, effects, duration):18    def __init__(self, effects, duration):
19        self.duration = duration19        self.duration = duration
20        self.used = False20        self.used = False
21        self.is_depleted = False21        self.is_depleted = False
22        if isinstance(next(iter(effects.values())), Effect):22        if isinstance(next(iter(effects.values())), Effect):
23            self.effects = effects23            self.effects = effects
24        else:24        else:
25            effects_object = {}25            effects_object = {}
26            for effect_name, effect in effects.items():26            for effect_name, effect in effects.items():
27                effects_object[effect_name] = Effect(effect)27                effects_object[effect_name] = Effect(effect)
28            self.effects = effects_object28            self.effects = effects_object
29    29    
30    def _create_effects(self, effects):30    def _create_effects(self, effects):
31        effects_object = {}31        effects_object = {}
32        for effect_name, effect in effects.items():32        for effect_name, effect in effects.items():
33            effects_object[effect_name] = Effect(effect.effect) if (isinstance(effect, Effect)) else Effect(effect)33            effects_object[effect_name] = Effect(effect.effect) if (isinstance(effect, Effect)) else Effect(effect)
34        return effects_object34        return effects_object
3535
36    def __add__(self, potion):36    def __add__(self, potion):
37        combined_effects = self._create_effects(self.effects)37        combined_effects = self._create_effects(self.effects)
38        for effect_name, effect in potion.effects.items():38        for effect_name, effect in potion.effects.items():
39            if effect_name in combined_effects:39            if effect_name in combined_effects:
40                combined_effects[effect_name].intensity += 140                combined_effects[effect_name].intensity += 1
41            else:41            else:
42                combined_effects[effect_name] = Effect(effect)42                combined_effects[effect_name] = Effect(effect)
43        self.used = True43        self.used = True
44        potion.used =True44        potion.used =True
45        return Potion(combined_effects, max(self.duration, potion.duration))45        return Potion(combined_effects, max(self.duration, potion.duration))
46    46    
47    def __mul__(self, intensity):47    def __mul__(self, intensity):
48        def enchance(effect):48        def enchance(effect):
49            effect.intensity *= intensity49            effect.intensity *= intensity
5050
51        def downgrade(effect):51        def downgrade(effect):
52            new_intesity = effect.intensity * intensity52            new_intesity = effect.intensity * intensity
53            effect.intensity = int(new_intesity) if new_intesity % 1 <= 0.5 else int(new_intesity + 1)53            effect.intensity = int(new_intesity) if new_intesity % 1 <= 0.5 else int(new_intesity + 1)
54        54        
55        enchanced_effects = self._create_effects(self.effects)55        enchanced_effects = self._create_effects(self.effects)
5656
57        if intensity <= 1:57        if intensity <= 1:
58            for effect_name, effect in enchanced_effects.items():58            for effect_name, effect in enchanced_effects.items():
59                effect.intensity = self.effects[effect_name].intensity59                effect.intensity = self.effects[effect_name].intensity
6060
61        action = enchance if intensity > 1 else downgrade61        action = enchance if intensity > 1 else downgrade
62        for effect in enchanced_effects.values():62        for effect in enchanced_effects.values():
63            action(effect)63            action(effect)
64        self.used = True64        self.used = True
65        return Potion(enchanced_effects, self.duration)65        return Potion(enchanced_effects, self.duration)
66    66    
67    def __sub__(self, potion):67    def __sub__(self, potion):
68        def is_valid_effect(effect_name, effect):68        def is_valid_effect(effect_name, effect):
69            if effect_name in potion.effects.keys():69            if effect_name in potion.effects.keys():
70                if effect.intensity > 1:70                if effect.intensity > 1:
71                    effect.intensity -= potion.effects[effect_name].intensity71                    effect.intensity -= potion.effects[effect_name].intensity
72                    return effect.intensity > 072                    return effect.intensity > 0
73                return False73                return False
74            return True74            return True
75        75        
76        if any(map(lambda effect: effect not in self.effects.keys(), potion.effects.keys())):76        if any(map(lambda effect: effect not in self.effects.keys(), potion.effects.keys())):
77            raise TypeError("Ко? Не.")77            raise TypeError("Ко? Не.")
78        78        
79        effects = self._create_effects(self.effects)79        effects = self._create_effects(self.effects)
80        filtered_effects = {effect_name: effect for effect_name, effect in effects.items() if is_valid_effect(effect_name, effect)}80        filtered_effects = {effect_name: effect for effect_name, effect in effects.items() if is_valid_effect(effect_name, effect)}
81        self.used = True81        self.used = True
82        potion.used =True82        potion.used =True
83        return Potion(filtered_effects, self.duration)83        return Potion(filtered_effects, self.duration)
8484
85    def __truediv__(self, divider):85    def __truediv__(self, divider):
86        new_potions = []86        new_potions = []
87        intensity_coefficient = 1 / divider87        intensity_coefficient = 1 / divider
88        self.is_divided = True88        self.is_divided = True
89        for _ in range(divider):89        for _ in range(divider):
90            new_potions.append(self * intensity_coefficient)90            new_potions.append(self * intensity_coefficient)
91        self.used = True91        self.used = True
92        return new_potions92        return new_potions
93    93    
94    def __eq__(self, potion):94    def __eq__(self, potion):
95        return all(95        return all(
96            list(map(96            list(map(
97                lambda effect: effect in self.effects.keys() and potion.effects[effect].intensity == self.effects[effect].intensity, 97                lambda effect: effect in self.effects.keys() and potion.effects[effect].intensity == self.effects[effect].intensity, 
98                potion.effects.keys()98                potion.effects.keys()
99            ))99            ))
100        )100        )
101    101    
102    def __gt__(self, other_potion):102    def __gt__(self, other_potion):
103        return self.get_score() > other_potion.get_score()103        return self.get_score() > other_potion.get_score()
104    104    
105    def __lt__(self, other_potion):105    def __lt__(self, other_potion):
106        return self.get_score() < other_potion.get_score()106        return self.get_score() < other_potion.get_score()
107    107    
108    def __getattribute__(self, name):108    def __getattribute__(self, name):
109        effects = object.__getattribute__(self, 'effects')109        effects = object.__getattribute__(self, 'effects')
110        if name in effects:110        if name in effects:
nn111            if effects[name].intensity < 0:
112                raise TypeError("Effect is depleted.")
113            self.check_validity()
114            return effects[name]
115        return object.__getattribute__(self, name)
116    
117    def check_validity(self):
111            if self.used:118        if self.used:
112                raise TypeError("Potion is now part of something bigger than itself.")119                raise TypeError("Potion is now part of something bigger than itself.")
n113            if effects[name].intensity < 0:n
114                raise TypeError("Effect is depleted")
115            is_depleted = True120        is_depleted = True
116            for name, effect in effects.items():121        for effect in self.effects.values():
117                if (effect.intensity >= 0):122            if (effect.intensity >= 0):
118                    is_depleted = False123                is_depleted = False
119                    break124                break
125        if is_depleted:
120            self.is_depleted = is_depleted126            self.is_depleted = is_depleted
n121            return effects[name]n127            raise TypeError("Potion is depleted.")
122        return object.__getattribute__(self, name) 
123    128    
124    def get_score(potion):129    def get_score(potion):
125        return sum(getattr(potion, effect).intensity for effect in potion.effects if getattr(potion, effect, False))130        return sum(getattr(potion, effect).intensity for effect in potion.effects if getattr(potion, effect, False))
126    131    
127132
128class ГоспожатаПоХимия:133class ГоспожатаПоХимия:
129    def __init__(self):134    def __init__(self):
130        self.ticks_effects_end = {}135        self.ticks_effects_end = {}
131        self.timer = 0136        self.timer = 0
132137
133    def tick(self):138    def tick(self):
134        self.timer += 1139        self.timer += 1
135        if self.timer not in self.ticks_effects_end:140        if self.timer not in self.ticks_effects_end:
136            return141            return
137        142        
138        for target_data in self.ticks_effects_end[self.timer]:143        for target_data in self.ticks_effects_end[self.timer]:
139            target = target_data["target"]144            target = target_data["target"]
140            for state_name, state in target_data["target_changes"].items():145            for state_name, state in target_data["target_changes"].items():
141                setattr(target, state_name, state)146                setattr(target, state_name, state)
142    147    
143    def apply(self, target, potion):148    def apply(self, target, potion):
n144        if potion.used:n149        potion.check_validity()
145            raise TypeError("Potion is now part of something bigger than itself.")
146        if not potion.duration or potion.is_depleted:
147            raise TypeError("Potion is depleted")
148150
149        effects_tuples = sorted(potion.effects.items(), key = lambda item: sum([ord(char) for char in item[0]]), reverse = True)151        effects_tuples = sorted(potion.effects.items(), key = lambda item: sum([ord(char) for char in item[0]]), reverse = True)
150        effects = {effect_tuple[0]: effect_tuple[1] for effect_tuple in effects_tuples}152        effects = {effect_tuple[0]: effect_tuple[1] for effect_tuple in effects_tuples}
151153
152        for effect in effects.values():154        for effect in effects.values():
153            end_time = self.timer + potion.duration155            end_time = self.timer + potion.duration
154            if end_time not in self.ticks_effects_end:156            if end_time not in self.ticks_effects_end:
155                self.ticks_effects_end[end_time] = []157                self.ticks_effects_end[end_time] = []
156            target_dict = dict(target.__dict__)158            target_dict = dict(target.__dict__)
157            try:159            try:
158                for _ in range(effect.intensity):160                for _ in range(effect.intensity):
159                    effect(target)161                    effect(target)
160                target_changes = {key: target_dict[key] for key, value in target.__dict__.items() if target_dict[key] != value}162                target_changes = {key: target_dict[key] for key, value in target.__dict__.items() if target_dict[key] != value}
161                target_changes.update({key: 0 for key in target.__dict__.keys() if key not in target_dict})163                target_changes.update({key: 0 for key in target.__dict__.keys() if key not in target_dict})
162164
163                self.ticks_effects_end[end_time].append({165                self.ticks_effects_end[end_time].append({
164                    "target": target,166                    "target": target,
165                    "target_changes": target_changes167                    "target_changes": target_changes
166                })168                })
167            except TypeError:169            except TypeError:
t168                raise TypeError("Potion is depleted")t170                raise TypeError("Potion is depleted.")
169        potion.used = True
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op