1import keyword
2
3EPS = 1e-9
4
5class Egg:
6 def __init__(self):
7 self.segments = []
8 self.covered = 0.0
9 self.top_cracked = False
10 self.bottom_cracked = False
11 self.tournament = None
12
13 def paint(self, *pairs):
14 sum_new_percentage = sum(percentage for _, percentage in pairs)
15
16 if self.covered + sum_new_percentage > 100.0 + EPS:
17 raise ValueError("Egg cannot be overpainted")
18
19 for hex_color, percentage in pairs:
20 self.segments.append((hex_color.upper(), percentage))
21
22 self.covered += sum_new_percentage
23
24 def _pigment_value(self, hex_color):
25 r = int(hex_color[0:2], base=16)
26 g = int(hex_color[2:4], base=16)
27 b = int(hex_color[4:6], base=16)
28 return r + g + b
29
30 def _strength(self, side):
31 if side == "top":
32 side_start = 0.0
33 side_end = 50.0
34 elif side == "bottom":
35 side_start = 50.0
36 side_end = 100.0
37
38 current_position = 0.0
39 total_strength = 0.0
40 has_paint = False
41
42 for hex_color, percentage in self.segments:
43 segment_start = current_position
44 segment_end = current_position + percentage
45
46 overlap_start = max(segment_start, side_start)
47 overlap_end = min(segment_end, side_end)
48
49 if overlap_start < overlap_end:
50 has_paint = True
51 segment_portion = (overlap_end - overlap_start) / 50.0
52 total_strength += self._pigment_value(hex_color) * segment_portion
53
54 current_position = segment_end
55
56 return total_strength, has_paint
57
58 def __mul__(self, other):
59 if self.top_cracked or other.top_cracked:
60 raise TypeError("Cannot clash with cracked top side")
61
62 my_strength, my_has_paint = self._strength("top")
63 other_strength, other_has_paint = other._strength("top")
64
65 if my_strength > other_strength:
66 winner = self
67 loser = other
68 elif other_strength > my_strength:
69 winner = other
70 loser = self
71 else:
72 if my_has_paint and not other_has_paint:
73 winner = self
74 loser = other
75 else:
76 winner = other
77 loser = self
78
79 loser.top_cracked = True
80
81 if self.tournament is not None and self.tournament is other.tournament:
82 self.tournament.record_match(self, other, "top", winner)
83
84 return winner
85
86 def __matmul__(self, other):
87 if self.bottom_cracked or other.bottom_cracked:
88 raise TypeError("Cannot clash with cracked bottom side")
89
90 my_strength, my_has_paint = self._strength("bottom")
91 other_strength, other_has_paint = other._strength("bottom")
92
93 if my_strength > other_strength:
94 winner = self
95 loser = other
96 elif other_strength > my_strength:
97 winner = other
98 loser = self
99 else:
100 if my_has_paint and not other_has_paint:
101 winner = self
102 loser = other
103 else:
104 winner = other
105 loser = self
106
107 loser.bottom_cracked = True
108
109 if self.tournament is not None and self.tournament is other.tournament:
110 self.tournament.record_match(self, other, "bottom", winner)
111
112 return winner
113
114
115class EggTournament:
116 def __init__(self):
117 self.eggs_by_name = {}
118 self.names_by_egg = {}
119 self.wins = {}
120 self.matches = {}
121
122 def register(self, egg, name):
123 if not isinstance(egg, Egg):
124 raise TypeError("Invalid egg")
125
126 if egg.tournament is not None:
127 raise ValueError("An egg cannot be registered in multiple tournaments")
128
129 if not isinstance(name, str) or not name.isidentifier() or keyword.iskeyword(name):
130 raise ValueError("Invalid registration name")
131
132 if name in self.eggs_by_name:
133 raise ValueError(f"Egg with name {name} has already been registered")
134
135 self.eggs_by_name[name] = egg
136 self.names_by_egg[egg] = name
137 self.wins[egg] = 0
138 egg.tournament = self
139
140 def record_match(self, egg1, egg2, side, winner):
141 key = (frozenset({egg1, egg2}), side)
142 self.matches[key] = winner
143 self.wins[winner] += 1
144
145 def __getitem__(self, item):
146 if isinstance(item, tuple):
147 if len(item) != 3:
148 raise KeyError
149 egg1, egg2, side = item
150 elif isinstance(item, slice):
151 egg1 = item.start
152 egg2 = item.stop
153 side = item.step
154 else:
155 raise KeyError
156
157 key = (frozenset({egg1, egg2}), side)
158
159 if key not in self.matches:
160 raise KeyError
161
162 return self.matches[key]
163
164 def _ranking(self):
165 grouped_by_wins = {}
166
167 for egg, victories in self.wins.items():
168 if victories not in grouped_by_wins:
169 grouped_by_wins[victories] = set()
170
171 grouped_by_wins[victories].add(egg)
172
173 sorted_victories = sorted(grouped_by_wins.keys(), reverse=True)
174 ranking = {}
175 position = 1
176
177 for victory in sorted_victories:
178 ranking[position] = grouped_by_wins[victory]
179 position += 1
180
181 return ranking
182
183 def __rmatmul__(self, position):
184 ranking = self._ranking()
185
186 if position not in ranking:
187 raise IndexError
188
189 eggs_on_position = ranking[position]
190
191 if len(eggs_on_position) == 1:
192 return next(iter(eggs_on_position))
193
194 return eggs_on_position
195
196 def _ranking_of_egg(self, egg):
197 ranking = self._ranking()
198
199 for position, eggs in ranking.items():
200 if egg in eggs:
201 return position
202
203
204 def __getattr__(self, name):
205 if name not in self.eggs_by_name:
206 raise AttributeError("Apologies, there is no such egg registered")
207
208 egg = self.eggs_by_name[name]
209
210 return {"position": self._ranking_of_egg(egg),
211 "victories": self.wins[egg]}
212
213 def __contains__(self, egg):
214 return egg in self.names_by_egg
..............................................
----------------------------------------------------------------------
Ran 46 tests in 0.001s
OK
15.04.2026 16:34
15.04.2026 16:36
15.04.2026 16:37