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

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

6 точки общо

43 успешни теста
3 неуспешни теста
Код

  1class Egg:
  2    def __init__(self):
  3        self._segments = []
  4        self._filled = 0.0
  5        self._broken_top = False
  6        self._broken_bottom = False
  7        self._tournament = None
  8
  9    def paint(self, *args):
 10        total_new = sum(p for _, p in args)
 11
 12        if self._filled + total_new > 100.0:
 13            raise ValueError("Too much paint")
 14
 15        current = self._filled
 16
 17        for hex_color, percentage in args:
 18            pigment = self._pigment(hex_color)
 19
 20            start = current
 21            end = current + percentage
 22
 23            if start < 50 < end:
 24                self._segments.append((start, 50, pigment))
 25                self._segments.append((50, end, pigment))
 26            else:
 27                self._segments.append((start, end, pigment))
 28
 29            current = end
 30
 31        self._filled += total_new
 32
 33    def _pigment(self, hex_color):
 34        r = int(hex_color[0:2], 16)
 35        g = int(hex_color[2:4], 16)
 36        b = int(hex_color[4:6], 16)
 37        return r + g + b
 38
 39    def _strength(self, top):
 40        if top and self._broken_top:
 41            raise TypeError("Top side is broken")
 42        if not top and self._broken_bottom:
 43            raise TypeError("Bottom side is broken")
 44
 45        low, high = (0, 50) if top else (50, 100)
 46        total = 0.0
 47
 48        for start, end, pigment in self._segments:
 49            overlap_start = max(start, low)
 50            overlap_end = min(end, high)
 51
 52            if overlap_start < overlap_end:
 53                portion = (overlap_end - overlap_start) / 50
 54                total += portion * pigment
 55
 56        return total
 57
 58    def _battle(self, other, top):
 59        s1 = self._strength(top)
 60        s2 = other._strength(top)
 61
 62        if s1 > s2:
 63            winner, loser = self, other
 64        else:
 65            winner, loser = other, self
 66
 67        if top:
 68            loser._broken_top = True
 69        else:
 70            loser._broken_bottom = True
 71
 72        if self._tournament and self._tournament is other._tournament:
 73            self._tournament.record(self, other, "top" if top else "bottom", winner)
 74
 75        return winner
 76
 77    def __mul__(self, other):
 78        return self._battle(other, True)
 79
 80    def __matmul__(self, other):
 81        return self._battle(other, False)
 82
 83
 84class EggTournament:
 85    def __init__(self):
 86        self._eggs = {}
 87        self._names = {}
 88        self._history = {}
 89        self._wins = {}
 90
 91    def register(self, egg, name):
 92        if not name.isidentifier():
 93            raise ValueError("Invalid registration name")
 94
 95        if name in self._eggs:
 96            raise ValueError(f"Egg with name {name} has already been registered")
 97
 98        if egg._tournament is not None:
 99            raise ValueError("An egg cannot be registered in multiple tournaments")
100
101        self._eggs[name] = egg
102        self._names[egg] = name
103        self._wins[egg] = 0
104        egg._tournament = self
105
106    def _pair_key(self, egg1, egg2):
107        return (egg1, egg2) if id(egg1) < id(egg2) else (egg2, egg1)
108
109    def record(self, egg1, egg2, side, winner):
110        if egg1 not in self._names or egg2 not in self._names:
111            return
112
113        key = self._pair_key(egg1, egg2), side
114        self._history[key] = winner
115        self._wins[winner] += 1
116
117    def __getitem__(self, item):
118        if isinstance(item, tuple):
119            egg1, egg2, side = item
120        elif isinstance(item, slice):
121            egg1, egg2, side = item.start, item.stop, item.step
122        else:
123            raise KeyError
124
125        key = self._pair_key(egg1, egg2), side
126
127        if key not in self._history:
128            raise KeyError
129
130        return self._history[key]
131
132    def __contains__(self, egg):
133        return egg in self._names
134
135    def __getattr__(self, name):
136        if name not in self._eggs:
137            raise AttributeError("Apologies, there is no such egg registered")
138
139        egg = self._eggs[name]
140        return {
141            "position": self._position(egg),
142            "victories": self._wins[egg]
143        }
144
145    @property
146    def ranking(self):
147        sorted_eggs = sorted(self._wins.items(), key=lambda x: -x[1])
148
149        ranking = {}
150        current_pos = 1
151        last_wins = None
152
153        for i, (egg, wins) in enumerate(sorted_eggs):
154            if wins != last_wins:
155                current_pos = i + 1
156
157            if current_pos not in ranking:
158                ranking[current_pos] = set()
159
160            ranking[current_pos].add(egg)
161            last_wins = wins
162
163        return ranking
164
165    def _position(self, egg):
166        for pos, eggs in self.ranking.items():
167            if egg in eggs:
168                return pos
169
170    def __rmatmul__(self, position):
171        if position not in self.ranking:
172            raise IndexError
173
174        eggs = self.ranking[position]
175
176        if len(eggs) == 1:
177            return list(eggs)[0]
178
179        return eggs

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

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

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

