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

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

7 точки общо

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

  1import math
  2
  3def normal_round(n):
  4    if n - math.floor(n) <= 0.5:
  5        return math.floor(n)
  6    return math.ceil(n)
  7
  8class Potion:
  9
 10    def __init__(self, effects: dict, duration: int):
 11        self.effects = effects
 12        self.potency = dict.fromkeys(effects, 1)
 13        self.duration = duration
 14        self.active_effects = set(effects.keys())
 15        self.is_used = False
 16
 17    def __eq__(self, other) -> bool:
 18        return self.effects.keys() == other.effects.keys() and self.potency == other.potency
 19
 20    def __gt__(self, other) -> bool:
 21        itensity_first = 0
 22        itensity_second = 0
 23        for effect in self.potency:
 24            itensity_first += self.potency[effect]
 25        for effect in other.potency:
 26            itensity_second += other.potency[effect]
 27
 28        return itensity_first > itensity_second
 29
 30    def __lt__(self, other) -> bool:
 31        itensity_first = 0
 32        itensity_second = 0
 33        for effect in self.potency:
 34            itensity_first += self.potency[effect]
 35        for effect in other.potency:
 36            itensity_second += other.potency[effect]
 37
 38        return itensity_first < itensity_second
 39
 40    def __add__(self, other):
 41        if self.is_used or other.is_used:
 42            raise TypeError("Potion is now part of something bigger than itself.")
 43
 44        combined_potion = Potion(self.effects, self.duration)
 45        combined_potion.potency = self.potency
 46        combined_potion.active_effects = self.active_effects
 47        for effect in other.effects:
 48            if effect in combined_potion.effects:
 49                combined_potion.potency[effect] += other.potency[effect]
 50            else:
 51                combined_potion.effects[effect] = other.effects[effect]
 52                combined_potion.potency[effect] = other.potency[effect]
 53                combined_potion.active_effects.add(effect)
 54        combined_potion.duration = max(combined_potion.duration, other.duration)
 55
 56        self.is_used = True
 57        other.is_used = True
 58        return combined_potion
 59
 60    def __sub__(self, other):
 61        if self.is_used or other.is_used:
 62            raise TypeError("Potion is now part of something bigger than itself.")
 63
 64        diluted_potion = Potion(self.effects, self.duration)
 65        diluted_potion.potency = self.potency
 66        diluted_potion.active_effects = self.active_effects
 67        try:
 68            for effect in other.effects:
 69                diluted_potion.potency[effect] -= other.potency[effect]
 70                if diluted_potion.potency[effect] <= 0:
 71                    diluted_potion.effects.pop(effect)
 72                    diluted_potion.potency.pop(effect)
 73                    diluted_potion.active_effects.remove(effect)
 74            self.is_used = True
 75            other.is_used = True
 76            return diluted_potion
 77        except:
 78            raise TypeError("Potion cannot be diluted")
 79
 80    def __mul__(self, value):
 81        if self.is_used:
 82            raise TypeError("Potion is now part of something bigger than itself.")
 83
 84        new_potion = Potion(self.effects, self.duration)
 85        new_potion.potency = self.potency
 86        new_potion.active_effects = self.active_effects
 87        if value < 1:
 88            for effect in new_potion.potency:
 89                new_potion.potency[effect] = int(normal_round(new_potion.potency[effect] * value))
 90        else:
 91            for effect in new_potion.potency:
 92                new_potion.potency[effect] *= value
 93
 94        self.is_used = True
 95        return new_potion
 96
 97    def __truediv__(self, value):
 98        if self.is_used:
 99            raise TypeError("Potion is now part of something bigger than itself.")
100
101        new_potion = Potion(self.effects, self.duration)
102        new_potion.potency = self.potency
103        new_potion.active_effects = self.active_effects
104
105        for effect in new_potion.potency:
106            new_potion.potency[effect] = int(normal_round(new_potion.potency[effect] / value))
107
108        self.is_used = True
109
110        potions = []
111        for _ in range(0, value):
112            copy_potion = Potion(new_potion.effects, new_potion.duration)
113            copy_potion.potency = new_potion.potency.copy()
114            copy_potion.active_effects = new_potion.active_effects.copy()
115            potions.append(copy_potion)
116
117        return tuple(potions)
118
119    def __getattr__(self, effect):
120        try:
121            self.active_effects.remove(effect)
122            return self.apply_potency(effect)
123        except:
124            raise TypeError("Effect is depleted.")
125
126    def apply_potency(self, effect):
127        def apply_effect(target):
128            for _ in range(self.potency[effect]):
129                self.effects[effect](target)
130        return apply_effect
131
132
133class ГоспожатаПоХимия:
134
135    def apply(self, target, potion: Potion):
136        if potion.is_used or not potion.active_effects:
137            raise TypeError("Potion is depleted.")
138
139        sorted_effects = sorted(list(potion.active_effects),
140                                key = lambda effect : sum(ord(ch) for ch in effect), reverse=True)
141        for effect in sorted_effects:
142            potion.__getattr__(effect)(target)
143
144        potion.is_used = True
145
146    def tick(self):
147        pass

.......F..E.F...FFFF
======================================================================
ERROR: test_purification (test.TestPotionOperations)
Test purification of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/solution.py", line 121, in __getattr__
self.active_effects.remove(effect)
KeyError: 'int_attr_fun'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/tmp/test.py", line 169, in test_purification
potion.int_attr_fun(self._target)
File "/tmp/solution.py", line 124, in __getattr__
raise TypeError("Effect is depleted.")
TypeError: Effect is depleted.

======================================================================
FAIL: test_deprecation (test.TestPotionOperations)
Test deprecation of a potion.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 257, in test_deprecation
with self.assertRaisesRegex(TypeError, 'Potion is now part of something bigger than itself\.'):
AssertionError: TypeError not raised

======================================================================
FAIL: test_applying_depleted_potion (test.TestГоспожатаПоХимия)
Test applying a depleted potion or a potion that was used in a reaction.
----------------------------------------------------------------------
TypeError: Potion is now part of something bigger than itself.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/tmp/test.py", line 382, in test_applying_depleted_potion
with self.assertRaisesRegex(TypeError, 'Potion is depleted\.'):
AssertionError: "Potion is depleted\." does not match "Potion is now part of something bigger than itself."

======================================================================
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=6, errors=1)

Дискусия
Виктор Бечев
08.12.2023 13:56

Отвъд прекалено за моя вкус либералната употреба на нови редове - добре структуриран и четим код, браво.
История
Това решение има само една версия.