Домашни > Хелоуин в Припят > Решения > Решението на Цветомир Гълъбов

Резултати
8 точки от тестове
2 точки от учител

10 точки общо

10 успешни теста
2 неуспешни теста
Код

  1import math
  2
  3
  4def validate_uranium(func):
  5    def wrapper(self, mass, uranium):
  6        if uranium < 0 or uranium > 1:
  7            raise ValueError("Candy object's uranium value must be between 0 and 1 .")
  8        return func(self, mass, uranium)
  9
 10    return wrapper
 11
 12
 13class Candy:
 14    @validate_uranium
 15    def __init__(self, mass, uranium=0):
 16        self.__mass = mass
 17        self.__uranium = uranium
 18
 19    def get_uranium_quantity(self):
 20        return self.__mass * self.__uranium
 21
 22    def get_mass(self):
 23        return self.__mass
 24
 25
 26def validate_possition(func):
 27    def wrapper(self, possition):
 28        if type(possition) is not tuple:
 29            raise TypeError(
 30                "Person object's attribute possition must be of type tuple."
 31            )
 32        elif len(possition) != 2:
 33            raise ValueError(
 34                "Person object's attribute possition must contain two coordinates."
 35            )
 36        return func(self, possition)
 37
 38    return wrapper
 39
 40
 41class Person:
 42    @validate_possition
 43    def __init__(self, possition):
 44        self.__possition = possition
 45
 46    @validate_possition
 47    def set_possition(self, possition):
 48        self.__possition = possition
 49
 50    def get_possition(self):
 51        return self.__possition
 52
 53
 54def validate_candy(func):
 55    def wrapper(self, candy):
 56        if type(candy) is not Candy:
 57            raise TypeError("Kid object can have only Candy objects in its bag.")
 58        return func(self, candy)
 59
 60    return wrapper
 61
 62
 63def check_if_it_is_critital(func):
 64    def wrapper(self):
 65        total_uranium = 0
 66        for candy in self._Kid__bag:
 67            total_uranium += candy.get_uranium_quantity()
 68        if total_uranium > 20:
 69            return func(self, True)
 70        else:
 71            return func(self, False)
 72
 73    return wrapper
 74
 75
 76class Kid(Person):
 77    def __init__(self, possition, initiative):
 78        super().__init__(possition)
 79        self.__bag = set()
 80        self.__initiative = initiative
 81
 82    def get_initiative(self):
 83        return self.__initiative
 84
 85    @validate_candy
 86    def add_candy(self, candy):
 87        self.__bag.add(candy)
 88
 89    @check_if_it_is_critital
 90    def is_critical(self, Dead=False):
 91        return Dead
 92
 93
 94def validate_host_init(func):
 95    def wrapper(self, possition, candy_bag):
 96        valid_candy_bag = set()
 97        for candy in candy_bag:
 98            if len(candy) == 2:
 99                valid_candy_bag.add(Candy(*candy))