Дискусия
История

f1class Egg:f1class Egg:
2    def __init__(self):2    def __init__(self):
3        self._segments = []3        self._segments = []
4        self._filled = 0.04        self._filled = 0.0
5        self._broken_top = False5        self._broken_top = False
6        self._broken_bottom = False6        self._broken_bottom = False
7        self._tournament = None7        self._tournament = None
88
9    def paint(self, *args):9    def paint(self, *args):
10        total_new = sum(p for _, p in args)10        total_new = sum(p for _, p in args)
1111
12        if self._filled + total_new > 100.0:12        if self._filled + total_new > 100.0:
13            raise ValueError("Too much paint")13            raise ValueError("Too much paint")
1414
15        current = self._filled15        current = self._filled
1616
17        for hex_color, percentage in args:17        for hex_color, percentage in args:
18            pigment = self._pigment(hex_color)18            pigment = self._pigment(hex_color)
1919
20            start = current20            start = current
21            end = current + percentage21            end = current + percentage
2222
23            if start < 50 < end:23            if start < 50 < end:
24                self._segments.append((start, 50, pigment))24                self._segments.append((start, 50, pigment))
25                self._segments.append((50, end, pigment))25                self._segments.append((50, end, pigment))
26            else:26            else:
27                self._segments.append((start, end, pigment))27                self._segments.append((start, end, pigment))
2828
29            current = end29            current = end
3030
31        self._filled += total_new31        self._filled += total_new
3232
33    def _pigment(self, hex_color):33    def _pigment(self, hex_color):
n34        hex_color = hex_color.lower()n
35        r = int(hex_color[0:2], 16)34        r = int(hex_color[0:2], 16)
36        g = int(hex_color[2:4], 16)35        g = int(hex_color[2:4], 16)
37        b = int(hex_color[4:6], 16)36        b = int(hex_color[4:6], 16)
38        return r + g + b37        return r + g + b
3938
n40    def _strength(self, top=True):n39    def _strength(self, top):
41        if top and self._broken_top:40        if top and self._broken_top:
42            raise TypeError("Top side is broken")41            raise TypeError("Top side is broken")
43        if not top and self._broken_bottom:42        if not top and self._broken_bottom:
44            raise TypeError("Bottom side is broken")43            raise TypeError("Bottom side is broken")
4544
46        low, high = (0, 50) if top else (50, 100)45        low, high = (0, 50) if top else (50, 100)
n47 n
48        total = 0.046        total = 0.0
4947
50        for start, end, pigment in self._segments:48        for start, end, pigment in self._segments:
51            overlap_start = max(start, low)49            overlap_start = max(start, low)
52            overlap_end = min(end, high)50            overlap_end = min(end, high)
5351
54            if overlap_start < overlap_end:52            if overlap_start < overlap_end:
55                portion = (overlap_end - overlap_start) / 5053                portion = (overlap_end - overlap_start) / 50
56                total += portion * pigment54                total += portion * pigment
5755
58        return total56        return total
5957
n60    def _battle(self, other, top=True):n58    def _battle(self, other, top):
61        s1 = self._strength(top)59        s1 = self._strength(top)
62        s2 = other._strength(top)60        s2 = other._strength(top)
6361
64        if s1 > s2:62        if s1 > s2:
65            winner, loser = self, other63            winner, loser = self, other
66        else:64        else:
67            winner, loser = other, self65            winner, loser = other, self
6866
69        if top:67        if top:
70            loser._broken_top = True68            loser._broken_top = True
71        else:69        else:
72            loser._broken_bottom = True70            loser._broken_bottom = True
7371
74        if self._tournament and self._tournament is other._tournament:72        if self._tournament and self._tournament is other._tournament:
n75            self._tournament._record(self, other, "top" if top else "bottom", winner)n73            self._tournament.record(self, other, "top" if top else "bottom", winner)
7674
77        return winner75        return winner
7876
79    def __mul__(self, other):77    def __mul__(self, other):
n80        return self._battle(other, top=True)n78        return self._battle(other, True)
8179
82    def __matmul__(self, other):80    def __matmul__(self, other):
n83        return self._battle(other, top=False)n81        return self._battle(other, False)
8482
8583
86class EggTournament:84class EggTournament:
87    def __init__(self):85    def __init__(self):
88        self._eggs = {}86        self._eggs = {}
89        self._names = {}87        self._names = {}
90        self._history = {}88        self._history = {}
91        self._wins = {}89        self._wins = {}
9290
93    def register(self, egg, name):91    def register(self, egg, name):
94        if not name.isidentifier():92        if not name.isidentifier():
95            raise ValueError("Invalid registration name")93            raise ValueError("Invalid registration name")
9694
97        if name in self._eggs:95        if name in self._eggs:
98            raise ValueError(f"Egg with name {name} has already been registered")96            raise ValueError(f"Egg with name {name} has already been registered")
9997
100        if egg._tournament is not None:98        if egg._tournament is not None:
101            raise ValueError("An egg cannot be registered in multiple tournaments")99            raise ValueError("An egg cannot be registered in multiple tournaments")
102100
103        self._eggs[name] = egg101        self._eggs[name] = egg
104        self._names[egg] = name102        self._names[egg] = name
105        self._wins[egg] = 0103        self._wins[egg] = 0
106        egg._tournament = self104        egg._tournament = self
107105
108    def _pair_key(self, egg1, egg2):106    def _pair_key(self, egg1, egg2):
109        return (egg1, egg2) if id(egg1) < id(egg2) else (egg2, egg1)107        return (egg1, egg2) if id(egg1) < id(egg2) else (egg2, egg1)
110108
n111    def _record(self, egg1, egg2, side, winner):n109    def record(self, egg1, egg2, side, winner):
112        if egg1 not in self._names or egg2 not in self._names:110        if egg1 not in self._names or egg2 not in self._names:
113            return111            return
114112
115        key = self._pair_key(egg1, egg2), side113        key = self._pair_key(egg1, egg2), side
116        self._history[key] = winner114        self._history[key] = winner
117        self._wins[winner] += 1115        self._wins[winner] += 1
118116
119    def __getitem__(self, item):117    def __getitem__(self, item):
120        if isinstance(item, tuple):118        if isinstance(item, tuple):
121            egg1, egg2, side = item119            egg1, egg2, side = item
122        elif isinstance(item, slice):120        elif isinstance(item, slice):
123            egg1, egg2, side = item.start, item.stop, item.step121            egg1, egg2, side = item.start, item.stop, item.step
124        else:122        else:
125            raise KeyError123            raise KeyError
126124
127        key = self._pair_key(egg1, egg2), side125        key = self._pair_key(egg1, egg2), side
128126
129        if key not in self._history:127        if key not in self._history:
130            raise KeyError128            raise KeyError
131129
132        return self._history[key]130        return self._history[key]
133131
134    def __contains__(self, egg):132    def __contains__(self, egg):
135        return egg in self._names133        return egg in self._names
136134
137    def __getattr__(self, name):135    def __getattr__(self, name):
138        if name not in self._eggs:136        if name not in self._eggs:
139            raise AttributeError("Apologies, there is no such egg registered")137            raise AttributeError("Apologies, there is no such egg registered")
140138
141        egg = self._eggs[name]139        egg = self._eggs[name]
n142        victories = self._wins[egg]n140        return {
143        position = self._position(egg)141            "position": self._position(egg),
142            "victories": self._wins[egg]
143        }
144144
n145        return {"position": position, "victories": victories}n145    @property
146 
147    def _ranking(self):146    def ranking(self):
148        sorted_eggs = sorted(self._wins.items(), key=lambda x: -x[1])147        sorted_eggs = sorted(self._wins.items(), key=lambda x: -x[1])
149148
150        ranking = {}149        ranking = {}
151        current_pos = 1150        current_pos = 1
152        last_wins = None151        last_wins = None
153152
154        for i, (egg, wins) in enumerate(sorted_eggs):153        for i, (egg, wins) in enumerate(sorted_eggs):
155            if wins != last_wins:154            if wins != last_wins:
156                current_pos = i + 1155                current_pos = i + 1
nn156 
157            if current_pos not in ranking:157            if current_pos not in ranking:
158                ranking[current_pos] = set()158                ranking[current_pos] = set()
159159
160            ranking[current_pos].add(egg)160            ranking[current_pos].add(egg)
161            last_wins = wins161            last_wins = wins
162162
163        return ranking163        return ranking
164164
165    def _position(self, egg):165    def _position(self, egg):
n166        ranking = self._ranking()n
167        for pos, eggs in ranking.items():166        for pos, eggs in self.ranking.items():
168            if egg in eggs:167            if egg in eggs:
169                return pos168                return pos
170169
171    def __rmatmul__(self, position):170    def __rmatmul__(self, position):
n172        ranking = self._ranking()n
173 
174        if position not in ranking:171        if position not in self.ranking:
175            raise IndexError172            raise IndexError
176173
n177        eggs = ranking[position]n174        eggs = self.ranking[position]
178175
179        if len(eggs) == 1:176        if len(eggs) == 1:
180            return list(eggs)[0]177            return list(eggs)[0]
nn178 
181        return eggs179        return eggs
t182 t
183 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op