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

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

8 точки общо

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

  1import math
  2from copy import deepcopy
  3from functools import reduce
  4
  5TRANSCENDED = 'Potion is now part of something bigger than itself.'
  6DEPLETED_P = 'Potion is depleted.'
  7DEPLETED_E = 'Effect is depleted.'
  8
  9class Potion:
 10    def __init__(self, effects, duration):
 11        self.effects = { func_name: [ func, 1 ] if not isinstance(func, list) else func for func_name, func in effects.items() }
 12        self.duration = duration
 13        self.is_used_for_other_potions = False
 14        self.applied_effects = set()
 15
 16    def _is_depleated(self):
 17        return len(self.applied_effects) == len(self.effects)
 18
 19    def __add__(self, other):
 20        if self._is_depleated() or other._is_depleated():
 21            raise TypeError(DEPLETED_P)
 22        combined_effects = deepcopy(self.effects)
 23        for effect_name, effect in other.effects.items():
 24            if effect_name not in combined_effects:
 25                combined_effects[effect_name] = effect
 26            else:
 27                combined_effects[effect_name][1] += 1
 28        combined_duration = max(self.duration, other.duration)
 29        self.is_used_for_other_potions = other.is_used_for_other_potions = True
 30        return Potion(combined_effects, combined_duration)
 31    
 32    def __mul__(self, other):
 33        if self._is_depleated():
 34            raise TypeError(DEPLETED_P)
 35        dict_copy = deepcopy(self.effects)
 36        for _, effect in dict_copy.items():
 37            effect[1] *= other
 38            number = effect[1] % 1
 39            if number <= 0.5:
 40                effect[1] = math.floor(effect[1])
 41            else:
 42                effect[1] = math.ceil(effect[1])
 43        self.is_used_for_other_potions = True
 44        return Potion(dict_copy, self.duration)
 45
 46    def __sub__(self, other):
 47        if self._is_depleated() or other._is_depleated():
 48            raise TypeError(DEPLETED_P)
 49        for key in other.effects.keys():
 50            if key not in self.effects:
 51                raise TypeError(TRANSCENDED)
 52        dict_copy = deepcopy(self.effects)
 53        for func_name, func_and_times in other.effects.items():
 54            if func_name in dict_copy:
 55                if dict_copy[func_name][1] <= func_and_times[1]:
 56                    dict_copy.pop(func_name)
 57                else:
 58                    dict_copy[func_name][1] -= func_and_times[1]
 59        self.is_used_for_other_potions = other.is_used_for_other_potions = True
 60        return Potion(dict_copy, self.duration)
 61    
 62    def __truediv__(self, other):
 63        if self._is_depleated():
 64            raise TypeError(DEPLETED_P)
 65        dict_copy = deepcopy(self.effects)
 66        to_pop = []
 67        for key, effect in dict_copy.items():
 68            effect[1] /= other
 69            number = effect[1] % 1
 70            if number <= 0.5:
 71                effect[1] = math.floor(effect[1])
 72            else:
 73                effect[1] = math.ceil(effect[1])
 74            if not effect[1]:
 75                to_pop.append(key)
 76        for key in to_pop:
 77            dict_copy.pop(key)
 78        self.is_used_for_other_potions = True
 79        return [ Potion(deepcopy(dict_copy), self.duration) for _ in range(other) ]
 80
 81    def __eq__(self, other):
 82        if self.is_used_for_other_potions or other.is_used_for_other_potions:
 83            raise TypeError(TRANSCENDED)
 84        if self._is_depleated():
 85            raise TypeError(DEPLETED_P)
 86        return self.effects == other.effects
 87
 88    def __lt__(self, other):
 89        if self.is_used_for_other_potions or other.is_used_for_other_potions:
 90            raise TypeError(TRANSCENDED)
 91        if self._is_depleated():
 92            raise TypeError(DEPLETED_P)
 93        self_intensity = reduce(lambda acc, l: acc + l[1], self.effects.values(), 0)
 94        other_intensity = reduce(lambda acc, l: acc + l[1], other.effects.values(), 0)
 95        return self_intensity < other_intensity
 96
 97    def __gt__(self, other):
 98        if self.is_used_for_other_potions or other.is_used_for_other_potions:
 99            raise TypeError(TRANSCENDED)
