Домашни > Великденско домашно > Решения > Решението на Дуйгу Дуран

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

6 точки общо

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

  1import keyword
  2
  3
  4class Egg:
  5    def __init__(self):
  6        self.paint_data = []
  7        self._percentage_painted = 0.0
  8        self.broken_top = False
  9        self.broken_bottom = False
 10        self.tournament = None
 11
 12    def __mul__(self, other):  # сблъсък от горна страна
 13        if self.broken_top:
 14            raise TypeError("This egg's top side is broken and cannot compete again.")
 15        if other.broken_top:
 16            raise TypeError("The other egg's top side is broken and cannot compete again.")
 17
 18        self_strength = self.half_strength(0, 50)
 19        other_strength = other.half_strength(0, 50)
 20
 21        winner = self if self_strength > other_strength else other
 22        loser = other if winner is self else self
 23
 24        winner.broken_top = False
 25        loser.broken_top = True
 26
 27        if (self.tournament is not None
 28                and self.tournament is other.tournament):
 29            self.tournament.record_battle(self, other, "top", winner)
 30
 31        return winner
 32
 33    def __matmul__(self, other):  # сблъсък от долна страна
 34        if self.broken_bottom:
 35            raise TypeError("This egg's bottom side is broken and cannot compete again.")
 36        if other.broken_bottom:
 37            raise TypeError("The other egg's bottom side is broken and cannot compete again.")
 38
 39        self_strength = self.half_strength(50, 100)
 40        other_strength = other.half_strength(50, 100)
 41
 42        winner = self if self_strength > other_strength else other
 43        loser = other if winner is self else self
 44
 45        winner.broken_bottom = False
 46        loser.broken_bottom = True
 47
 48        if (self.tournament is not None
 49                and self.tournament is other.tournament):
 50            self.tournament.record_battle(self, other, "bottom", winner)
 51
 52        return winner
 53
 54    def half_strength(self, half_start, half_end):
 55        current_start = 0.0
 56        strength = 0.0
 57
 58        for hex_color, percentage in self.paint_data:
 59            segment_start = current_start
 60            segment_end = current_start + percentage
 61
 62            overlap = (max(0.0, min(segment_end, half_end) - max(segment_start, half_start)))
 63
 64            if overlap > 0:
 65                pigment_value = Egg.pigment_value(hex_color)
 66                strength += pigment_value * (overlap / 50)
 67
 68            current_start = segment_end
 69
 70        return strength
 71
 72    def paint(self, *hex_color_data):
 73        total_paint_percentage = sum(percentage for _, percentage in hex_color_data)
 74
 75        if total_paint_percentage + self._percentage_painted > 100.0:
 76            raise ValueError("The egg is overpainted.")
 77
 78        for hex_color, percentage in hex_color_data:
 79            self.paint_data.append((hex_color, percentage))
 80            self._percentage_painted += percentage
 81
 82    @staticmethod
 83    def convert_hex_to_rgb(hex_color):
 84        return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4))
 85
 86    @staticmethod
 87    def pigment_value(hex_color):
 88        r, g, b = Egg.convert_hex_to_rgb(hex_color)
 89        return r + g + b
 90
 91
 92class EggTournament:
 93    def __init__(self):
 94        self._eggs = {}
 95        self._egg_to_name = {}
 96        self._victories = {}
 97        self._history = {}
 98
 99    def register(self, egg: Egg, name: str):
100        if not name.isidentifier() or keyword.iskeyword(name):
101            raise ValueError("Invalid registration name")
102
103        if egg.tournament is not None:
104            raise ValueError("An egg cannot be registered in multiple tournaments")
105
106        if name in self._eggs:
107            raise ValueError(f"Egg with name {name} has already been registered")
108
109        self._eggs[name] = egg
110        self._egg_to_name[id(egg)] = name
111        self._victories[id(egg)] = 0
112        egg.tournament = self
113
114    def record_battle(self, egg1: Egg, egg2: Egg, side: str, winner: Egg):
115        if id(egg1) not in self._egg_to_name or id(egg2) not in self._egg_to_name:
116            return
117
118        key = (frozenset({id(egg1), id(egg2)}), side)
119        self._history[key] = winner
120        self._victories[id(winner)] += 1
121
122    def __getitem__(self, item):
123        if isinstance(item, tuple):
124            egg1, egg2, side = item
125        elif isinstance(item, slice):
126            egg1 = item.start
127            egg2 = item.stop
128            side = item.step
129        else:
130            raise KeyError(item)
131
132        side_map = {"top": "top", "bottom": "bottom"}
133        if side not in side_map:
134            raise KeyError(f"Unknown side: {side}")
135
136        key = (frozenset({id(egg1), id(egg2)}), side)
137        if key not in self._history:
138            raise KeyError("No such battle found in the tournament.")
139
140        return self._history[key]
141
142    def __rmatmul__(self, position: int):
143        if not self._eggs:
144            raise IndexError("No eggs registered in this tournament.")
145
146        sorted_eggs = sorted(
147            self._victories.items(),
148            key=lambda kv: kv[1],
149            reverse=True
150        )
151
152        ranks = {}
153        current_rank = 1
154        prev_wins = None
155        for i, (egg_id, wins) in enumerate(sorted_eggs):
156            if wins != prev_wins:
157                current_rank = i + 1
158                prev_wins = wins
159            ranks[egg_id] = current_rank
160
161        result = {
162            self._eggs[self._egg_to_name[egg_id]]
163            for egg_id, rank in ranks.items()
164            if rank == position
165        }
166
167        if not result:
168            raise IndexError(f"No egg at position {position} in the rankings.")
169
170        if len(result) == 1:
171            return next(iter(result))
172        return result
173
174    def __getattr__(self, name: str):
175        if name.startswith("_"):
176            raise AttributeError(f"Apologies, there is no such egg registered")
177
178        eggs = object.__getattribute__(self, "_eggs")
179        victories = object.__getattribute__(self, "_victories")
180
181        if name not in eggs:
182            raise AttributeError("Apologies, there is no such egg registered")
183
184        egg = eggs[name]
185        wins = victories[id(egg)]
186
187        sorted_wins = sorted(victories.values(), reverse=True)
188        rank = 1
189        prev = None
190        for i, v in enumerate(sorted_wins):
191            if v != prev:
192                rank = i + 1
193                prev = v
194            if v == wins:
195                break
196
197        return {"position": rank, "victories": wins}
198
199    def __contains__(self, egg: Egg):
200        return id(egg) in self._egg_to_name

.....................F................F..E....
======================================================================
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 168, in __rmatmul__
raise IndexError(f"No egg at position {position} in the rankings.")
IndexError: No egg at position 3 in the rankings.

======================================================================
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 205, in test_unpainted_half_loses_to_half_painted_black
self.assertIs(black_egg * unpainted_egg, black_egg)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x70904122cfa0> is not <solution.Egg object at 0x70904122ce50>

======================================================================
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

----------------------------------------------------------------------
Ran 46 tests in 0.003s

FAILED (failures=2, errors=1)

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