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

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

4 точки общо

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

  1from keyword import iskeyword
  2
  3
  4class Egg:
  5
  6    def __init__(self):
  7        self.upper_colors = {}
  8        self.lower_colors = {}
  9        self.percentage_colored = 0.0
 10        self.bottom_broken = False
 11        self.top_broken = False
 12        self.tournament = None
 13
 14    def paint(self, *color_pairs):
 15        new_total = self.percentage_colored + sum(p for _, p in color_pairs)
 16        if new_total > 100.0:
 17            raise ValueError("Egg color cannot exceed 100%")
 18
 19        for hex_color, percentage in color_pairs:
 20
 21            start = self.percentage_colored
 22            end = self.percentage_colored + percentage
 23            hex_color = hex_color.upper()
 24
 25            if start > 50.0:
 26                self.lower_colors[hex_color] = self.lower_colors.get(hex_color, 0) + percentage
 27                self.percentage_colored += percentage
 28                continue
 29
 30            if start < 50 and end > 50:
 31                upper_part = 50 - self.percentage_colored
 32                lower_part =  percentage - upper_part
 33                self.upper_colors[hex_color] = self.upper_colors.get(hex_color, 0) + upper_part
 34                self.lower_colors[hex_color] = self.lower_colors.get(hex_color, 0) + lower_part
 35                self.percentage_colored += percentage
 36                continue
 37
 38            if end <= 50.0:
 39                self.upper_colors[hex_color] = self.upper_colors.get(hex_color, 0) + percentage
 40                self.percentage_colored += percentage
 41                continue
 42
 43    def register_in_tournament(self, tournament):
 44        self.tournament = tournament
 45
 46
 47    def __mul__(self, other):
 48        if self.bottom_broken or other.bottom_broken:
 49            raise TypeError("Egg is broken")
 50        winner = None
 51        if self.get_topside_pigment() < other.get_topside_pigment():
 52            self.topside_broken = True
 53            winner = other
 54        else:
 55            other.top_broken = True
 56            winner = self
 57
 58        if self.tournament == other.tournament and self.tournament is not None:
 59            self.tournament.log_result(self, other, "top", winner)
 60            winner.tournament.add_point_to_egg(winner)
 61        return winner
 62
 63    def __matmul__(self, other):
 64        if self.bottom_broken or other.bottom_broken:
 65            raise TypeError("Egg is broken")
 66        winner = None
 67        if self.get_bottomside_pigment() < other.get_bottomside_pigment():
 68            self.bottom_broken = True
 69            winner = other
 70        else:
 71            other.bottom_broken = True
 72            winner = self
 73
 74        if self.tournament == other.tournament and self.tournament is not None:
 75            self.tournament.log_result(self, other, "bottom", winner)
 76            winner.tournament.add_point_to_egg(winner)
 77        return winner
 78
 79    def get_topside_pigment(self):
 80        pigment = 0
 81        for colour, percentage in self.upper_colors.items():
 82            r = int(colour[0:2], 16)
 83            g = int(colour[2:4], 16)
 84            b = int(colour[4:6], 16)
 85            pigment += percentage * (r + g + b)
 86        if self.percentage_colored > 0.0:
 87            pigment += 0.0001
 88
 89        return pigment
 90
 91
 92    def get_bottomside_pigment(self):
 93        pigment = 0
 94        for colour, percentage in self.lower_colors.items():
 95            r = int(colour[0:2], 16)
 96            g = int(colour[2:4], 16)
 97            b = int(colour[4:6], 16)
 98            pigment += percentage * (r + g + b)
 99        if self.percentage_colored > 50.0:
