Домашни > Великденско домашно > Решения > Решението на Николина Маджарова

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

6 точки общо

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

  1class Egg:
  2    def __init__(self):
  3        self.layers = []  # [(value, percent)]
  4        self.total_percent = 0.0
  5        self.broken_top = False
  6        self.broken_bottom = False
  7        self.tournament = None
  8
  9    def _hex_to_value(self, hex_color):
 10        r = int(hex_color[0:2], 16)
 11        g = int(hex_color[2:4], 16)
 12        b = int(hex_color[4:6], 16)
 13        return r + g + b
 14
 15    def paint(self, *args):
 16        add = sum(p for _, p in args)
 17
 18        if self.total_percent + add > 100:
 19            raise ValueError("Overpainting not allowed")
 20
 21        for color, percent in args:
 22            value = self._hex_to_value(color.upper())
 23            self.layers.append((value, percent))
 24            self.total_percent += percent
 25
 26    def _strength(self, part):
 27        if part == "top":
 28            start, end = 0, 50
 29        else:
 30            start, end = 50, 100
 31
 32        cur = 0
 33        strength = 0
 34
 35        for value, percent in self.layers:
 36            nxt = cur + percent
 37
 38            overlap_start = max(cur, start)
 39            overlap_end = min(nxt, end)
 40
 41            if overlap_start < overlap_end:
 42                overlap = overlap_end - overlap_start
 43                strength += value * (overlap / 100)
 44
 45            cur = nxt
 46
 47        return strength
 48
 49    def _fight(self, other, part):
 50        if part == "top":
 51            if self.broken_top or other.broken_top:
 52                raise TypeError("Broken egg side")
 53        else:
 54            if self.broken_bottom or other.broken_bottom:
 55                raise TypeError("Broken egg side")
 56
 57        my_strength = self._strength(part)
 58        other_strength = other._strength(part)
 59
 60        if my_strength >= other_strength:
 61            winner, loser = self, other
 62        else:
 63            winner, loser = other, self
 64
 65        if part == "top":
 66            loser.broken_top = True
 67        else:
 68            loser.broken_bottom = True
 69
 70        if self.tournament is not None and self.tournament is other.tournament:
 71            self.tournament.record(self, other, part, winner)
 72
 73        return winner
 74
 75    def __mul__(self, other):
 76        return self._fight(other, "top")
 77
 78    def __matmul__(self, other):
 79        return self._fight(other, "bottom")
 80
 81
 82class EggTournament:
 83    def __init__(self):
 84        self.eggs = {}      # egg -> name
 85        self.names = {}     # name -> egg
 86        self.history = {}   # (e1, e2, part) -> winner
 87        self.wins = {}
 88
 89    def register(self, egg, name):
 90        if not name.isidentifier():
 91            raise ValueError("Invalid name")
 92
 93        if egg.tournament is not None:
 94            raise ValueError("Egg already in tournament")
 95
 96        if name in self.names:
 97            raise ValueError("Name already used")
 98
 99        self.eggs[egg] = name
100        self.names[name] = egg
101        self.wins[egg] = 0
102        egg.tournament = self
103
104    def record(self, e1, e2, part, winner):
105        if e1.tournament is not self or e2.tournament is not self:
106            return
107
108        name1 = self.eggs[e1]
109        name2 = self.eggs[e2]
110
111        key = (tuple(sorted((e1, e2), key=lambda e: self.eggs[e])), part)
112
113        self.history[key] = winner
114        self.wins[winner] += 1
115
116    def __getitem__(self, key):
117        if isinstance(key, tuple):
118            e1, e2, part = key
119        else:
120            e1, e2, part = key.start, key.stop, key.step
121
122        real_key = (
123            tuple(sorted((e1, e2), key=lambda e: self.eggs[e])),
124            part
125        )
126
127        return self.history[real_key]
128
129    def _ranking(self):
130        sorted_eggs = sorted(
131            self.wins.items(),
132            key=lambda x: (-x[1], id(x[0]))
133        )
134
135        ranking = {}
136        pos = 1
137        prev = None
138
139        for i, (egg, wins) in enumerate(sorted_eggs):
140            if wins != prev:
141                pos = i + 1
142            ranking.setdefault(pos, set()).add(egg)
143            prev = wins
144
145        return ranking
146
147    def __rmatmul__(self, position):
148        ranking = self._ranking()
149
150        if position not in ranking:
151            raise IndexError
152
153        res = ranking[position]
154        return next(iter(res)) if len(res) == 1 else res
155
156    def __getattr__(self, name):
157        if name not in self.names:
158            raise AttributeError("Apologies, there is no such egg registered.")
159
160        egg = self.names[name]
161        ranking = self._ranking()
162
163        for pos, eggs in ranking.items():
164            if egg in eggs:
165                return {
166                    "position": pos,
167                    "victories": self.wins[egg]
168                }
169
170    def __contains__(self, egg):
171        return egg in self.eggs