100        if self._is_depleated():
101            raise TypeError(DEPLETED_P)
102        self_intensity = reduce(lambda acc, l: acc + l[1], self.effects.values(), 0)
103        other_intensity = reduce(lambda acc, l: acc + l[1], other.effects.values(), 0)
104        return self_intensity > other_intensity
105    
106    def _apply_effect(self, effect, target):
107        for _ in range(self.effects[effect][1]):
108            self.effects[effect][0](target)
109        self.effects[effect][1] = 0
110
111    def __getattr__(self, effect):
112        if effect not in self.effects:
113            raise AttributeError("The potion has no such effect")
114        elif effect in self.applied_effects:
115            raise TypeError(DEPLETED_E)
116        elif self.is_used_for_other_potions:
117            raise TypeError(TRANSCENDED)
118        elif len(self.effects) == len(self.applied_effects):
119            raise TypeError(DEPLETED_P)
120
121        self.applied_effects.add(effect)
122        return lambda target: self._apply_effect(effect, target)
123
124
125class ГоспожатаПоХимия:
126    def __init__(self):
127        self.applied_potions = set()
128        self.target = None  
129
130    def apply(self, target, potion):
131        self.target = target
132        if id(potion) in self.applied_potions:
133            raise TypeError(DEPLETED_P)
134        effect_names = sorted(potion.effects.keys(), key=lambda name: sum(ord(char) for char in name), reverse=True)
135        for effect in effect_names:
136            if potion.duration > 0:
137                getattr(potion, effect)(target)
138        self.applied_potions.add(id(potion))
139
140    def tick(self):
141        for _, _, i in self.applied_potions:
142            if i > 0:
143                i -= 1

...............EEEEE
======================================================================
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 137, in apply
getattr(potion, effect)(target)
File "/tmp/solution.py", line 115, in __getattr__
raise TypeError(DEPLETED_E)
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 426, in test_ticking_immutable
self._dimitrichka.tick()
File "/tmp/solution.py", line 141, in tick
for _, _, i in self.applied_potions:
TypeError: cannot unpack non-iterable int object

======================================================================
ERROR: 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 457, in test_ticking_multiple_potions
self._dimitrichka.tick()
File "/tmp/solution.py", line 141, in tick
for _, _, i in self.applied_potions:
TypeError: cannot unpack non-iterable int object

======================================================================
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 489, in test_ticking_multiple_targets
self._dimitrichka.tick()
File "/tmp/solution.py", line 141, in tick
for _, _, i in self.applied_potions:
TypeError: cannot unpack non-iterable int object