100            pigment += 0.0001
101
102        return pigment
103
104class EggTournament:
105    registered_eggs = set()
106
107    def __init__(self):
108        self.eggs = {}
109        self.result = {}
110        self.ranking = {}
111
112    def register(self, egg, name):
113        if egg in self.registered_eggs:
114            raise ValueError("An egg cannot be registered in multiple tournaments")
115        if not name.isidentifier() or iskeyword(name):
116            raise ValueError("Invalid registration name")
117        if name in self.eggs:
118            raise ValueError(f"Egg with name {name} has already been registered")
119        self.eggs[name] = egg
120        self.registered_eggs.add(egg)
121        egg.register_in_tournament(self)
122        self.ranking[egg] = 0
123
124    def log_result(self, egg1, egg2, side, outcome):
125        self.result[(egg1,egg2, side)] = outcome
126
127    def __getitem__(self, index):
128        if isinstance(index, slice):
129            egg1, egg2, side = index.start, index.stop, index.step
130        else:
131            egg1, egg2, side = index
132
133        if (egg1, egg2, side) in self.result:
134            return self.result[(egg1, egg2, side)]
135        if (egg2, egg1, side) in self.result:
136            return self.result[(egg2, egg1, side)]
137        raise KeyError("No such battle has occurred")
138
139    def add_point_to_egg(self, egg):
140        self.ranking[egg] = self.ranking.get(egg, 0) + 1
141
142    def __rmatmul__(self, other):
143        if other <= 0:
144            raise IndexError("index out of bounds")
145        ranklist = {}
146        for egg, points in self.ranking.items():
147            ranklist.setdefault(points, set()).add(egg)
148
149        sorted_wins = sorted(ranklist.items(), reverse=True, key=lambda x: x[0])
150
151        if len(sorted_wins) < other:
152            raise IndexError("Index out of bounds")
153
154        return sorted_wins[other - 1][1]
155
156    def __getattr__(self, name):
157        if name not in self.eggs:
158            raise AttributeError("Apologies, there is no such egg registered")
159        target_egg = self.eggs[name]
160
161        wins_to_eggs = {}
162        for egg, points in self.ranking.items():
163            wins_to_eggs.setdefault(points, set()).add(egg)
164
165        sorted_wins = sorted(wins_to_eggs.keys(), reverse=True)
166        victories = self.ranking[target_egg]
167        position = sorted_wins.index(victories) + 1
168        return {"position": position, "victories": victories}
169
170    def __contains__(self, egg):
171        return egg in self.registered_eggs

.FFFF.F.F....F..........F...F.F.......F.FF..F.
======================================================================
FAIL: test_breaking_one_side_does_not_prevent_using_the_other_side (test.TestEgg.test_breaking_one_side_does_not_prevent_using_the_other_side)
Breaking one side of an egg should not prevent using the other side.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 293, in test_breaking_one_side_does_not_prevent_using_the_other_side
self.assertIs(third_egg @ fourth_egg, fourth_egg)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb6435c0> is not <solution.Egg object at 0x7599bb494950>

