Домашни > Великденско домашно > Решения > Решението на Емилияна Атанасова

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

5 точки общо

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

  1FULL_PERCENTAGE = 100
  2HALF_PERCENTAGE = 50
  3NUMBER_SYSTEM = 16
  4COLOR_LEN = 2
  5
  6class Egg:
  7
  8    def __init__(self):
  9        self.painted_percentage = 0
 10        self.paints = []
 11        self.solid_upper_side = True
 12        self.solid_lower_side = True
 13        self.tournament = None
 14
 15    def paint(self, *args):
 16        total = 0
 17        for _, percentage in args:
 18            total += percentage
 19        if self.painted_percentage + total > FULL_PERCENTAGE:
 20            raise ValueError
 21        for hex_color, percentage in args:
 22            self.painted_percentage += percentage
 23            self.paints.append((hex_color, percentage))
 24         
 25    def _pigment(self, color):
 26        r = int(color[0:COLOR_LEN], NUMBER_SYSTEM)
 27        g = int(color[COLOR_LEN:COLOR_LEN * 2], NUMBER_SYSTEM)
 28        b = int(color[COLOR_LEN * 2:COLOR_LEN * 3], NUMBER_SYSTEM)
 29        return r + g + b
 30    
 31    def _strength(self, part):
 32        needed_start = 0 if part == "top" else HALF_PERCENTAGE
 33        needed_end = HALF_PERCENTAGE if part == "top" else FULL_PERCENTAGE
 34        current = 0
 35        total_strength = 0
 36
 37        for color, p in self.paints:
 38            start = current
 39            end = current + p
 40
 41            overlap = max(0, min(end, needed_end) - max(start, needed_start))
 42
 43            if overlap > 0:
 44                ratio = overlap / p
 45                total_strength += self._pigment(color) * ratio
 46
 47            current += p
 48
 49        return total_strength
 50    
 51    def _fight(self, other, part):
 52        if part == "top":
 53            if not self.solid_upper_side or not other.solid_upper_side:
 54                raise TypeError("Already broken side")
 55        else:
 56            if not self.solid_lower_side or not other.solid_lower_side:
 57                raise TypeError("Already broken side")
 58
 59        my_strength = self._strength(part)
 60        other_strength = other._strength(part)
 61
 62        if my_strength > other_strength:
 63            winner, loser = self, other
 64        else:
 65            winner, loser = other, self
 66
 67        if part == "top":
 68            loser.solid_upper_side = False
 69        else:
 70            loser.solid_lower_side = False
 71
 72        if self.tournament and self.tournament is other.tournament:
 73            self.tournament._record(self, other, part, winner)
 74
 75        return winner
 76   
 77    def __mul__(self, other):
 78        return self._fight(other, "top")
 79
 80
 81    def __matmul__(self, other):
 82        return self._fight(other, "bottom")
 83
 84class EggTournament:
 85
 86    def __init__(self):
 87        self.collisions = {}
 88        self.egg_names = {}
 89        self.wins = {}
 90
 91    def register(self, egg, name):
 92        if egg.tournament:
 93            raise ValueError("An egg cannot be registered in multiple tournaments")
 94        if not name.isidentifier():
 95            raise ValueError("Invalid registration name")
 96        if name in self.egg_names:
 97            raise ValueError(f"Egg with name {name} has already been registered")
 98        self.egg_names[name] = egg
 99        self.wins[egg] = 0
100        egg.tournament = self
101
102    def _record(self, egg1, egg2, part, winner):
103        key = frozenset([egg1, egg2]), part
104        self.collisions[key] = winner
105        self.wins[winner] += 1
106
107    def __getitem__(self, key):
108        if isinstance(key, tuple):
109            egg1, egg2, part = key
110        else:  
111            egg1, egg2, part = key.start, key.stop, key.step
112
113        k = frozenset([egg1, egg2]), part
114
115        if k not in self.collisions:
116            raise KeyError
117
118        return self.collisions[k]
119    
120    def _ranking(self):
121        sorted_eggs = sorted(self.wins.items(), key=lambda x: -x[1])
122
123        ranking = {}
124        pos = 1
125        last_score = None
126
127        for i, (egg, score) in enumerate(sorted_eggs):
128            if score != last_score:
129                pos = i + 1
130            if pos not in ranking:
131                ranking[pos] = set()
132            ranking[pos].add(egg)
133            last_score = score
134
135        return ranking
136    
137    def __getattr__(self, name):
138        if name not in self.egg_names:
139            raise AttributeError("Apologies, there is no such egg registered")
140
141        egg = self.egg_names[name]
142        wins = self.wins[egg]
143
144        ranking = self._ranking()
145
146        position = next(pos for pos, eggs in ranking.items() if egg in eggs)
147
148        return {"position": position, "victories": wins}
149
150    def __contains__(self, egg):
151        return egg in self.wins
152    
153    def __rmatmul__(self, position):
154        ranking = self._ranking()
155
156        if position not in ranking:
157            raise IndexError
158
159        result = ranking[position]
160        return next(iter(result)) if len(result) == 1 else result

.........F..F....F...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 157, in __rmatmul__
raise IndexError
IndexError

======================================================================
FAIL: test_paint_chunk_crossing_50_percent_boundary_is_split_correctly (test.TestEgg.test_paint_chunk_crossing_50_percent_boundary_is_split_correctly)
Painting a chunk across the half boundary should split it correctly between the two halves.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 139, in test_paint_chunk_crossing_50_percent_boundary_is_split_correctly
self.assertIs(egg @ opponent, opponent)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x72d5d8e4cd00> is not <solution.Egg object at 0x72d5d8e4cde0>

======================================================================
FAIL: test_paint_multiple_calls_can_cross_50_percent_boundary (test.TestEgg.test_paint_multiple_calls_can_cross_50_percent_boundary)
Painting an egg across the half boundary in multiple calls should split the halves correctly.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 151, in test_paint_multiple_calls_can_cross_50_percent_boundary
self.assertIs(egg @ opponent, opponent)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x72d5d8e4cd00> is not <solution.Egg object at 0x72d5d8e4cde0>

======================================================================
FAIL: test_paint_overflow_with_multiple_colors_should_not_change_the_egg (test.TestEgg.test_paint_overflow_with_multiple_colors_should_not_change_the_egg)
Failing to overpaint an egg with multiple colors should not change the egg.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 163, in test_paint_overflow_with_multiple_colors_should_not_change_the_egg
self.assertIs(egg @ bottom_opponent, bottom_opponent)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x72d5d8e4cd00> is not <solution.Egg object at 0x72d5d8e4cde0>

======================================================================
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 0x72d5d8e4ce50> is not <solution.Egg object at 0x72d5d8e4cd00>

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

Дискусия
Виктор Бечев
16.04.2026 19:01

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