1class Egg:
2
3 def __init__(self):
4 self.colors = []
5 self.total_percentage = 0
6 self.top_cracked = False
7 self.bottom_cracked = False
8 self.tournament = None
9
10 def paint(self, *args):
11
12 new_percentage = 0
13
14 for hex_color, percentage in args:
15 new_percentage += percentage
16
17 if self.total_percentage + new_percentage > 100:
18 raise ValueError
19
20 self.colors.extend((hex_color.upper(), percentage) for hex_color, percentage in args)
21 self.total_percentage += new_percentage
22
23 def hex_color_value(self, hex_color):
24
25 first_hex_pair = hex_color[0:2]
26 second_hex_pair = hex_color[2:4]
27 third_hex_pair = hex_color[4:6]
28
29 sum_hex_color_value = int(first_hex_pair, 16) + int(second_hex_pair, 16) + int(third_hex_pair, 16)
30
31 return sum_hex_color_value
32
33 def overlap(self, start1, end1, start2, end2):
34
35 return max(0, min(end1, end2) - max(start1, start2))
36
37 def egg_half_values(self):
38
39 current_position = 0
40 top_value = 0
41 bottom_value = 0
42
43 for hex_color, percentage in self.colors:
44 start_position = current_position
45 end_position = start_position + percentage
46
47 raw_pigment_value = self.hex_color_value(hex_color)
48 pigment_value = raw_pigment_value if raw_pigment_value != 0 else 1
49 top_part = self.overlap(start_position, end_position, 0, 50)
50 bottom_part = self.overlap(start_position, end_position, 50, 100)
51
52 top_value += top_part * pigment_value / 50
53 bottom_value += bottom_part * pigment_value / 50
54
55 current_position = end_position
56
57 return top_value, bottom_value
58
59 def __mul__(self, other):
60
61 if self.top_cracked or other.top_cracked:
62 raise TypeError
63
64 my_top_value = self.egg_half_values()[0]
65 other_top_value = other.egg_half_values()[0]
66
67 if my_top_value > other_top_value:
68 other.top_cracked = True
69 winner = self
70 else:
71 self.top_cracked = True
72 winner = other
73
74 if self.tournament is not None and self.tournament is other.tournament:
75 self.tournament.record_match(self, other, "top", winner)
76
77 return winner
78
79 def __matmul__(self, other):
80
81 if self.bottom_cracked or other.bottom_cracked:
82 raise TypeError
83
84 my_bottom_value = self.egg_half_values()[1]
85 other_bottom_value = other.egg_half_values()[1]
86
87 if my_bottom_value > other_bottom_value:
88 other.bottom_cracked = True
89 winner = self
90 else:
91 self.bottom_cracked = True
92 winner = other
93
94 if self.tournament is not None and self.tournament is other.tournament:
95 self.tournament.record_match(self, other, "bottom", winner)
96
97 return winner
98
99class EggTournament:
100
101 def __init__(self):
102 self.egg_to_name = {}
103 self.name_to_egg = {}
104 self.victories = {}
105 self.matches = {}
106
107 def register(self, egg, name):
108
109 if not name.isidentifier():
110 raise ValueError("Invalid registration name")
111
112 if egg.tournament is not None:
113 raise ValueError("An egg cannot be registered in multiple tournaments")
114
115 if name in self.name_to_egg:
116 raise ValueError(f"Egg with name {name} has already been registered")
117
118 self.egg_to_name[egg] = name
119 self.name_to_egg[name] = egg
120 self.victories[egg] = 0
121 egg.tournament = self
122
123 def __contains__(self, egg):
124 return egg in self.egg_to_name
125
126 def get_position(self, egg):
127
128 egg_victories = self.victories[egg]
129 count_position = 0
130
131 for victories in set(self.victories.values()):
132 count_position += 1 if victories > egg_victories else 0
133
134 return count_position + 1
135
136 def __getattr__(self, name):
137
138 if name not in self.name_to_egg:
139 raise AttributeError("Apologies, there is no such egg registered")
140
141 egg = self.name_to_egg[name]
142
143 return {
144 "position": self.get_position(egg),
145 "victories": self.victories[egg]
146 }
147
148 def record_match(self, egg1, egg2, side, winner):
149
150 self.matches[(frozenset({egg1, egg2}), side)] = winner
151 self.victories[winner] += 1
152
153 def __getitem__(self, key):
154
155 if isinstance(key, tuple):
156 egg1, egg2, side = key
157 elif isinstance(key, slice):
158 egg1, egg2, side = key.start, key.stop, key.step
159 else:
160 raise KeyError
161
162 match_key = (frozenset({egg1, egg2}), side)
163
164 if match_key not in self.matches:
165 raise KeyError
166
167 return self.matches[match_key]
168
169 def __rmatmul__(self, position):
170 eggs_at_position = {egg for egg in self.victories if self.get_position(egg) == position}
171
172 if not eggs_at_position:
173 raise IndexError
174
175 if len(eggs_at_position) == 1:
176 return next(iter(eggs_at_position))
177
178 return eggs_at_position
..............................................
----------------------------------------------------------------------
Ran 46 tests in 0.002s
OK
17.04.2026 21:59
17.04.2026 22:01
17.04.2026 22:03
17.04.2026 22:04
17.04.2026 22:04
17.04.2026 22:05