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

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

6 точки общо

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

  1import copy
  2
  3
  4class Potion:
  5    @staticmethod
  6    def effect_decorator(name, func):
  7        def params_holder(self, target):
  8            if not name in self.intenzity:
  9                raise AttributeError(
 10                    '\'Potion\' object has no attribute \'' + name + '\'')
 11            if self.used:
 12                raise TypeError(
 13                    'Potion is now part of something bigger than itself.')
 14            if self.depleted:
 15                raise TypeError('Potion is depleted.')
 16            if self.intenzity[name] == -1 and not self.inAppliance:
 17                raise TypeError('Effect is depleted.')
 18            result = None
 19            for _ in range(self.intenzity[name]):
 20                result = func(target)
 21            self.count_effects_executed += 1
 22            if self.count_effects_executed == len(self.intenzity):
 23                self.depleted = True
 24            self.intenzity[name] = -1
 25            return result
 26        return params_holder
 27
 28    def __init__(self, effects, duration):
 29        self.count_effects_executed = 0
 30        self.used = False
 31        self.depleted = False
 32        self.inAppliance = False
 33        self.intenzity = {}
 34        self.duration = duration
 35
 36        for name in effects:
 37            self.intenzity[name] = 1
 38            if not hasattr(Potion, name):
 39                decorated_func = Potion.effect_decorator(name, effects[name])
 40                setattr(Potion, name, decorated_func)
 41
 42    def __add__(self, other_potion):
 43        if self.used or other_potion.used:
 44            raise TypeError(
 45                'Potion is now part of something bigger than itself.')
 46        if self.depleted or other_potion.depleted:
 47            raise TypeError('Potion is depleted.')
 48        new_potion = copy.deepcopy(self)
 49        new_potion.duration = max(
 50            self.duration, other_potion.duration)
 51
 52        self.used = True
 53        other_potion.used = True
 54
 55        for name in other_potion.intenzity:
 56            if name in new_potion.intenzity:
 57                if other_potion.intenzity[name] != -1:
 58                    new_potion.intenzity[name] = other_potion.intenzity[name]
 59                    if self.intenzity[name] != -1:
 60                        new_potion.intenzity[name] += self.intenzity[name]
 61            else:
 62                new_potion.intenzity[name] = other_potion.intenzity[name]
 63        return new_potion
 64
 65    def __mul__(self, number):
 66        if self.used:
 67            raise TypeError(
 68                'Potion is now part of something bigger than itself.')
 69        if self.depleted:
 70            raise TypeError('Potion is depleted.')
 71        newPotion = copy.deepcopy(self)
 72        self.used = True
 73        for name in newPotion.intenzity:
 74            if newPotion.intenzity[name] != -1:
 75                newPotion.intenzity[name] *= number
 76                if number < 1:
 77                    wholePart, decimalPart = divmod(
 78                        newPotion.intenzity[name], 1)
 79                    if decimalPart <= 0.5:
 80                        newPotion.intenzity[name] = int(wholePart)
 81                    else:
 82                        newPotion.intenzity[name] = int(wholePart)+1
 83        return newPotion
 84
 85    def __sub__(self, other_potion):
 86        if self.used or other_potion.used:
 87            raise TypeError(
 88                'Potion is now part of something bigger than itself.')
 89        if self.depleted or other_potion.depleted:
 90            raise TypeError('Potion is depleted.')
 91        for name in other_potion.intenzity:
 92            if not name in self.intenzity:
 93                raise TypeError(
 94                    'The first potion should have all of the effects of the second one')
 95        cleared_potion = copy.deepcopy(self)
 96        self.used = True
 97        other_potion.used = True
 98        for name in other_potion.intenzity:
 99            if cleared_potion.intenzity[name] != -1:
100                if cleared_potion.intenzity[name] < other_potion.intenzity[name]:
101                    del cleared_potion.intenzity[name]
102                else:
103                    cleared_potion.intenzity[name] -= other_potion.intenzity[name]
104        return cleared_potion
105
106    def __truediv__(self, coef):
107        if self.used:
108            raise TypeError(
109                'Potion is now part of something bigger than itself.')
110        if self.depleted:
111            raise TypeError('Potion is depleted.')
112        divided_potion = copy.deepcopy(self)
113        self.used = True
114        for name in divided_potion.intenzity:
115            if divided_potion.intenzity[name] != -1:
116                divided_potion.intenzity[name] /= coef
117                wholePart, decimalPart = divmod(
118                    divided_potion.intenzity[name], 1)
119                if decimalPart <= 0.5:
120                    divided_potion.intenzity[name] = int(wholePart)
121                else:
122                    divided_potion.intenzity[name] = int(wholePart) + 1
123        return (divided_potion,)*coef
124
125    def __eq__(self, other_potion):
126        if not len(self.intenzity) == len(other_potion.intenzity):
127            return False
128        for name in self.intenzity:
129            if not name in other_potion.intenzity:
130                return False
131            if self.intenzity[name] != other_potion.intenzity[name]:
132                return False
133        return True
134
135    def get_sum_potion(self):
136        sum = 0
137        for name in self.intenzity:
138            if self.intenzity[name] != -1:
139                sum += self.intenzity[name]
140        return sum
141
142    def __lt__(self, other_potion):
143        return self.get_sum_potion() < other_potion.get_sum_potion()
144
145    def __gt__(self, other_potion):
146        return self.get_sum_potion() > other_potion.get_sum_potion()
147
148
149class ГоспожатаПоХимия:
150    def __init__(self):
151        self.affected_objects = {}
152        self.duration = 0
153
154    def apply(self, target, potion):
155        if potion.used:
156            raise TypeError(
157                'Potion is now part of something bigger than itself.')
158        if potion.depleted:
159            raise TypeError('Potion is depleted.')
160
161        if potion.duration != 0:
162            object_ref = copy.deepcopy(target)
163            self.affected_objects[object_ref] = (target, potion)
164
165            sorted_intenzity = sorted(potion.intenzity, key=lambda k: sum(
166                map(ord, list(k))), reverse=True)
167
168            for name in sorted_intenzity:
169                getattr(potion, name)(target)
170
171    def tick(self):
172        found = False
173
174        for object in self.affected_objects:
175            self.affected_objects[object][1].duration-=1
176            if self.affected_objects[object][1].duration == 0:
177                self.affected_objects[object][0].__dict__ = object.__dict__
178                found = True
179                break
180        if found:
181            del self.affected_objects[object]

.F........FE...E.FF.
======================================================================
ERROR: test_separation (test.TestPotionOperations)
Test separation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 218, in test_separation
potion2.int_attr_fun(self._target)
File "/tmp/solution.py", line 15, in params_holder
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.

======================================================================
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 169, in apply
getattr(potion, name)(target)
File "/tmp/solution.py", line 15, in params_holder
raise TypeError('Potion is depleted.')
TypeError: Potion is depleted.

======================================================================
FAIL: test_depletion (test.TestBasicPotion)
Test depletion of a potion effect.
----------------------------------------------------------------------
TypeError: Potion is depleted.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/tmp/test.py", line 78, in test_depletion
with self.assertRaisesRegex(TypeError, 'Effect is depleted\.'):
AssertionError: "Effect is depleted\." does not match "Potion is depleted."

======================================================================
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_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_multiple_targets (test.TestГоспожатаПоХимия)
Test ticking after applying a potion with mutable attributes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 494, in test_ticking_multiple_targets
self.assertEqual(target2.int_attr, 5)
AssertionError: 50 != 5

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

FAILED (failures=4, errors=2)

Дискусия
История
Това решение има само една версия.