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

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

5 точки общо

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

  1from types import MethodType
  2
  3class Potion:
  4    
  5    def __init__(self, effects, duration):
  6        self.effects = effects  
  7        self.duration = duration
  8        self.applied_buffs = set()
  9        self.used_for_the_greater_good = False
 10        self.ticks = duration
 11        self.effect_intensity = {effect: 1 for effect in effects}
 12        for effect_name, effect_func in effects.items():
 13            method = MethodType(self.create_method(effect_name, effect_func), self)
 14            setattr(self, effect_name, method)
 15    
 16    #помощна фунция за създаване на методи
 17    def create_method(self, effect_name, effect_func):
 18        def effect_method(self, target):    
 19            if effect_name in self.applied_buffs:
 20                raise TypeError('Effect is depleted.')
 21            if self.used_for_the_greater_good:
 22                raise TypeError('Potion is now part of something bigger than itself.')
 23            
 24            if self.effect_intensity[effect_name]:
 25                for _ in range(self.effect_intensity[effect_name]):
 26                    effect_func(target)
 27                self.applied_buffs.add(effect_name)
 28                
 29        return effect_method
 30    
 31    #правя го hashable за да мога да го пъхна в списъка на Димитричка :)
 32    def __hash__(self):
 33        return hash(id(self))
 34    
 35    #комбиниране на коктейли (коктейл-fication)
 36    def __add__(self, other):
 37        combo_effects = {**self.effects}
 38        combo_intensity = self.effect_intensity
 39        
 40        for effect_name in other.effects.keys():
 41            if effect_name in self.effects.keys():
 42                self.effect_intensity[effect_name] += 1
 43            else:
 44                self.effect_intensity.update({effect_name : 1})
 45                       
 46        combo_duration = max(self.duration, other.duration)
 47        combo_potion = Potion(combo_effects, combo_duration)
 48        combo_potion.effect_intensity = combo_intensity
 49        
 50        self.used_for_the_greater_good = True
 51        other.used_for_the_greater_good = True
 52        
 53        return combo_potion
 54    
 55    #Като си сложиш екстра шот в коктейла (или като го разредиш idk)
 56    def __mul__(self, other):
 57        if other >= 1:
 58            potent_potion = self
 59            for _ in range(other - 1):
 60                potent_potion += self
 61            return potent_potion
 62        elif 0 < other < 1:
 63            diluted_intensity = {effect_name : round(self.effect_intensity[effect_name] * other) for effect_name in self.effect_intensity}
 64            diluted_potion = self
 65            diluted_potion.effect_intensity = diluted_intensity
 66            
 67            self.used_for_the_greater_good = True
 68            
 69            return diluted_potion
 70    
 71    #тук waterbend-ваме и премахваме съставки от коктейла
 72    def __sub__(self, other):
 73        if not all(effect in self.effects for effect in other.effects):
 74            raise TypeError('Cannot purify what does not exist.') 
 75        
 76        purified_effects = self.effects
 77        purified_intensity = {effect: self.effect_intensity[effect] - other.effect_intensity.get(effect, 0) for effect in self.effect_intensity}
 78        for effect_name, effect_intensity in purified_intensity.items():
 79            if effect_intensity < 0:
 80                self.applied_buffs.add(effect_name) 
 81         
 82        purified_potion = Potion(purified_effects, self.duration)
 83        purified_potion.effect_intensity = purified_intensity
 84        
 85        self.used_for_the_greater_good = True
 86        other.used_for_the_greater_good = True
 87        
 88        return purified_potion
 89    
 90    #споделяме с приятели
 91    #абсолютно същото като  __mul__, но с '/'
 92    def __truediv__(self, other):
 93        split_intensity = {effect_name : round(self.effect_intensity[effect_name] / other) for effect_name in self.effect_intensity}
 94        
 95        split_potion = self
 96        split_potion.effect_intensity = split_intensity
 97        
 98        self.used_for_the_greater_good = True
 99        