100            else:
101                raise ValueError(
102                    "Host object attribute candy_bag must contains candies with two attributes."
103                )
104        return func(self, possition, valid_candy_bag)
105
106    return wrapper
107
108
109def biggest_candy(candies):
110    best_candy = max(candies, key=lambda candy: candy.get_mass())
111    return best_candy
112
113
114class Host(Person):
115    @validate_host_init
116    def __init__(self, possition, candy_bag):
117        super().__init__(possition)
118        self.__candy_bag = candy_bag
119
120    def have_candies(self):
121        return bool(self.__candy_bag)
122
123    def remove_candy(self, func):
124        if self.__candy_bag:
125            element_to_remove = func(self.__candy_bag)
126            self.__candy_bag.remove(element_to_remove)
127            return element_to_remove
128        else:
129            return None
130
131
132def calculate_distance(point1, point2):
133    x1, y1 = point1
134    x2, y2 = point2
135    return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
136
137
138def closest_neighbour(func):
139    def wrapper(self, kid):
140        closest_host = min(
141            (
142                host
143                for host in self.hosts_kids_on_the_door
144                if host not in self.kids_visited[kid]
145            ),
146            key=lambda host: (
147                calculate_distance(host.get_possition(), kid.get_possition()),
148                host.get_possition()[0],
149                host.get_possition()[1],
150            ),
151        )
152        return func(self, kid, closest_host)
153
154    return wrapper
155
156
157def when_should_stop(func):
158    def wrapper(self):
159        if self.hosts_not_out_of_candies() and self.still_unvisited_hosts():
160            return func(self, False)
161        return func(self, True)
162
163    return wrapper
164
165
166class FluxCapacitor:
167    def __init__(self, participants):
168        self.participants = participants
169        self.__init_participarts(participants)
170
171    def __init_participarts(self, participants):
172        self.kids_visited = {}
173        self.hosts_kids_on_the_door = {}
174        self.__victims = set()
175        for participant in participants:
176            if isinstance(participant, Kid):
177                self.kids_visited[participant] = set()
178            elif isinstance(participant, Host):
179                self.hosts_kids_on_the_door[participant] = set()
180
181    # we are happy if even one host have candies left,
182    # so the game makes sence to continue
183    def hosts_not_out_of_candies(self):
184        for host in self.hosts_kids_on_the_door:
185            if host.have_candies():
186                return True
187        return False
188
189    def still_unvisited_hosts(self):
190        hosts_count = len(self.hosts_kids_on_the_door)
191        for kid, visited_hosts in self.kids_visited.items():
192            if len(visited_hosts) < hosts_count:
193                return True
194        return False
195
196    @when_should_stop
197    def __should_stop(self, stop=False):
198        return stop
199
200    def __go_to_host(self, kid, host):
201        self.hosts_kids_on_the_door[host].add(kid)
202        self.kids_visited[kid].add(host)
203        kid.set_possition(host.get_possition())
204
205    @closest_neighbour
206    def __find_host(self, kid, closest_host=None):
207        return closest_host
208
209    def __hosts_give_candies(self):
210        for host, kids_on_the_door in self.hosts_kids_on_the_door.items():
211            if kids_on_the_door:
212                sorted_kids = sorted(
213                    kids_on_the_door, key=lambda kid: kid.get_initiative(), reverse=True
214                )
215                for kid in sorted_kids:
216                    candy = host.remove_candy(biggest_candy)
217                    if candy:
218                        kid.add_candy(candy)
219                    self.hosts_kids_on_the_door[host].discard(
220                        kid
221                    )  # Remove the kid from the set
222
223    def __add_victim(self, kid):
224        self.__victims.add(kid)
225
226    def __have_victims(self):
227        if self.__victims:
228            return True
229        return False
230
231    def __collect_victims(self):
232        for kid in self.kids_visited.keys():
233            if kid.is_critical():
234                self.__add_victim(kid)
235
236    def get_victim(self):
237        while not self.__should_stop():
238            for kid in self.kids_visited:
239                host_to_go = self.__find_host(kid)
240                if host_to_go:
241                    self.__go_to_host(kid, host_to_go)
242            self.__hosts_give_candies()
243            self.__collect_victims()
244            if self.__have_victims():
245                return self.__victims
246        return None
247
248
249kid1 = Kid((0, 0), 5)
250kid2 = Kid((1, 1), 3)
251host1 = Host(
252    (2, 2),
253    [
254        (10, 0.2),
255    ],
256)
257host2 = Host((3, 3), [])
258host3 = Host((4, 4), [(100, 0.1), (99, 0.5)])
259host4 = Host(
260    (5, 5),
261    [(3, 0.4)],
262)
263
264flux = FluxCapacitor({kid1, kid2, host1, host2, host3, host4})
265
266# Run the simulation
267victims = flux.get_victim()
268print("Victims:", victims)

Victims: {<solution.Kid object at 0x7f1a5632b8e0>}
........E..E
======================================================================
ERROR: test_basic_usage (test.KidTest)
Test basic usage of Kid class.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 39, in test_basic_usage
self.assertEqual(kid.get_position(), (0, 0))
AttributeError: 'Kid' object has no attribute 'get_position'

======================================================================
ERROR: test_basic_usage (test.PersonTest)
Test basic usage of Person class.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 24, in test_basic_usage
self.assertEqual(person.get_position(), (0, 0))
AttributeError: 'Person' object has no attribute 'get_position'

----------------------------------------------------------------------
Ran 12 tests in 0.001s

FAILED (errors=2)

Дискусия
Георги Кунчев
07.11.2023 19:02

След дискусия, стана ясно, че има "typo", което е трудно да се хване при тестване, защото просто копи-пействаме код. Правя изключение и добавям двете липсващи точки.
История