.....................F.......F.......FF..EFF..
======================================================================
ERROR: test_ranking_uses_dense_ranking_without_skipping_places (test.TestEggTournament.test_ranking_uses_dense_ranking_without_skipping_places)
Looking up ranking positions should use dense ranking without skipping places.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 516, in test_ranking_uses_dense_ranking_without_skipping_places
self.assertEqual(3 @ tournament, {delta, epsilon})
~~^~~~~~~~~~~~
File "/tmp/solution.py", line 151, in __rmatmul__
raise IndexError
IndexError

======================================================================
FAIL: test_unpainted_half_loses_to_half_painted_black (test.TestEgg.test_unpainted_half_loses_to_half_painted_black)
An unpainted half should lose to a half painted in black.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 200, in test_unpainted_half_loses_to_half_painted_black
self.assertIs(unpainted_egg * black_egg, black_egg)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7593f7140de0> is not <solution.Egg object at 0x7593f7140ec0>

======================================================================
FAIL: test_egg_cannot_be_registered_in_second_tournament (test.TestEggTournament.test_egg_cannot_be_registered_in_second_tournament)
Registering an egg in a second tournament should raise a ValueError.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 344, in test_egg_cannot_be_registered_in_second_tournament
self.assertEqual(
~~~~~~~~~~~~~~~~^
str(context.exception),
^^^^^^^^^^^^^^^^^^^^^^^
"An egg cannot be registered in multiple tournaments",
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
AssertionError: 'Egg already in tournament' != 'An egg cannot be registered in multiple tournaments'
- Egg already in tournament
+ An egg cannot be registered in multiple tournaments

======================================================================
FAIL: test_missing_egg_attribute_raises_attribute_error (test.TestEggTournament.test_missing_egg_attribute_raises_attribute_error)
Accessing an unregistered egg as an attribute should raise an AttributeError.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 586, in test_missing_egg_attribute_raises_attribute_error
self.assertEqual(
~~~~~~~~~~~~~~~~^
str(context.exception),
^^^^^^^^^^^^^^^^^^^^^^^
"Apologies, there is no such egg registered",
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
AssertionError: 'Apologies, there is no such egg registered.' != 'Apologies, there is no such egg registered'
- Apologies, there is no such egg registered.
? -
+ Apologies, there is no such egg registered

======================================================================
FAIL: test_ranking_missing_position_raises_index_error (test.TestEggTournament.test_ranking_missing_position_raises_index_error)
Looking up a missing ranking position should raise an IndexError.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 538, in test_ranking_missing_position_raises_index_error
with self.assertRaises(IndexError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
AssertionError: IndexError not raised

======================================================================
FAIL: test_register_duplicate_name_raises_value_error (test.TestEggTournament.test_register_duplicate_name_raises_value_error)
Registering an egg with a duplicate name should raise a ValueError.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 328, in test_register_duplicate_name_raises_value_error
self.assertEqual(
~~~~~~~~~~~~~~~~^
str(context.exception),
^^^^^^^^^^^^^^^^^^^^^^^
"Egg with name the_monster has already been registered",
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
AssertionError: 'Name already used' != 'Egg with name the_monster has already been registered'
- Name already used
+ Egg with name the_monster has already been registered

======================================================================
FAIL: test_register_invalid_name_raises_value_error (test.TestEggTournament.test_register_invalid_name_raises_value_error)
Registering an egg with an invalid name should raise a ValueError.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 315, in test_register_invalid_name_raises_value_error
self.assertEqual(str(context.exception), "Invalid registration name")
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 'Invalid name' != 'Invalid registration name'
- Invalid name
+ Invalid registration name

----------------------------------------------------------------------
Ran 46 tests in 0.004s

FAILED (failures=6, errors=1)

Дискусия
Виктор Бечев
12.04.2026 21:45

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