1class Egg:
2 def __init__(self):
3 self._sum_percent = 0.0
4 self._top_lost = False
5 self._bottom_lost = False
6 self._painted_parts = []
7 self._Egg_tournament = None
8
9 def paint(self, *parts):
10 current_sum = self._sum_percent
11 for part in parts:
12 percent = part[1]
13 current_sum += percent
14 if current_sum > 100.0:
15 raise ValueError("Cannot exceed 100%")
16 for part in parts:
17 hex_color = part[0]
18 percent = part[1]
19 self._painted_parts.append((hex_color.upper(), percent))
20 self._sum_percent += percent
21
22 def _half_of_the_egg(self, top_or_bottom):
23 if top_or_bottom:
24 if self._top_lost:
25 raise TypeError("This egg has already been defeated from the top side!")
26 first, sec = 0.0, 50.0
27 else:
28 if self._bottom_lost:
29 raise TypeError("This egg has already been defeated from the bottom side!")
30 first, sec = 50.0, 100.0
31 pigment_quantity = 0.0
32 current_percentage = 0.0
33 for hex_color, prc_of_part in self._painted_parts:
34 first_part = current_percentage
35 sec_part = current_percentage + prc_of_part
36 current_percentage = sec_part
37 first_overlap = max(first_part,first)
38 sec_overlap = min(sec_part, sec)
39 if sec_overlap > first_overlap:
40 percent_overlap = sec_overlap - first_overlap
41 r = int(hex_color[0:2], 16)
42 g = int(hex_color[2:4], 16)
43 b = int(hex_color[4:6], 16)
44 paint_per_100p = r + g + b
45 pigment_quantity += paint_per_100p * (percent_overlap / 100.0)
46 return pigment_quantity
47
48 def __mul__(self, other):
49
50 if not isinstance(other, Egg):
51 return NotImplemented
52 left = self._half_of_the_egg(top_or_bottom=True)
53 right = other._half_of_the_egg(top_or_bottom=True)
54
55 if left > right:
56 winner = self
57 loser = other
58 else:
59 winner = other
60 loser = self
61 loser._top_lost =True
62
63 if (
64 self._Egg_tournament is not None and
65 other._Egg_tournament is not None and
66 self._Egg_tournament == other._Egg_tournament
67 ):
68 self._Egg_tournament.Battles(self, other, "top", winner)
69
70 return winner
71
72 def __matmul__(self, other):
73
74 if not isinstance(other, Egg):
75 return NotImplemented
76 left = self._half_of_the_egg(top_or_bottom=False)
77 right = other._half_of_the_egg(top_or_bottom=False)
78 if left > right:
79 winner = self
80 loser = other
81 else:
82 winner = other
83 loser = self
84 loser._bottom_lost =True
85 if (
86 self._Egg_tournament is not None and
87 other._Egg_tournament is not None and
88 self._Egg_tournament == other._Egg_tournament
89 ):
90 self._Egg_tournament.Battles(self, other, "bottom", winner)
91 return winner
92
93class EggTournament:
94 def __init__(self):
95 self.name_egg = {}
96 self.egg_name = {}
97 self.win = {}
98 self.storage = {}
99
100 def register(self, egg, name):
101 if not name.isidentifier():
102 raise ValueError("Invalid registration name")
103 if hasattr(egg, '_Egg_tournament') and egg._Egg_tournament is not None:
104 raise ValueError("An egg cannot be registered in multiple tournaments")
105 if name in self.name_egg:
106 raise ValueError(f"Egg with name {name} has already been registered")
107 self.name_egg[name] = egg
108 self.egg_name[egg] = name
109 self.win[egg] = 0
110 egg._Egg_tournament = self
111
112 def Battles(self, egg1, egg2, side, winner):
113 key1 = id(egg1)
114 key2 = id(egg2)
115 if key1 < key2:
116 key = (key1, key2, side)
117 else:
118 key = (key2, key1, side)
119 self.storage[key] = winner
120 if winner in self.win:
121 self.win[winner] += 1
122
123 def _normalize_eggs(self, egg1, egg2):
124 if id(egg1) < id(egg2):
125 return id(egg1), id(egg2)
126 return id(egg2), id(egg1)
127
128 def __getitem__(self, key):
129 if isinstance(key, tuple):
130 if len(key) != 3:
131 raise KeyError("Invalid key")
132 egg1, egg2, side = key
133 elif isinstance(key, slice):
134 egg1 = key.start
135 egg2 = key.stop
136 side = key.step
137 else:
138 raise KeyError("Invalid key")
139 if side not in ("top", "bottom"):
140 raise KeyError("Invalid side")
141 if egg1 not in self.win or egg2 not in self.win:
142 raise KeyError("not a valid registration")
143 key1, key2 = self._normalize_eggs(egg1, egg2)
144 key_tuple = (key1, key2, side)
145 if key_tuple not in self.storage:
146 raise KeyError("there is no battle between these eggs")
147 return self.storage[key_tuple]
148
149 def __matmul__(self, position):
150 if not isinstance(position, int):
151 raise TypeError("Position must be an integer")
152 if position < 1:
153 raise IndexError("position must be >=1")
154 def get_wins(egg):
155 return self.win[egg]
156 sort_eggs = sorted(
157 self.win.keys(),
158 key=get_wins,
159 reverse=True
160 )
161 if position > len(sort_eggs):
162 raise IndexError("position is out of range")
163 winners = []
164 current_winners = None
165 current_group = []
166 for egg in sort_eggs:
167 winner = self.win[egg]
168 if winner != current_winners:
169 if current_group:
170 winners.append(current_group)
171 current_winners = winner
172 current_group = [egg]
173 else:
174 current_group.append(egg)
175 if current_group:
176 winners.append(current_group)
177
178 pos = 1
179 for group in winners:
180 if pos <= position < pos + len(group):
181 if len(group) == 1:
182 return group[0]
183 else:
184 return set(group)
185 pos += len(group)
186 raise IndexError("Invalid position")
187
188 def __getattr__(self, name):
189 if name not in self.name_egg:
190 raise AttributeError("Apologies, there is no such egg registered")
191 egg = self.name_egg[name]
192 victories = self.win[egg]
193 def get_wins(e):
194 return self.win[e]
195 sorted_eggs = sorted(
196 self.win.keys(),
197 key=get_wins,
198 reverse=True
199 )
200 pos = 1
201 i = 0
202 while i < len(sorted_eggs):
203 current = self.win[sorted_eggs[i]]
204 count = 0
205 while i+count < len(sorted_eggs) and self.win[sorted_eggs[i + count]] == current:
206 count += 1
207 for j in range(count):
208 if sorted_eggs[i+j] == egg:
209 return {"position": pos, "victories": victories}
210 pos += count
211 i += count
212
213 return {"position": pos, "victories": victories}
214
215 def __contains__(self, item):
216 return item in self.win
217
.....................F..E.............EEEE....
======================================================================
ERROR: 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)
~~^~~~~~~~~~~~
TypeError: unsupported operand type(s) for @: 'int' and 'EggTournament'
======================================================================
ERROR: 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 539, in test_ranking_missing_position_raises_index_error
_ = 4 @ tournament
~~^~~~~~~~~~~~
TypeError: unsupported operand type(s) for @: 'int' and 'EggTournament'
======================================================================
ERROR: test_ranking_tied_position_returns_set_of_eggs (test.TestEggTournament.test_ranking_tied_position_returns_set_of_eggs)
Looking up a tied ranking position should return a set of eggs.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 492, in test_ranking_tied_position_returns_set_of_eggs
self.assertEqual(1 @ tournament, {alpha, beta})
~~^~~~~~~~~~~~
TypeError: unsupported operand type(s) for @: 'int' and 'EggTournament'
======================================================================
ERROR: 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)
~~^~~~~~~~~~~~
TypeError: unsupported operand type(s) for @: 'int' and 'EggTournament'
======================================================================
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 514, in test_ranking_uses_dense_ranking_without_skipping_places
self.assertIs(1 @ tournament, alpha)
~~^~~~~~~~~~~~
TypeError: unsupported operand type(s) for @: 'int' and 'EggTournament'
======================================================================
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 0x7c5b9b80d0f0> is not <solution.Egg object at 0x7c5b9b80cfa0>
----------------------------------------------------------------------
Ran 46 tests in 0.003s
FAILED (failures=1, errors=5)
15.04.2026 16:13
15.04.2026 16:15
15.04.2026 16:16
15.04.2026 16:17
15.04.2026 16:19
15.04.2026 16:23