======================================================================
ERROR: test_ticking_mutable (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 443, in test_ticking_mutable
self._dimitrichka.tick()
File "/tmp/solution.py", line 141, in tick
for _, _, i in self.applied_potions:
TypeError: cannot unpack non-iterable int object

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

FAILED (errors=5)

Дискусия
История

f1import mathf1import math
2from copy import deepcopy2from copy import deepcopy
3from functools import reduce3from functools import reduce
44
5TRANSCENDED = 'Potion is now part of something bigger than itself.'5TRANSCENDED = 'Potion is now part of something bigger than itself.'
6DEPLETED_P = 'Potion is depleted.'6DEPLETED_P = 'Potion is depleted.'
7DEPLETED_E = 'Effect is depleted.'7DEPLETED_E = 'Effect is depleted.'
88
9class Potion:9class Potion:
10    def __init__(self, effects, duration):10    def __init__(self, effects, duration):
11        self.effects = { func_name: [ func, 1 ] if not isinstance(func, list) else func for func_name, func in effects.items() }11        self.effects = { func_name: [ func, 1 ] if not isinstance(func, list) else func for func_name, func in effects.items() }
12        self.duration = duration12        self.duration = duration
13        self.is_used_for_other_potions = False13        self.is_used_for_other_potions = False
14        self.applied_effects = set()14        self.applied_effects = set()
1515
16    def _is_depleated(self):16    def _is_depleated(self):
17        return len(self.applied_effects) == len(self.effects)17        return len(self.applied_effects) == len(self.effects)
1818
19    def __add__(self, other):19    def __add__(self, other):
20        if self._is_depleated() or other._is_depleated():20        if self._is_depleated() or other._is_depleated():
21            raise TypeError(DEPLETED_P)21            raise TypeError(DEPLETED_P)
22        combined_effects = deepcopy(self.effects)22        combined_effects = deepcopy(self.effects)
23        for effect_name, effect in other.effects.items():23        for effect_name, effect in other.effects.items():
24            if effect_name not in combined_effects:24            if effect_name not in combined_effects:
25                combined_effects[effect_name] = effect25                combined_effects[effect_name] = effect
26            else:26            else:
27                combined_effects[effect_name][1] += 127                combined_effects[effect_name][1] += 1
28        combined_duration = max(self.duration, other.duration)28        combined_duration = max(self.duration, other.duration)
29        self.is_used_for_other_potions = other.is_used_for_other_potions = True29        self.is_used_for_other_potions = other.is_used_for_other_potions = True
30        return Potion(combined_effects, combined_duration)30        return Potion(combined_effects, combined_duration)
31    31    
32    def __mul__(self, other):32    def __mul__(self, other):
33        if self._is_depleated():33        if self._is_depleated():
34            raise TypeError(DEPLETED_P)34            raise TypeError(DEPLETED_P)
35        dict_copy = deepcopy(self.effects)35        dict_copy = deepcopy(self.effects)
36        for _, effect in dict_copy.items():36        for _, effect in dict_copy.items():
37            effect[1] *= other37            effect[1] *= other
38            number = effect[1] % 138            number = effect[1] % 1
39            if number <= 0.5:39            if number <= 0.5:
40                effect[1] = math.floor(effect[1])40                effect[1] = math.floor(effect[1])
41            else:41            else:
42                effect[1] = math.ceil(effect[1])42                effect[1] = math.ceil(effect[1])
43        self.is_used_for_other_potions = True43        self.is_used_for_other_potions = True
44        return Potion(dict_copy, self.duration)44        return Potion(dict_copy, self.duration)
4545
46    def __sub__(self, other):46    def __sub__(self, other):
47        if self._is_depleated() or other._is_depleated():47        if self._is_depleated() or other._is_depleated():
48            raise TypeError(DEPLETED_P)48            raise TypeError(DEPLETED_P)
49        for key in other.effects.keys():49        for key in other.effects.keys():
50            if key not in self.effects:50            if key not in self.effects:
51                raise TypeError(TRANSCENDED)51                raise TypeError(TRANSCENDED)
52        dict_copy = deepcopy(self.effects)52        dict_copy = deepcopy(self.effects)
53        for func_name, func_and_times in other.effects.items():53        for func_name, func_and_times in other.effects.items():
54            if func_name in dict_copy:54            if func_name in dict_copy:
55                if dict_copy[func_name][1] <= func_and_times[1]:55                if dict_copy[func_name][1] <= func_and_times[1]:
56                    dict_copy.pop(func_name)56                    dict_copy.pop(func_name)
57                else:57                else:
58                    dict_copy[func_name][1] -= func_and_times[1]58                    dict_copy[func_name][1] -= func_and_times[1]
59        self.is_used_for_other_potions = other.is_used_for_other_potions = True59        self.is_used_for_other_potions = other.is_used_for_other_potions = True
60        return Potion(dict_copy, self.duration)60        return Potion(dict_copy, self.duration)
61    61    
62    def __truediv__(self, other):62    def __truediv__(self, other):
63        if self._is_depleated():63        if self._is_depleated():
64            raise TypeError(DEPLETED_P)64            raise TypeError(DEPLETED_P)
65        dict_copy = deepcopy(self.effects)65        dict_copy = deepcopy(self.effects)
66        to_pop = []66        to_pop = []
67        for key, effect in dict_copy.items():67        for key, effect in dict_copy.items():
68            effect[1] /= other68            effect[1] /= other
69            number = effect[1] % 169            number = effect[1] % 1
70            if number <= 0.5:70            if number <= 0.5:
71                effect[1] = math.floor(effect[1])71                effect[1] = math.floor(effect[1])
72            else:72            else:
73                effect[1] = math.ceil(effect[1])73                effect[1] = math.ceil(effect[1])
74            if not effect[1]:74            if not effect[1]:
75                to_pop.append(key)75                to_pop.append(key)
76        for key in to_pop:76        for key in to_pop:
77            dict_copy.pop(key)77            dict_copy.pop(key)
78        self.is_used_for_other_potions = True78        self.is_used_for_other_potions = True
79        return [ Potion(deepcopy(dict_copy), self.duration) for _ in range(other) ]79        return [ Potion(deepcopy(dict_copy), self.duration) for _ in range(other) ]
8080
81    def __eq__(self, other):81    def __eq__(self, other):
82        if self.is_used_for_other_potions or other.is_used_for_other_potions:82        if self.is_used_for_other_potions or other.is_used_for_other_potions:
83            raise TypeError(TRANSCENDED)83            raise TypeError(TRANSCENDED)
84        if self._is_depleated():84        if self._is_depleated():
85            raise TypeError(DEPLETED_P)85            raise TypeError(DEPLETED_P)
86        return self.effects == other.effects86        return self.effects == other.effects
8787
88    def __lt__(self, other):88    def __lt__(self, other):
89        if self.is_used_for_other_potions or other.is_used_for_other_potions:89        if self.is_used_for_other_potions or other.is_used_for_other_potions:
90            raise TypeError(TRANSCENDED)90            raise TypeError(TRANSCENDED)
91        if self._is_depleated():91        if self._is_depleated():
92            raise TypeError(DEPLETED_P)92            raise TypeError(DEPLETED_P)
93        self_intensity = reduce(lambda acc, l: acc + l[1], self.effects.values(), 0)93        self_intensity = reduce(lambda acc, l: acc + l[1], self.effects.values(), 0)
94        other_intensity = reduce(lambda acc, l: acc + l[1], other.effects.values(), 0)94        other_intensity = reduce(lambda acc, l: acc + l[1], other.effects.values(), 0)
95        return self_intensity < other_intensity95        return self_intensity < other_intensity
9696
97    def __gt__(self, other):97    def __gt__(self, other):
98        if self.is_used_for_other_potions or other.is_used_for_other_potions:98        if self.is_used_for_other_potions or other.is_used_for_other_potions:
99            raise TypeError(TRANSCENDED)99            raise TypeError(TRANSCENDED)
100        if self._is_depleated():100        if self._is_depleated():
101            raise TypeError(DEPLETED_P)101            raise TypeError(DEPLETED_P)
102        self_intensity = reduce(lambda acc, l: acc + l[1], self.effects.values(), 0)102        self_intensity = reduce(lambda acc, l: acc + l[1], self.effects.values(), 0)
103        other_intensity = reduce(lambda acc, l: acc + l[1], other.effects.values(), 0)103        other_intensity = reduce(lambda acc, l: acc + l[1], other.effects.values(), 0)
104        return self_intensity > other_intensity104        return self_intensity > other_intensity
105    105    
106    def _apply_effect(self, effect, target):106    def _apply_effect(self, effect, target):
107        for _ in range(self.effects[effect][1]):107        for _ in range(self.effects[effect][1]):
108            self.effects[effect][0](target)108            self.effects[effect][0](target)
109        self.effects[effect][1] = 0109        self.effects[effect][1] = 0
110110
111    def __getattr__(self, effect):111    def __getattr__(self, effect):
112        if effect not in self.effects:112        if effect not in self.effects:
113            raise AttributeError("The potion has no such effect")113            raise AttributeError("The potion has no such effect")
114        elif effect in self.applied_effects:114        elif effect in self.applied_effects:
115            raise TypeError(DEPLETED_E)115            raise TypeError(DEPLETED_E)
116        elif self.is_used_for_other_potions:116        elif self.is_used_for_other_potions:
117            raise TypeError(TRANSCENDED)117            raise TypeError(TRANSCENDED)
118        elif len(self.effects) == len(self.applied_effects):118        elif len(self.effects) == len(self.applied_effects):
119            raise TypeError(DEPLETED_P)119            raise TypeError(DEPLETED_P)
120120
121        self.applied_effects.add(effect)121        self.applied_effects.add(effect)
122        return lambda target: self._apply_effect(effect, target)122        return lambda target: self._apply_effect(effect, target)
123123
124124
t125class GospojataPoHimiq:t125class ГоспожатаПоХимия:
126    def __init__(self):126    def __init__(self):
127        self.applied_potions = set()127        self.applied_potions = set()
128        self.target = None  128        self.target = None  
129129
130    def apply(self, target, potion):130    def apply(self, target, potion):
131        self.target = target131        self.target = target
132        if id(potion) in self.applied_potions:132        if id(potion) in self.applied_potions:
133            raise TypeError(DEPLETED_P)133            raise TypeError(DEPLETED_P)
134        effect_names = sorted(potion.effects.keys(), key=lambda name: sum(ord(char) for char in name), reverse=True)134        effect_names = sorted(potion.effects.keys(), key=lambda name: sum(ord(char) for char in name), reverse=True)
135        for effect in effect_names:135        for effect in effect_names:
136            if potion.duration > 0:136            if potion.duration > 0:
137                getattr(potion, effect)(target)137                getattr(potion, effect)(target)
138        self.applied_potions.add(id(potion))138        self.applied_potions.add(id(potion))
139139
140    def tick(self):140    def tick(self):
141        for _, _, i in self.applied_potions:141        for _, _, i in self.applied_potions:
142            if i > 0:142            if i > 0:
143                i -= 1143                i -= 1
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op