f1import mathf1import math
22
33
4def validate_uranium(func):4def validate_uranium(func):
5    def wrapper(self, mass, uranium):5    def wrapper(self, mass, uranium):
6        if uranium < 0 or uranium > 1:6        if uranium < 0 or uranium > 1:
7            raise ValueError("Candy object's uranium value must be between 0 and 1 .")7            raise ValueError("Candy object's uranium value must be between 0 and 1 .")
8        return func(self, mass, uranium)8        return func(self, mass, uranium)
99
10    return wrapper10    return wrapper
1111
1212
13class Candy:13class Candy:
14    @validate_uranium14    @validate_uranium
15    def __init__(self, mass, uranium=0):15    def __init__(self, mass, uranium=0):
16        self.__mass = mass16        self.__mass = mass
17        self.__uranium = uranium17        self.__uranium = uranium
1818
19    def get_uranium_quantity(self):19    def get_uranium_quantity(self):
20        return self.__mass * self.__uranium20        return self.__mass * self.__uranium
2121
22    def get_mass(self):22    def get_mass(self):
23        return self.__mass23        return self.__mass
2424
2525
26def validate_possition(func):26def validate_possition(func):
27    def wrapper(self, possition):27    def wrapper(self, possition):
28        if type(possition) is not tuple:28        if type(possition) is not tuple:
29            raise TypeError(29            raise TypeError(
30                "Person object's attribute possition must be of type tuple."30                "Person object's attribute possition must be of type tuple."
31            )31            )
32        elif len(possition) != 2:32        elif len(possition) != 2:
33            raise ValueError(33            raise ValueError(
34                "Person object's attribute possition must contain two coordinates."34                "Person object's attribute possition must contain two coordinates."
35            )35            )
36        return func(self, possition)36        return func(self, possition)
3737
38    return wrapper38    return wrapper
3939
4040
41class Person:41class Person:
42    @validate_possition42    @validate_possition
43    def __init__(self, possition):43    def __init__(self, possition):
44        self.__possition = possition44        self.__possition = possition
4545
46    @validate_possition46    @validate_possition
47    def set_possition(self, possition):47    def set_possition(self, possition):
48        self.__possition = possition48        self.__possition = possition
4949
50    def get_possition(self):50    def get_possition(self):
51        return self.__possition51        return self.__possition
5252
5353
54def validate_candy(func):54def validate_candy(func):
55    def wrapper(self, candy):55    def wrapper(self, candy):
56        if type(candy) is not Candy:56        if type(candy) is not Candy:
57            raise TypeError("Kid object can have only Candy objects in its bag.")57            raise TypeError("Kid object can have only Candy objects in its bag.")
58        return func(self, candy)58        return func(self, candy)
5959
60    return wrapper60    return wrapper
6161
6262
63def check_if_it_is_critital(func):63def check_if_it_is_critital(func):
64    def wrapper(self):64    def wrapper(self):
65        total_uranium = 065        total_uranium = 0
66        for candy in self._Kid__bag:66        for candy in self._Kid__bag:
67            total_uranium += candy.get_uranium_quantity()67            total_uranium += candy.get_uranium_quantity()
68        if total_uranium > 20:68        if total_uranium > 20:
69            return func(self, True)69            return func(self, True)
70        else:70        else:
71            return func(self, False)71            return func(self, False)
7272
73    return wrapper73    return wrapper
7474
7575
76class Kid(Person):76class Kid(Person):
77    def __init__(self, possition, initiative):77    def __init__(self, possition, initiative):
78        super().__init__(possition)78        super().__init__(possition)
79        self.__bag = set()79        self.__bag = set()
80        self.__initiative = initiative80        self.__initiative = initiative
8181
82    def get_initiative(self):82    def get_initiative(self):
83        return self.__initiative83        return self.__initiative
8484
85    @validate_candy85    @validate_candy
86    def add_candy(self, candy):86    def add_candy(self, candy):
87        self.__bag.add(candy)87        self.__bag.add(candy)
8888
89    @check_if_it_is_critital89    @check_if_it_is_critital
90    def is_critical(self, Dead=False):90    def is_critical(self, Dead=False):
91        return Dead91        return Dead
9292
9393
94def validate_host_init(func):94def validate_host_init(func):
95    def wrapper(self, possition, candy_bag):95    def wrapper(self, possition, candy_bag):
96        valid_candy_bag = set()96        valid_candy_bag = set()
97        for candy in candy_bag:97        for candy in candy_bag:
98            if len(candy) == 2:98            if len(candy) == 2:
99                valid_candy_bag.add(Candy(*candy))99                valid_candy_bag.add(Candy(*candy))
100            else:100            else:
101                raise ValueError(101                raise ValueError(
102                    "Host object attribute candy_bag must contains candies with two attributes."102                    "Host object attribute candy_bag must contains candies with two attributes."
103                )103                )
104        return func(self, possition, valid_candy_bag)104        return func(self, possition, valid_candy_bag)
105105
106    return wrapper106    return wrapper
107107
108108
109def biggest_candy(candies):109def biggest_candy(candies):
110    best_candy = max(candies, key=lambda candy: candy.get_mass())110    best_candy = max(candies, key=lambda candy: candy.get_mass())
111    return best_candy111    return best_candy
112112
113113
114class Host(Person):114class Host(Person):
115    @validate_host_init115    @validate_host_init
116    def __init__(self, possition, candy_bag):116    def __init__(self, possition, candy_bag):
117        super().__init__(possition)117        super().__init__(possition)
118        self.__candy_bag = candy_bag118        self.__candy_bag = candy_bag
119119
120    def have_candies(self):120    def have_candies(self):
121        return bool(self.__candy_bag)121        return bool(self.__candy_bag)
122122
123    def remove_candy(self, func):123    def remove_candy(self, func):
124        if self.__candy_bag:124        if self.__candy_bag:
125            element_to_remove = func(self.__candy_bag)125            element_to_remove = func(self.__candy_bag)
126            self.__candy_bag.remove(element_to_remove)126            self.__candy_bag.remove(element_to_remove)
127            return element_to_remove127            return element_to_remove
128        else:128        else:
129            return None129            return None
130130
131131
132def calculate_distance(point1, point2):132def calculate_distance(point1, point2):
133    x1, y1 = point1133    x1, y1 = point1
134    x2, y2 = point2134    x2, y2 = point2
135    return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)135    return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
136136
137137
138def closest_neighbour(func):138def closest_neighbour(func):
139    def wrapper(self, kid):139    def wrapper(self, kid):
140        closest_host = min(140        closest_host = min(
141            (141            (
142                host142                host
143                for host in self.hosts_kids_on_the_door143                for host in self.hosts_kids_on_the_door
144                if host not in self.kids_visited[kid]144                if host not in self.kids_visited[kid]
145            ),145            ),
146            key=lambda host: (146            key=lambda host: (
147                calculate_distance(host.get_possition(), kid.get_possition()),147                calculate_distance(host.get_possition(), kid.get_possition()),
148                host.get_possition()[0],148                host.get_possition()[0],
149                host.get_possition()[1],149                host.get_possition()[1],
150            ),150            ),
151        )151        )
152        return func(self, kid, closest_host)152        return func(self, kid, closest_host)
153153
154    return wrapper154    return wrapper
155155
156156
157def when_should_stop(func):157def when_should_stop(func):
158    def wrapper(self):158    def wrapper(self):
159        if self.hosts_not_out_of_candies() and self.still_unvisited_hosts():159        if self.hosts_not_out_of_candies() and self.still_unvisited_hosts():
160            return func(self, False)160            return func(self, False)
161        return func(self, True)161        return func(self, True)
162162
163    return wrapper163    return wrapper
164164
165165
166class FluxCapacitor:166class FluxCapacitor:
167    def __init__(self, participants):167    def __init__(self, participants):
168        self.participants = participants168        self.participants = participants
169        self.__init_participarts(participants)169        self.__init_participarts(participants)
170170
171    def __init_participarts(self, participants):171    def __init_participarts(self, participants):
172        self.kids_visited = {}172        self.kids_visited = {}
173        self.hosts_kids_on_the_door = {}173        self.hosts_kids_on_the_door = {}
174        self.__victims = set()174        self.__victims = set()
175        for participant in participants:175        for participant in participants:
176            if isinstance(participant, Kid):176            if isinstance(participant, Kid):
177                self.kids_visited[participant] = set()177                self.kids_visited[participant] = set()
178            elif isinstance(participant, Host):178            elif isinstance(participant, Host):
179                self.hosts_kids_on_the_door[participant] = set()179                self.hosts_kids_on_the_door[participant] = set()
180180
181    # we are happy if even one host have candies left,181    # we are happy if even one host have candies left,
182    # so the game makes sence to continue182    # so the game makes sence to continue
183    def hosts_not_out_of_candies(self):183    def hosts_not_out_of_candies(self):
n184        for host in self.hosts_kids_on_the_door.keys():n184        for host in self.hosts_kids_on_the_door:
185            if host.have_candies():185            if host.have_candies():
186                return True186                return True
187        return False187        return False
188188
189    def still_unvisited_hosts(self):189    def still_unvisited_hosts(self):
190        hosts_count = len(self.hosts_kids_on_the_door)190        hosts_count = len(self.hosts_kids_on_the_door)
191        for kid, visited_hosts in self.kids_visited.items():191        for kid, visited_hosts in self.kids_visited.items():
192            if len(visited_hosts) < hosts_count:192            if len(visited_hosts) < hosts_count:
193                return True193                return True
194        return False194        return False
195195
196    @when_should_stop196    @when_should_stop
197    def __should_stop(self, stop=False):197    def __should_stop(self, stop=False):
198        return stop198        return stop
199199
200    def __go_to_host(self, kid, host):200    def __go_to_host(self, kid, host):
201        self.hosts_kids_on_the_door[host].add(kid)201        self.hosts_kids_on_the_door[host].add(kid)
202        self.kids_visited[kid].add(host)202        self.kids_visited[kid].add(host)
203        kid.set_possition(host.get_possition())203        kid.set_possition(host.get_possition())
204204
205    @closest_neighbour205    @closest_neighbour
206    def __find_host(self, kid, closest_host=None):206    def __find_host(self, kid, closest_host=None):
207        return closest_host207        return closest_host
208208
209    def __hosts_give_candies(self):209    def __hosts_give_candies(self):
210        for host, kids_on_the_door in self.hosts_kids_on_the_door.items():210        for host, kids_on_the_door in self.hosts_kids_on_the_door.items():
211            if kids_on_the_door:211            if kids_on_the_door:
212                sorted_kids = sorted(212                sorted_kids = sorted(
213                    kids_on_the_door, key=lambda kid: kid.get_initiative(), reverse=True213                    kids_on_the_door, key=lambda kid: kid.get_initiative(), reverse=True
214                )214                )
215                for kid in sorted_kids:215                for kid in sorted_kids:
216                    candy = host.remove_candy(biggest_candy)216                    candy = host.remove_candy(biggest_candy)
217                    if candy:217                    if candy:
218                        kid.add_candy(candy)218                        kid.add_candy(candy)
219                    self.hosts_kids_on_the_door[host].discard(219                    self.hosts_kids_on_the_door[host].discard(
220                        kid220                        kid
221                    )  # Remove the kid from the set221                    )  # Remove the kid from the set
222222
223    def __add_victim(self, kid):223    def __add_victim(self, kid):
224        self.__victims.add(kid)224        self.__victims.add(kid)
225225
n226    def __we_have_victims(self):n226    def __have_victims(self):
227        if self.__victims:227        if self.__victims:
228            return True228            return True
229        return False229        return False
230230
231    def __collect_victims(self):231    def __collect_victims(self):
232        for kid in self.kids_visited.keys():232        for kid in self.kids_visited.keys():
233            if kid.is_critical():233            if kid.is_critical():
234                self.__add_victim(kid)234                self.__add_victim(kid)
235235
236    def get_victim(self):236    def get_victim(self):
237        while not self.__should_stop():237        while not self.__should_stop():
n238            for kid in self.kids_visited.keys():n238            for kid in self.kids_visited:
239                host_to_go = self.__find_host(kid)239                host_to_go = self.__find_host(kid)
240                if host_to_go:240                if host_to_go:
241                    self.__go_to_host(kid, host_to_go)241                    self.__go_to_host(kid, host_to_go)
242            self.__hosts_give_candies()242            self.__hosts_give_candies()
243            self.__collect_victims()243            self.__collect_victims()
n244            if self.__we_have_victims():n244            if self.__have_victims():
245                return self.__victims245                return self.__victims
246        return None246        return None
247247
248248
249kid1 = Kid((0, 0), 5)249kid1 = Kid((0, 0), 5)
250kid2 = Kid((1, 1), 3)250kid2 = Kid((1, 1), 3)
251host1 = Host(251host1 = Host(
252    (2, 2),252    (2, 2),
253    [253    [
254        (10, 0.2),254        (10, 0.2),
255    ],255    ],
256)256)
257host2 = Host((3, 3), [])257host2 = Host((3, 3), [])
t258host3 = Host((4, 4), [])t258host3 = Host((4, 4), [(100, 0.1), (99, 0.5)])
259host4 = Host(259host4 = Host(
260    (5, 5),260    (5, 5),
261    [(3, 0.4)],261    [(3, 0.4)],
262)262)
263263
264flux = FluxCapacitor({kid1, kid2, host1, host2, host3, host4})264flux = FluxCapacitor({kid1, kid2, host1, host2, host3, host4})
265265
266# Run the simulation266# Run the simulation
267victims = flux.get_victim()267victims = flux.get_victim()
268print("Victims:", victims)268print("Victims:", victims)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1import mathf1import math
22
33
4def validate_uranium(func):4def validate_uranium(func):
5    def wrapper(self, mass, uranium):5    def wrapper(self, mass, uranium):
6        if uranium < 0 or uranium > 1:6        if uranium < 0 or uranium > 1:
7            raise ValueError("Candy object's uranium value must be between 0 and 1 .")7            raise ValueError("Candy object's uranium value must be between 0 and 1 .")
8        return func(self, mass, uranium)8        return func(self, mass, uranium)
99
10    return wrapper10    return wrapper
1111
1212
13class Candy:13class Candy:
14    @validate_uranium14    @validate_uranium
15    def __init__(self, mass, uranium=0):15    def __init__(self, mass, uranium=0):
16        self.__mass = mass16        self.__mass = mass
17        self.__uranium = uranium17        self.__uranium = uranium
1818
19    def get_uranium_quantity(self):19    def get_uranium_quantity(self):
20        return self.__mass * self.__uranium20        return self.__mass * self.__uranium
2121
22    def get_mass(self):22    def get_mass(self):
23        return self.__mass23        return self.__mass
2424
2525
26def validate_possition(func):26def validate_possition(func):
27    def wrapper(self, possition):27    def wrapper(self, possition):
28        if type(possition) is not tuple:28        if type(possition) is not tuple:
29            raise TypeError(29            raise TypeError(
30                "Person object's attribute possition must be of type tuple."30                "Person object's attribute possition must be of type tuple."
31            )31            )
32        elif len(possition) != 2:32        elif len(possition) != 2:
33            raise ValueError(33            raise ValueError(
34                "Person object's attribute possition must contain two coordinates."34                "Person object's attribute possition must contain two coordinates."
35            )35            )
36        return func(self, possition)36        return func(self, possition)
3737
38    return wrapper38    return wrapper
3939
4040
41class Person:41class Person:
42    @validate_possition42    @validate_possition
43    def __init__(self, possition):43    def __init__(self, possition):
44        self.__possition = possition44        self.__possition = possition
4545
46    @validate_possition46    @validate_possition
47    def set_possition(self, possition):47    def set_possition(self, possition):
48        self.__possition = possition48        self.__possition = possition
4949
50    def get_possition(self):50    def get_possition(self):
51        return self.__possition51        return self.__possition
5252
5353
54def validate_candy(func):54def validate_candy(func):
55    def wrapper(self, candy):55    def wrapper(self, candy):
56        if type(candy) is not Candy:56        if type(candy) is not Candy:
57            raise TypeError("Kid object can have only Candy objects in its bag.")57            raise TypeError("Kid object can have only Candy objects in its bag.")
58        return func(self, candy)58        return func(self, candy)
5959
60    return wrapper60    return wrapper
6161
6262
63def check_if_it_is_critital(func):63def check_if_it_is_critital(func):
64    def wrapper(self):64    def wrapper(self):
65        total_uranium = 065        total_uranium = 0
66        for candy in self._Kid__bag:66        for candy in self._Kid__bag:
67            total_uranium += candy.get_uranium_quantity()67            total_uranium += candy.get_uranium_quantity()
68        if total_uranium > 20:68        if total_uranium > 20:
69            return func(self, True)69            return func(self, True)
70        else:70        else:
71            return func(self, False)71            return func(self, False)
7272
73    return wrapper73    return wrapper
7474
7575
76class Kid(Person):76class Kid(Person):
77    def __init__(self, possition, initiative):77    def __init__(self, possition, initiative):
78        super().__init__(possition)78        super().__init__(possition)
79        self.__bag = set()79        self.__bag = set()
80        self.__initiative = initiative80        self.__initiative = initiative
8181
82    def get_initiative(self):82    def get_initiative(self):
83        return self.__initiative83        return self.__initiative
8484
85    @validate_candy85    @validate_candy
86    def add_candy(self, candy):86    def add_candy(self, candy):
87        self.__bag.add(candy)87        self.__bag.add(candy)
8888
89    @check_if_it_is_critital89    @check_if_it_is_critital
90    def is_critical(self, Dead=False):90    def is_critical(self, Dead=False):
91        return Dead91        return Dead
9292
9393
94def validate_host_init(func):94def validate_host_init(func):
95    def wrapper(self, possition, candy_bag):95    def wrapper(self, possition, candy_bag):
96        valid_candy_bag = set()96        valid_candy_bag = set()
97        for candy in candy_bag:97        for candy in candy_bag:
98            if len(candy) == 2:98            if len(candy) == 2:
99                valid_candy_bag.add(Candy(*candy))99                valid_candy_bag.add(Candy(*candy))
100            else:100            else:
101                raise ValueError(101                raise ValueError(
102                    "Host object attribute candy_bag must contains candies with two attributes."102                    "Host object attribute candy_bag must contains candies with two attributes."
103                )103                )
104        return func(self, possition, valid_candy_bag)104        return func(self, possition, valid_candy_bag)
105105
106    return wrapper106    return wrapper
107107
108108
109def biggest_candy(candies):109def biggest_candy(candies):
n110    max_weigth = 0n110    best_candy = max(candies, key=lambda candy: candy.get_mass())
111    best_candy = None
112    for candy in candies:
113        current_weigth = candy.get_mass()
114        if current_weigth > max_weigth:
115            max_weigth = current_weigth
116            best_candy = candy
117    return best_candy111    return best_candy
118112
119113
120class Host(Person):114class Host(Person):
121    @validate_host_init115    @validate_host_init
122    def __init__(self, possition, candy_bag):116    def __init__(self, possition, candy_bag):
123        super().__init__(possition)117        super().__init__(possition)
124        self.__candy_bag = candy_bag118        self.__candy_bag = candy_bag
125119
126    def have_candies(self):120    def have_candies(self):
127        return bool(self.__candy_bag)121        return bool(self.__candy_bag)
128122
129    def remove_candy(self, func):123    def remove_candy(self, func):
130        if self.__candy_bag:124        if self.__candy_bag:
131            element_to_remove = func(self.__candy_bag)125            element_to_remove = func(self.__candy_bag)
132            self.__candy_bag.remove(element_to_remove)126            self.__candy_bag.remove(element_to_remove)
133            return element_to_remove127            return element_to_remove
134        else:128        else:
135            return None129            return None
136130
137131
138def calculate_distance(point1, point2):132def calculate_distance(point1, point2):
n139    x1, y1 = point1()n133    x1, y1 = point1
140    x2, y2 = point2()134    x2, y2 = point2
141    return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)135    return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
142136
143137
144def closest_neighbour(func):138def closest_neighbour(func):
145    def wrapper(self, kid):139    def wrapper(self, kid):
n146        closest_host = Nonen140        closest_host = min(
147        min_distance = float("inf")141            (
142                host
148        for current_host in self.hosts_kids_on_the_door.keys():143                for host in self.hosts_kids_on_the_door
149            if current_host not in self.kids_visited[kid]:144                if host not in self.kids_visited[kid]
150                current_distance = calculate_distance(
151                    kid.get_possition, current_host.get_possition
152                )145            ),
153                if current_distance < min_distance:146            key=lambda host: (
154                    min_distance = current_distance147                calculate_distance(host.get_possition(), kid.get_possition()),
155                    closest_host = current_host148                host.get_possition()[0],
156                elif current_distance == min_distance:149                host.get_possition()[1],
157                    current_x, current_y = current_host.get_possition150            ),
158                    current_best_x, current_best_y = closest_host.get_possition151        )
159                    if current_x < current_best_x:
160                        closest_host = current_host
161                    elif current_x == current_best_x:
162                        if current_y < current_best_y:
163                            closest_host = current_host
164        return func(self, kid, closest_host)152        return func(self, kid, closest_host)
165153
166    return wrapper154    return wrapper
167155
168156
n169def when_should_we_stop(func):n157def when_should_stop(func):
170    def wrapper(self):158    def wrapper(self):
171        if self.hosts_not_out_of_candies() and self.still_unvisited_hosts():159        if self.hosts_not_out_of_candies() and self.still_unvisited_hosts():
172            return func(self, False)160            return func(self, False)
173        return func(self, True)161        return func(self, True)
174162
175    return wrapper163    return wrapper
176164
177165
178class FluxCapacitor:166class FluxCapacitor:
179    def __init__(self, participants):167    def __init__(self, participants):
180        self.participants = participants168        self.participants = participants
n181        self.__init_participarts__(participants)n169        self.__init_participarts(participants)
182170
n183    def __init_participarts__(self, participants):n171    def __init_participarts(self, participants):
184        self.kids_visited = {}172        self.kids_visited = {}
185        self.hosts_kids_on_the_door = {}173        self.hosts_kids_on_the_door = {}
n186        self.__victims__ = set()n174        self.__victims = set()
187        for participant in participants:175        for participant in participants:
188            if isinstance(participant, Kid):176            if isinstance(participant, Kid):
189                self.kids_visited[participant] = set()177                self.kids_visited[participant] = set()
190            elif isinstance(participant, Host):178            elif isinstance(participant, Host):
191                self.hosts_kids_on_the_door[participant] = set()179                self.hosts_kids_on_the_door[participant] = set()
192180
193    # we are happy if even one host have candies left,181    # we are happy if even one host have candies left,
194    # so the game makes sence to continue182    # so the game makes sence to continue
195    def hosts_not_out_of_candies(self):183    def hosts_not_out_of_candies(self):
196        for host in self.hosts_kids_on_the_door.keys():184        for host in self.hosts_kids_on_the_door.keys():
197            if host.have_candies():185            if host.have_candies():
198                return True186                return True
199        return False187        return False
200188
201    def still_unvisited_hosts(self):189    def still_unvisited_hosts(self):
202        hosts_count = len(self.hosts_kids_on_the_door)190        hosts_count = len(self.hosts_kids_on_the_door)
203        for kid, visited_hosts in self.kids_visited.items():191        for kid, visited_hosts in self.kids_visited.items():
204            if len(visited_hosts) < hosts_count:192            if len(visited_hosts) < hosts_count:
205                return True193                return True
206        return False194        return False
207195
n208    @when_should_we_stopn196    @when_should_stop
209    def __we_should_stop__(self, stop=False):197    def __should_stop(self, stop=False):
210        return stop198        return stop
211199
n212    def __go_to_host__(self, kid, host):n200    def __go_to_host(self, kid, host):
213        self.hosts_kids_on_the_door[host].add(kid)201        self.hosts_kids_on_the_door[host].add(kid)
214        self.kids_visited[kid].add(host)202        self.kids_visited[kid].add(host)
215        kid.set_possition(host.get_possition())203        kid.set_possition(host.get_possition())
216204
217    @closest_neighbour205    @closest_neighbour
n218    def __find_host__(self, kid, closest_host=None):n206    def __find_host(self, kid, closest_host=None):
219        return closest_host207        return closest_host
220208
n221    def __hosts_give_candies__(self):n209    def __hosts_give_candies(self):
222        for host, kids_on_the_door in self.hosts_kids_on_the_door.items():210        for host, kids_on_the_door in self.hosts_kids_on_the_door.items():
223            if kids_on_the_door:211            if kids_on_the_door:
224                sorted_kids = sorted(212                sorted_kids = sorted(
225                    kids_on_the_door, key=lambda kid: kid.get_initiative(), reverse=True213                    kids_on_the_door, key=lambda kid: kid.get_initiative(), reverse=True
226                )214                )
227                for kid in sorted_kids:215                for kid in sorted_kids:
228                    candy = host.remove_candy(biggest_candy)216                    candy = host.remove_candy(biggest_candy)
229                    if candy:217                    if candy:
230                        kid.add_candy(candy)218                        kid.add_candy(candy)
231                    self.hosts_kids_on_the_door[host].discard(219                    self.hosts_kids_on_the_door[host].discard(
232                        kid220                        kid
233                    )  # Remove the kid from the set221                    )  # Remove the kid from the set
234222
n235    def __add_victim__(self, kid):n223    def __add_victim(self, kid):
236        self.__victims__.add(kid)224        self.__victims.add(kid)
237225
n238    def __we_have_victims__(self):n226    def __we_have_victims(self):
239        if self.__victims__:227        if self.__victims:
240            return True228            return True
241        return False229        return False
242230
n243    def __collect_victims__(self):n231    def __collect_victims(self):
244        for kid in self.kids_visited.keys():232        for kid in self.kids_visited.keys():
245            if kid.is_critical():233            if kid.is_critical():
n246                self.__add_victim__(kid)n234                self.__add_victim(kid)
247235
248    def get_victim(self):236    def get_victim(self):
n249        while not self.__we_should_stop__():n237        while not self.__should_stop():
250            for kid in self.kids_visited.keys():238            for kid in self.kids_visited.keys():
n251                host_to_go = self.__find_host__(kid)n239                host_to_go = self.__find_host(kid)
252                if host_to_go:240                if host_to_go:
n253                    self.__go_to_host__(kid, host_to_go)n241                    self.__go_to_host(kid, host_to_go)
254            self.__hosts_give_candies__()242            self.__hosts_give_candies()
255            self.__collect_victims__()243            self.__collect_victims()
256            if self.__we_have_victims__():244            if self.__we_have_victims():
257                return self.__victims__245                return self.__victims
258        return None246        return None
259247
260248
261kid1 = Kid((0, 0), 5)249kid1 = Kid((0, 0), 5)
262kid2 = Kid((1, 1), 3)250kid2 = Kid((1, 1), 3)
263host1 = Host(251host1 = Host(
264    (2, 2),252    (2, 2),
265    [253    [
266        (10, 0.2),254        (10, 0.2),
267    ],255    ],
268)256)
269host2 = Host((3, 3), [])257host2 = Host((3, 3), [])
270host3 = Host((4, 4), [])258host3 = Host((4, 4), [])
271host4 = Host(259host4 = Host(
272    (5, 5),260    (5, 5),
t273    [(3, 0.4), (37, 0.5), (25, 0.9)],t261    [(3, 0.4)],
274)262)
275263
276flux = FluxCapacitor({kid1, kid2, host1, host2, host3, host4})264flux = FluxCapacitor({kid1, kid2, host1, host2, host3, host4})
277265
278# Run the simulation266# Run the simulation
279victims = flux.get_victim()267victims = flux.get_victim()
280print("Victims:", victims)268print("Victims:", victims)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op