======================================================================
FAIL: test_broken_side_raises_type_error_regardless_of_operand_position (test.TestEgg.test_broken_side_raises_type_error_regardless_of_operand_position)
Using a broken side in a collision should raise a TypeError regardless of operand position.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 262, in test_broken_side_raises_type_error_regardless_of_operand_position
with self.assertRaises(TypeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^
AssertionError: TypeError not raised

======================================================================
FAIL: test_collision_result_is_independent_of_operand_order (test.TestEgg.test_collision_result_is_independent_of_operand_order)
Swapping the egg operands should not change the collision winner.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 227, in test_collision_result_is_independent_of_operand_order
self.assertIs(
~~~~~~~~~~~~~^
reversed_bottom_second_egg @ reversed_bottom_first_egg,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
reversed_bottom_first_egg,
^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
AssertionError: <solution.Egg object at 0x7599bb4889f0> is not <solution.Egg object at 0x7599bb6b13d0>

======================================================================
FAIL: test_collision_with_partially_painted_eggs (test.TestEgg.test_collision_with_partially_painted_eggs)
Partially painted eggs should collide correctly from both sides.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 193, in test_collision_with_partially_painted_eggs
self.assertIs(first_egg @ second_egg, second_egg)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb4887e0> is not <solution.Egg object at 0x7599bb66e850>

======================================================================
FAIL: test_losing_side_becomes_unusable (test.TestEgg.test_losing_side_becomes_unusable)
Losing a collision should make the losing side unusable.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 240, in test_losing_side_becomes_unusable
with self.assertRaises(TypeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^
AssertionError: TypeError not raised

======================================================================
FAIL: test_paint_can_be_called_multiple_times (test.TestEgg.test_paint_can_be_called_multiple_times)
Painting an egg in multiple calls should preserve the full painting order.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 55, in test_paint_can_be_called_multiple_times
self.assertIs(egg @ bottom_opponent, egg)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb49c550> is not <solution.Egg object at 0x7599bb49c450>

======================================================================
FAIL: test_paint_order_of_color_chunks_matters (test.TestEgg.test_paint_order_of_color_chunks_matters)
Painting the same colors in different orders should change the collision result.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 123, in test_paint_order_of_color_chunks_matters
self.assertIs(first_egg @ second_egg, second_egg)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb49c3d0> is not <solution.Egg object at 0x7599bb49c550>

======================================================================
FAIL: test_collision_between_two_registered_eggs_is_recorded (test.TestEggTournament.test_collision_between_two_registered_eggs_is_recorded)
A collision between two registered eggs should be recorded in the tournament.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 373, in test_collision_between_two_registered_eggs_is_recorded
self.assertIs(1 @ tournament, first_egg)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: {<solution.Egg object at 0x7599bb49c4d0>} is not <solution.Egg object at 0x7599bb49c4d0>

======================================================================
FAIL: test_egg_broken_outside_tournament_remains_broken_inside_tournament (test.TestEggTournament.test_egg_broken_outside_tournament_remains_broken_inside_tournament)
Breaking an egg outside the tournament should preserve its broken state inside the tournament.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 406, in test_egg_broken_outside_tournament_remains_broken_inside_tournament
with self.assertRaises(TypeError):
~~~~~~~~~~~~~~~~~^^^^^^^^^^^
AssertionError: TypeError not raised

======================================================================
FAIL: test_failed_registration_in_second_tournament_does_not_remove_first_registration (test.TestEggTournament.test_failed_registration_in_second_tournament_does_not_remove_first_registration)
Failing to register an egg in a second tournament should not remove its first registration.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 363, in test_failed_registration_in_second_tournament_does_not_remove_first_registration
self.assertNotIn(egg, second_tournament)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb49c7d0> unexpectedly found in <solution.EggTournament object at 0x7599bb651e50>

======================================================================
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 535, in test_ranking_missing_position_raises_index_error
self.assertIs(beta @ delta, beta)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb49d050> is not <solution.Egg object at 0x7599bb49cf50>

======================================================================
FAIL: test_ranking_unique_position_returns_single_egg (test.TestEggTournament.test_ranking_unique_position_returns_single_egg)
Looking up a unique ranking position should return a single egg.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 478, in test_ranking_unique_position_returns_single_egg
self.assertIs(1 @ tournament, alpha)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: {<solution.Egg object at 0x7599bb49d3d0>} is not <solution.Egg object at 0x7599bb49d3d0>

======================================================================
FAIL: 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 511, in test_ranking_uses_dense_ranking_without_skipping_places
self.assertIs(beta @ delta, beta)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb49dad0> is not <solution.Egg object at 0x7599bb49d8d0>

======================================================================
FAIL: test_registered_egg_attribute_returns_position_and_victories (test.TestEggTournament.test_registered_egg_attribute_returns_position_and_victories)
Accessing a registered egg as an attribute should return its position and victories.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 558, in test_registered_egg_attribute_returns_position_and_victories
self.assertIs(beta @ delta, beta)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
AssertionError: <solution.Egg object at 0x7599bb49e2d0> is not <solution.Egg object at 0x7599bb49e1d0>

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

FAILED (failures=14)

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