100        return split_potion
101    
102    #мерим си... коктейлите
103    def __lt__(self, other):
104        return sum(self.effect_intensity.values()) < sum(other.effect_intensity.values())
105        
106    def __gt__(self, other):
107        return sum(self.effect_intensity.values()) > sum(other.effect_intensity.values())
108    
109    def __eq__(self, other):
110        return self.effect_intensity == other.effect_intensity
111    
112    def tick(self):
113        self.ticks = max(0, self.ticks - 1)
114    
115
116class ГоспожатаПоХимия:
117    
118    def __init__(self):
119        self.applied_potions = set()
120    
121    def apply(self, target, potion):
122        if potion in self.applied_potions:
123            raise TypeError('Potion is depleted.')
124
125        sorted_effects = sorted(potion.effects, key=lambda effect_name: sum(ord(letter) for letter in effect_name))
126
127        for effect_name in sorted_effects:
128            effect_method = getattr(potion, effect_name)
129            try:
130                effect_method(target)
131            except TypeError:
132                continue
133
134        self.applied_potions.add(potion)
135        
136    def tick(self):
137        for potion in self.applied_potions.copy():
138            potion.tick()
139            if potion.ticks == 0:
140                self.applied_potions.remove(potion)

.....E..E.FEF.F.FFFF
======================================================================
ERROR: test_combination_no_overlap (test.TestPotionOperations)
Test combining potions with no overlap.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 95, in test_combination_no_overlap
potion.float_attr_fun(self._target)
AttributeError: 'Potion' object has no attribute 'float_attr_fun'

======================================================================
ERROR: test_dilution (test.TestPotionOperations)
Test dilution of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 119, in test_dilution
half_potion.int_attr_fun(self._target)
File "/tmp/solution.py", line 22, in effect_method
raise TypeError('Potion is now part of something bigger than itself.')
TypeError: Potion is now part of something bigger than itself.

======================================================================
ERROR: test_separation (test.TestPotionOperations)
Test separation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 213, in test_separation
potion1, potion2, potion3 = potion / 3
TypeError: cannot unpack non-iterable Potion object

======================================================================
FAIL: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 168, in test_purification
with self.assertRaises(AttributeError):
AssertionError: AttributeError not raised

======================================================================
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_applying_order (test.TestГоспожатаПоХимия)
Test applying order of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 405, in test_applying_order
self.assertEqual(self._target.int_attr, 12)
AssertionError: 14 != 12

======================================================================
FAIL: test_ticking_immutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with immutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 429, in test_ticking_immutable
self.assertEqual(self._target.int_attr, 5)
AssertionError: 500 != 5

======================================================================
FAIL: test_ticking_multiple_potions (test.TestГоспожатаПоХимия)
Test ticking after applying multiple potions which affect the same attribute.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 458, in test_ticking_multiple_potions
self.assertEqual(self._target.int_attr, 50)
AssertionError: 500 != 50

======================================================================
FAIL: test_ticking_multiple_targets (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 490, in test_ticking_multiple_targets
self.assertEqual(target1.int_attr, 5)
AssertionError: 500 != 5

======================================================================
FAIL: test_ticking_mutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 444, in test_ticking_mutable
self.assertEqual(self._target.int_attr, 5)
AssertionError: 50 != 5

----------------------------------------------------------------------
Ran 20 tests in 0.002s

FAILED (failures=7, errors=3)

Дискусия
Георги Кунчев
01.12.2023 10:10

Нямам големи коментари по кода. Прилично написан е. Довърши си това, за което спомена, изтествай добре срещу изискванията и си готов.
Константин Кирязов
30.11.2023 21:11

Остава само да напиша как се премахват ефектите на отварата след като й изтече времето, но за сега толкоз. Уикенда ще има ъпдейт. ;)
История

