Домашни > Великденско домашно > Решения > Решението на Милица Лазарова

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

6 точки общо

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

  1from collections import defaultdict
  2from keyword import iskeyword
  3
  4
  5class Egg:
  6    def __init__(self):
  7        self.hex_colors_top = []
  8        self.hex_colors_bottom = []
  9        self.percentage = 0
 10        self.top_broken = False
 11        self.bottom_broken = False
 12        self.tournament = None
 13
 14    def paint(self, *args):
 15        to_add = 0.0
 16
 17        for color, percentage in args:
 18            to_add += percentage
 19
 20        if to_add + self.percentage > 100:
 21            raise ValueError("Too much paint")
 22
 23        for color, percentage in args:
 24            color = color.upper()
 25
 26            if self.percentage >= 50:
 27                self.hex_colors_bottom.append((color, percentage))
 28            else:
 29                if percentage + self.percentage <= 50:
 30                    self.hex_colors_top.append((color, percentage))
 31                else:
 32                    top_percentage = 50 - self.percentage
 33                    self.hex_colors_top.append((color, top_percentage))
 34                    self.hex_colors_bottom.append((color, percentage - top_percentage))
 35
 36            self.percentage += percentage
 37
 38    def __color_val(self, color):
 39        r = int(color[0:2], 16)
 40        g = int(color[2:4], 16)
 41        b = int(color[4:], 16)
 42        return r + g + b
 43
 44    def __damage(self, colors):
 45        total_damage = 0.0
 46        painted = 0
 47
 48        for color, percentage in colors:
 49            total_damage += (percentage / 50.0) * self.__color_val(color)
 50            painted += percentage
 51
 52        return (total_damage, painted)
 53
 54    @property
 55    def top_damage(self):
 56        return self.__damage(self.hex_colors_top)
 57
 58    @property
 59    def bottom_damage(self):
 60        return self.__damage(self.hex_colors_bottom)
 61
 62    def __mul__(self, other):
 63        if not isinstance(other, Egg):
 64            return NotImplemented
 65
 66        if self.top_broken or other.top_broken:
 67            raise TypeError("Already broken")
 68
 69        if self.top_damage > other.top_damage:
 70            other.top_broken = True
 71            winner = self
 72            loser = other
 73        else:
 74            self.top_broken = True
 75            winner = other
 76            loser = self
 77
 78        if self.tournament and self.tournament is other.tournament:
 79            self.tournament.record(winner, loser, "top")
 80            self.tournament.add_point(winner)
 81        return winner
 82
 83    def __matmul__(self, other):
 84        if not isinstance(other, Egg):
 85            return NotImplemented
 86
 87        if self.bottom_broken or other.bottom_broken:
 88            raise TypeError("Already broken")
 89
 90        if self.bottom_damage > other.bottom_damage:
 91            other.bottom_broken = True
 92            winner = self
 93            loser = other
 94        else:
 95            self.bottom_broken = True
 96            winner = other
 97            loser = self
 98
 99        if self.tournament and self.tournament is other.tournament:
100            self.tournament.record(winner, loser, "bottom")
101            self.tournament.add_point(winner)
102
103        return winner
104
105
106class EggTournament:
107
108    def __init__(self):
109        self.registered = {}
110        self.history = {}
111        self.points = defaultdict(int)
112
113    def register(self, egg, nickname):
114        if not isinstance(egg, Egg):
115            return NotImplemented
116
117        if egg.tournament is not None:
118            raise ValueError("An egg cannot be registered in multiple tournaments")
119
120        if not nickname.isidentifier() or iskeyword(nickname):
121            raise ValueError("Invalid registration name")
122
123        if nickname in self.registered:
124            raise ValueError(f"Egg with name {nickname} has already been registered")
125
126        self.registered[nickname] = egg
127        egg.tournament = self
128
129    def record(self, winner, loser, side):
130        self.history[(frozenset((winner, loser)), side)] = winner
131
132    def __getitem__(self, key):
133        if isinstance(key, tuple) and len(key) == 3:
134            egg1, egg2, side = key
135        elif isinstance(key, slice):
136            egg1, egg2, side = key.start, key.stop, key.step
137        else:
138            raise KeyError
139
140        key = (frozenset((egg1, egg2)), side)
141
142        if key not in self.history:
143            raise KeyError
144
145        return self.history[key]
146
147    def add_point(self, egg):
148        if not isinstance(egg, Egg):
149            return NotImplemented
150        self.points[egg] += 1
151
152    def __rmatmul__(self, place):
153        grouped_by_points = defaultdict(set)
154
155        for egg in self.registered.values():
156            grouped_by_points[self.points[egg]].add(egg)
157
158        ranked_points = sorted(grouped_by_points.keys(), reverse=True)
159
160        if place < 1 or place > len(ranked_points):
161            raise IndexError()
162
163        result = grouped_by_points[ranked_points[place - 1]]
164
165        if len(result) == 1:
166            return next(iter(result))
167        return result
168
169    def _position(self, egg):
170        ranked_points = set(self.points.values())
171        ranked_points.add(0)
172        ranked_points = list(sorted(ranked_points, reverse=True))
173
174        egg_points = self.points[egg]
175
176        place = 1
177        for pt in ranked_points:
178            if pt == egg_points:
179                return place
180            place += 1
181
182    def __getattr__(self, nickname):
183        if nickname not in self.registered:
184            raise AttributeError("Apologies, there is no such egg registered")
185
186        egg = self.registered[nickname]
187        return {"position": self._position(egg), "victories": self.points[egg]}
188
189    def __contains__(self, egg):
190        return egg in self.registered.values()

..............................................
----------------------------------------------------------------------
Ran 46 tests in 0.001s

OK

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