f1from types import MethodTypef1from types import MethodType
22
3class Potion:3class Potion:
4    4    
5    def __init__(self, effects, duration):5    def __init__(self, effects, duration):
6        self.effects = effects  6        self.effects = effects  
7        self.duration = duration7        self.duration = duration
8        self.applied_buffs = set()8        self.applied_buffs = set()
9        self.used_for_the_greater_good = False9        self.used_for_the_greater_good = False
10        self.ticks = duration10        self.ticks = duration
11        self.effect_intensity = {effect: 1 for effect in effects}11        self.effect_intensity = {effect: 1 for effect in effects}
12        for effect_name, effect_func in effects.items():12        for effect_name, effect_func in effects.items():
13            method = MethodType(self.create_method(effect_name, effect_func), self)13            method = MethodType(self.create_method(effect_name, effect_func), self)
14            setattr(self, effect_name, method)14            setattr(self, effect_name, method)
15    15    
16    #помощна фунция за създаване на методи16    #помощна фунция за създаване на методи
17    def create_method(self, effect_name, effect_func):17    def create_method(self, effect_name, effect_func):
18        def effect_method(self, target):    18        def effect_method(self, target):    
19            if effect_name in self.applied_buffs:19            if effect_name in self.applied_buffs:
20                raise TypeError('Effect is depleted.')20                raise TypeError('Effect is depleted.')
21            if self.used_for_the_greater_good:21            if self.used_for_the_greater_good:
22                raise TypeError('Potion is now part of something bigger than itself.')22                raise TypeError('Potion is now part of something bigger than itself.')
23            23            
24            if self.effect_intensity[effect_name]:24            if self.effect_intensity[effect_name]:
25                for _ in range(self.effect_intensity[effect_name]):25                for _ in range(self.effect_intensity[effect_name]):
26                    effect_func(target)26                    effect_func(target)
27                self.applied_buffs.add(effect_name)27                self.applied_buffs.add(effect_name)
28                28                
29        return effect_method29        return effect_method
30    30    
31    #правя го hashable за да мога да го пъхна в списъка на Димитричка :)31    #правя го hashable за да мога да го пъхна в списъка на Димитричка :)
32    def __hash__(self):32    def __hash__(self):
33        return hash(id(self))33        return hash(id(self))
34    34    
35    #комбиниране на коктейли (коктейл-fication)35    #комбиниране на коктейли (коктейл-fication)
36    def __add__(self, other):36    def __add__(self, other):
37        combo_effects = {**self.effects}37        combo_effects = {**self.effects}
38        combo_intensity = self.effect_intensity38        combo_intensity = self.effect_intensity
39        39        
40        for effect_name in other.effects.keys():40        for effect_name in other.effects.keys():
41            if effect_name in self.effects.keys():41            if effect_name in self.effects.keys():
42                self.effect_intensity[effect_name] += 142                self.effect_intensity[effect_name] += 1
43            else:43            else:
44                self.effect_intensity.update({effect_name : 1})44                self.effect_intensity.update({effect_name : 1})
45                       45                       
46        combo_duration = max(self.duration, other.duration)46        combo_duration = max(self.duration, other.duration)
47        combo_potion = Potion(combo_effects, combo_duration)47        combo_potion = Potion(combo_effects, combo_duration)
48        combo_potion.effect_intensity = combo_intensity48        combo_potion.effect_intensity = combo_intensity
49        49        
50        self.used_for_the_greater_good = True50        self.used_for_the_greater_good = True
51        other.used_for_the_greater_good = True51        other.used_for_the_greater_good = True
52        52        
53        return combo_potion53        return combo_potion
54    54    
55    #Като си сложиш екстра шот в коктейла (или като го разредиш idk)55    #Като си сложиш екстра шот в коктейла (или като го разредиш idk)
56    def __mul__(self, other):56    def __mul__(self, other):
57        if other >= 1:57        if other >= 1:
58            potent_potion = self58            potent_potion = self
59            for _ in range(other - 1):59            for _ in range(other - 1):
60                potent_potion += self60                potent_potion += self
61            return potent_potion61            return potent_potion
62        elif 0 < other < 1:62        elif 0 < other < 1:
63            diluted_intensity = {effect_name : round(self.effect_intensity[effect_name] * other) for effect_name in self.effect_intensity}63            diluted_intensity = {effect_name : round(self.effect_intensity[effect_name] * other) for effect_name in self.effect_intensity}
64            diluted_potion = self64            diluted_potion = self
65            diluted_potion.effect_intensity = diluted_intensity65            diluted_potion.effect_intensity = diluted_intensity
66            66            
67            self.used_for_the_greater_good = True67            self.used_for_the_greater_good = True
68            68            
69            return diluted_potion69            return diluted_potion
70    70    
71    #тук waterbend-ваме и премахваме съставки от коктейла71    #тук waterbend-ваме и премахваме съставки от коктейла
72    def __sub__(self, other):72    def __sub__(self, other):
73        if not all(effect in self.effects for effect in other.effects):73        if not all(effect in self.effects for effect in other.effects):
74            raise TypeError('Cannot purify what does not exist.') 74            raise TypeError('Cannot purify what does not exist.') 
75        75        
76        purified_effects = self.effects76        purified_effects = self.effects
77        purified_intensity = {effect: self.effect_intensity[effect] - other.effect_intensity.get(effect, 0) for effect in self.effect_intensity}77        purified_intensity = {effect: self.effect_intensity[effect] - other.effect_intensity.get(effect, 0) for effect in self.effect_intensity}
78        for effect_name, effect_intensity in purified_intensity.items():78        for effect_name, effect_intensity in purified_intensity.items():
79            if effect_intensity < 0:79            if effect_intensity < 0:
80                self.applied_buffs.add(effect_name) 80                self.applied_buffs.add(effect_name) 
81         81         
82        purified_potion = Potion(purified_effects, self.duration)82        purified_potion = Potion(purified_effects, self.duration)
83        purified_potion.effect_intensity = purified_intensity83        purified_potion.effect_intensity = purified_intensity
84        84        
85        self.used_for_the_greater_good = True85        self.used_for_the_greater_good = True
86        other.used_for_the_greater_good = True86        other.used_for_the_greater_good = True
87        87        
88        return purified_potion88        return purified_potion
89    89    
90    #споделяме с приятели90    #споделяме с приятели
91    #абсолютно същото като  __mul__, но с '/'91    #абсолютно същото като  __mul__, но с '/'
92    def __truediv__(self, other):92    def __truediv__(self, other):
93        split_intensity = {effect_name : round(self.effect_intensity[effect_name] / other) for effect_name in self.effect_intensity}93        split_intensity = {effect_name : round(self.effect_intensity[effect_name] / other) for effect_name in self.effect_intensity}
94        94        
95        split_potion = self95        split_potion = self
96        split_potion.effect_intensity = split_intensity96        split_potion.effect_intensity = split_intensity
97        97        
98        self.used_for_the_greater_good = True98        self.used_for_the_greater_good = True
99        99        
100        return split_potion100        return split_potion
101    101    
102    #мерим си... коктейлите102    #мерим си... коктейлите
103    def __lt__(self, other):103    def __lt__(self, other):
104        return sum(self.effect_intensity.values()) < sum(other.effect_intensity.values())104        return sum(self.effect_intensity.values()) < sum(other.effect_intensity.values())
105        105        
106    def __gt__(self, other):106    def __gt__(self, other):
107        return sum(self.effect_intensity.values()) > sum(other.effect_intensity.values())107        return sum(self.effect_intensity.values()) > sum(other.effect_intensity.values())
108    108    
109    def __eq__(self, other):109    def __eq__(self, other):
110        return self.effect_intensity == other.effect_intensity110        return self.effect_intensity == other.effect_intensity
111    111    
112    def tick(self):112    def tick(self):
113        self.ticks = max(0, self.ticks - 1)113        self.ticks = max(0, self.ticks - 1)
t114        print(self.ticks)t
115    114    
116115
117class ГоспожатаПоХимия:116class ГоспожатаПоХимия:
118    117    
119    def __init__(self):118    def __init__(self):
120        self.applied_potions = set()119        self.applied_potions = set()
121    120    
122    def apply(self, target, potion):121    def apply(self, target, potion):
123        if potion in self.applied_potions:122        if potion in self.applied_potions:
124            raise TypeError('Potion is depleted.')123            raise TypeError('Potion is depleted.')
125124
126        sorted_effects = sorted(potion.effects, key=lambda effect_name: sum(ord(letter) for letter in effect_name))125        sorted_effects = sorted(potion.effects, key=lambda effect_name: sum(ord(letter) for letter in effect_name))
127126
128        for effect_name in sorted_effects:127        for effect_name in sorted_effects:
129            effect_method = getattr(potion, effect_name)128            effect_method = getattr(potion, effect_name)
130            try:129            try:
131                effect_method(target)130                effect_method(target)
132            except TypeError:131            except TypeError:
133                continue132                continue
134133
135        self.applied_potions.add(potion)134        self.applied_potions.add(potion)
136        135        
137    def tick(self):136    def tick(self):
138        for potion in self.applied_potions.copy():137        for potion in self.applied_potions.copy():
139            potion.tick()138            potion.tick()
140            if potion.ticks == 0:139            if potion.ticks == 0:
141                self.applied_potions.remove(potion)140                self.applied_potions.remove(potion)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op