1import math
2
3class Candy:
4 def __init__(self, mass, uranium):
5 self.mass = mass
6 self.uranium = uranium
7
8 def get_uranium_quantity(self):
9 return self.mass * self.uranium
10
11 def get_mass(self):
12 return self.mass
13
14
15class Person:
16 def __init__(self, position):
17 self.position = position
18
19 def get_position(self):
20 return self.position
21
22 def set_position(self, new_position):
23 self.position = new_position
24
25
26class Kid(Person):
27 CRITICAL_URANIUM_MASS = 20
28
29 def __init__(self, position, initiative):
30 super().__init__(position)
31 self.initiative = initiative
32 self.candies = []
33
34 def get_initiative(self):
35 return self.initiative
36
37 def add_candy(self, candy):
38 self.candies.append(candy)
39
40 def is_critical(self):
41 uranium_mass = sum(candy.get_uranium_quantity() for candy in self.candies)
42 return uranium_mass > Kid.CRITICAL_URANIUM_MASS
43
44 def move_to_host(self, host):
45 self.set_position(host.get_position())
46
47
48class Host(Person):
49 def __init__(self, position, candies):
50 super().__init__(position)
51 self.candies = [Candy(mass, uranium) for mass, uranium in candies]
52
53 def remove_candy(self, selection_function):
54 if not self.candies:
55 return None
56 selected_candy = selection_function(self.candies)
57 self.candies.remove(selected_candy)
58 return selected_candy
59
60
61class FluxCapacitor:
62 def __init__(self, participants):
63 self.kids = {p for p in participants if isinstance(p, Kid)}
64 self.hosts = {p for p in participants if isinstance(p, Host)}
65 self.victims = set()
66 self.simulate_halloween()
67
68 def get_victim(self):
69 return self.victims if self.victims else None
70
71 def simulate_halloween(self):
72 visited_hosts = {kid: set() for kid in self.kids}
73 while self.hosts and not self.victims:
74 for kid in sorted(self.kids, key=lambda k: k.get_initiative(), reverse=True):
75 closest_host = self.find_closest_host(kid, visited_hosts[kid])
76 if closest_host:
77 visited_hosts[kid].add(closest_host)
78 kid.move_to_host(closest_host)
79 candy = closest_host.remove_candy(lambda candies: max(candies, key=lambda c: c.get_mass()))
80 if candy:
81 kid.add_candy(candy)
82 self.victims = {kid for kid in self.kids if kid.is_critical()}
83 if self.victims:
84 break
85 self.hosts = {host for host in self.hosts if host.candies}
86 if not any(visited_hosts[kid] != self.hosts for kid in self.kids):
87 break
88
89 def find_closest_host(self, kid, visited_hosts):
90 unvisited_hosts = [(host, self.calculate_distance(kid.get_position(), host.get_position()))
91 for host in self.hosts if host not in visited_hosts]
92 unvisited_hosts.sort(key=lambda x: (x[1], x[0].get_position()))
93 return unvisited_hosts[0][0] if unvisited_hosts else None
94
95 def calculate_distance(self, position1, position2):
96 return ((position1[0] - position2[0]) ** 2 + (position1[1] - position2[1]) ** 2) ** 0.5
............
----------------------------------------------------------------------
Ran 12 tests in 0.001s
OK
f | 1 | import math | f | 1 | import math |
2 | 2 | ||||
3 | class Candy: | 3 | class Candy: | ||
4 | def __init__(self, mass, uranium): | 4 | def __init__(self, mass, uranium): | ||
5 | self.mass = mass | 5 | self.mass = mass | ||
6 | self.uranium = uranium | 6 | self.uranium = uranium | ||
7 | 7 | ||||
8 | def get_uranium_quantity(self): | 8 | def get_uranium_quantity(self): | ||
9 | return self.mass * self.uranium | 9 | return self.mass * self.uranium | ||
10 | 10 | ||||
11 | def get_mass(self): | 11 | def get_mass(self): | ||
12 | return self.mass | 12 | return self.mass | ||
13 | 13 | ||||
14 | 14 | ||||
15 | class Person: | 15 | class Person: | ||
16 | def __init__(self, position): | 16 | def __init__(self, position): | ||
17 | self.position = position | 17 | self.position = position | ||
18 | 18 | ||||
19 | def get_position(self): | 19 | def get_position(self): | ||
20 | return self.position | 20 | return self.position | ||
21 | 21 | ||||
22 | def set_position(self, new_position): | 22 | def set_position(self, new_position): | ||
23 | self.position = new_position | 23 | self.position = new_position | ||
24 | 24 | ||||
25 | 25 | ||||
26 | class Kid(Person): | 26 | class Kid(Person): | ||
n | n | 27 | CRITICAL_URANIUM_MASS = 20 | ||
28 | |||||
27 | def __init__(self, position, initiative): | 29 | def __init__(self, position, initiative): | ||
28 | super().__init__(position) | 30 | super().__init__(position) | ||
29 | self.initiative = initiative | 31 | self.initiative = initiative | ||
30 | self.candies = [] | 32 | self.candies = [] | ||
31 | 33 | ||||
32 | def get_initiative(self): | 34 | def get_initiative(self): | ||
33 | return self.initiative | 35 | return self.initiative | ||
34 | 36 | ||||
35 | def add_candy(self, candy): | 37 | def add_candy(self, candy): | ||
36 | self.candies.append(candy) | 38 | self.candies.append(candy) | ||
37 | 39 | ||||
38 | def is_critical(self): | 40 | def is_critical(self): | ||
39 | uranium_mass = sum(candy.get_uranium_quantity() for candy in self.candies) | 41 | uranium_mass = sum(candy.get_uranium_quantity() for candy in self.candies) | ||
n | 40 | return uranium_mass > 20 | n | 42 | return uranium_mass > Kid.CRITICAL_URANIUM_MASS |
41 | 43 | ||||
42 | def move_to_host(self, host): | 44 | def move_to_host(self, host): | ||
43 | self.set_position(host.get_position()) | 45 | self.set_position(host.get_position()) | ||
44 | 46 | ||||
45 | 47 | ||||
46 | class Host(Person): | 48 | class Host(Person): | ||
47 | def __init__(self, position, candies): | 49 | def __init__(self, position, candies): | ||
48 | super().__init__(position) | 50 | super().__init__(position) | ||
49 | self.candies = [Candy(mass, uranium) for mass, uranium in candies] | 51 | self.candies = [Candy(mass, uranium) for mass, uranium in candies] | ||
50 | 52 | ||||
51 | def remove_candy(self, selection_function): | 53 | def remove_candy(self, selection_function): | ||
52 | if not self.candies: | 54 | if not self.candies: | ||
53 | return None | 55 | return None | ||
54 | selected_candy = selection_function(self.candies) | 56 | selected_candy = selection_function(self.candies) | ||
55 | self.candies.remove(selected_candy) | 57 | self.candies.remove(selected_candy) | ||
56 | return selected_candy | 58 | return selected_candy | ||
57 | 59 | ||||
58 | 60 | ||||
59 | class FluxCapacitor: | 61 | class FluxCapacitor: | ||
60 | def __init__(self, participants): | 62 | def __init__(self, participants): | ||
61 | self.kids = {p for p in participants if isinstance(p, Kid)} | 63 | self.kids = {p for p in participants if isinstance(p, Kid)} | ||
62 | self.hosts = {p for p in participants if isinstance(p, Host)} | 64 | self.hosts = {p for p in participants if isinstance(p, Host)} | ||
63 | self.victims = set() | 65 | self.victims = set() | ||
64 | self.simulate_halloween() | 66 | self.simulate_halloween() | ||
65 | 67 | ||||
n | n | 68 | def get_victim(self): | ||
69 | return self.victims if self.victims else None | ||||
70 | |||||
66 | def simulate_halloween(self): | 71 | def simulate_halloween(self): | ||
67 | visited_hosts = {kid: set() for kid in self.kids} | 72 | visited_hosts = {kid: set() for kid in self.kids} | ||
68 | while self.hosts and not self.victims: | 73 | while self.hosts and not self.victims: | ||
69 | for kid in sorted(self.kids, key=lambda k: k.get_initiative(), reverse=True): | 74 | for kid in sorted(self.kids, key=lambda k: k.get_initiative(), reverse=True): | ||
70 | closest_host = self.find_closest_host(kid, visited_hosts[kid]) | 75 | closest_host = self.find_closest_host(kid, visited_hosts[kid]) | ||
71 | if closest_host: | 76 | if closest_host: | ||
72 | visited_hosts[kid].add(closest_host) | 77 | visited_hosts[kid].add(closest_host) | ||
73 | kid.move_to_host(closest_host) | 78 | kid.move_to_host(closest_host) | ||
74 | candy = closest_host.remove_candy(lambda candies: max(candies, key=lambda c: c.get_mass())) | 79 | candy = closest_host.remove_candy(lambda candies: max(candies, key=lambda c: c.get_mass())) | ||
75 | if candy: | 80 | if candy: | ||
76 | kid.add_candy(candy) | 81 | kid.add_candy(candy) | ||
77 | self.victims = {kid for kid in self.kids if kid.is_critical()} | 82 | self.victims = {kid for kid in self.kids if kid.is_critical()} | ||
78 | if self.victims: | 83 | if self.victims: | ||
n | 79 | return self.victims | n | 84 | break |
80 | self.hosts = {host for host in self.hosts if host.candies} | 85 | self.hosts = {host for host in self.hosts if host.candies} | ||
81 | if not any(visited_hosts[kid] != self.hosts for kid in self.kids): | 86 | if not any(visited_hosts[kid] != self.hosts for kid in self.kids): | ||
n | 82 | return None | n | 87 | break |
83 | 88 | ||||
84 | def find_closest_host(self, kid, visited_hosts): | 89 | def find_closest_host(self, kid, visited_hosts): | ||
n | 85 | unvisited_hosts = [host for host in self.hosts if host not in visited_hosts] | n | ||
86 | closest_host = None | ||||
87 | min_distance = float('inf') | ||||
88 | |||||
89 | for host in unvisited_hosts: | ||||
90 | distance = self.calculate_distance(kid.get_position(), host.get_position()) | 90 | unvisited_hosts = [(host, self.calculate_distance(kid.get_position(), host.get_position())) | ||
91 | if distance < min_distance or (distance == min_distance and self.is_closer_by_coordinates(host, closest_host)): | 91 | for host in self.hosts if host not in visited_hosts] | ||
92 | min_distance = distance | 92 | unvisited_hosts.sort(key=lambda x: (x[1], x[0].get_position())) | ||
93 | closest_host = host | 93 | return unvisited_hosts[0][0] if unvisited_hosts else None | ||
94 | return closest_host | ||||
95 | 94 | ||||
96 | def calculate_distance(self, position1, position2): | 95 | def calculate_distance(self, position1, position2): | ||
97 | return ((position1[0] - position2[0]) ** 2 + (position1[1] - position2[1]) ** 2) ** 0.5 | 96 | return ((position1[0] - position2[0]) ** 2 + (position1[1] - position2[1]) ** 2) ** 0.5 | ||
t | 98 | t | |||
99 | def is_closer_by_coordinates(self, host1, host2): | ||||
100 | if not host2 or host1.get_position()[0] < host2.get_position()[0]: | ||||
101 | return True | ||||
102 | elif host1.get_position()[0] == host2.get_position()[0] and host1.get_position()[1] < host2.get_position()[1]: | ||||
103 | return True | ||||
104 | return False |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import math | f | 1 | import math |
2 | 2 | ||||
3 | class Candy: | 3 | class Candy: | ||
4 | def __init__(self, mass, uranium): | 4 | def __init__(self, mass, uranium): | ||
5 | self.mass = mass | 5 | self.mass = mass | ||
6 | self.uranium = uranium | 6 | self.uranium = uranium | ||
7 | 7 | ||||
8 | def get_uranium_quantity(self): | 8 | def get_uranium_quantity(self): | ||
9 | return self.mass * self.uranium | 9 | return self.mass * self.uranium | ||
10 | 10 | ||||
11 | def get_mass(self): | 11 | def get_mass(self): | ||
12 | return self.mass | 12 | return self.mass | ||
13 | 13 | ||||
14 | 14 | ||||
15 | class Person: | 15 | class Person: | ||
16 | def __init__(self, position): | 16 | def __init__(self, position): | ||
17 | self.position = position | 17 | self.position = position | ||
18 | 18 | ||||
19 | def get_position(self): | 19 | def get_position(self): | ||
20 | return self.position | 20 | return self.position | ||
21 | 21 | ||||
22 | def set_position(self, new_position): | 22 | def set_position(self, new_position): | ||
23 | self.position = new_position | 23 | self.position = new_position | ||
24 | 24 | ||||
25 | 25 | ||||
26 | class Kid(Person): | 26 | class Kid(Person): | ||
27 | def __init__(self, position, initiative): | 27 | def __init__(self, position, initiative): | ||
28 | super().__init__(position) | 28 | super().__init__(position) | ||
29 | self.initiative = initiative | 29 | self.initiative = initiative | ||
30 | self.candies = [] | 30 | self.candies = [] | ||
31 | 31 | ||||
32 | def get_initiative(self): | 32 | def get_initiative(self): | ||
33 | return self.initiative | 33 | return self.initiative | ||
34 | 34 | ||||
35 | def add_candy(self, candy): | 35 | def add_candy(self, candy): | ||
36 | self.candies.append(candy) | 36 | self.candies.append(candy) | ||
37 | 37 | ||||
38 | def is_critical(self): | 38 | def is_critical(self): | ||
39 | uranium_mass = sum(candy.get_uranium_quantity() for candy in self.candies) | 39 | uranium_mass = sum(candy.get_uranium_quantity() for candy in self.candies) | ||
40 | return uranium_mass > 20 | 40 | return uranium_mass > 20 | ||
41 | 41 | ||||
42 | def move_to_host(self, host): | 42 | def move_to_host(self, host): | ||
43 | self.set_position(host.get_position()) | 43 | self.set_position(host.get_position()) | ||
44 | 44 | ||||
n | n | 45 | |||
45 | class Host(Person): | 46 | class Host(Person): | ||
46 | def __init__(self, position, candies): | 47 | def __init__(self, position, candies): | ||
47 | super().__init__(position) | 48 | super().__init__(position) | ||
48 | self.candies = [Candy(mass, uranium) for mass, uranium in candies] | 49 | self.candies = [Candy(mass, uranium) for mass, uranium in candies] | ||
49 | 50 | ||||
50 | def remove_candy(self, selection_function): | 51 | def remove_candy(self, selection_function): | ||
51 | if not self.candies: | 52 | if not self.candies: | ||
52 | return None | 53 | return None | ||
53 | selected_candy = selection_function(self.candies) | 54 | selected_candy = selection_function(self.candies) | ||
54 | self.candies.remove(selected_candy) | 55 | self.candies.remove(selected_candy) | ||
55 | return selected_candy | 56 | return selected_candy | ||
56 | 57 | ||||
57 | 58 | ||||
58 | class FluxCapacitor: | 59 | class FluxCapacitor: | ||
59 | def __init__(self, participants): | 60 | def __init__(self, participants): | ||
60 | self.kids = {p for p in participants if isinstance(p, Kid)} | 61 | self.kids = {p for p in participants if isinstance(p, Kid)} | ||
61 | self.hosts = {p for p in participants if isinstance(p, Host)} | 62 | self.hosts = {p for p in participants if isinstance(p, Host)} | ||
62 | self.victims = set() | 63 | self.victims = set() | ||
63 | self.simulate_halloween() | 64 | self.simulate_halloween() | ||
64 | 65 | ||||
65 | def simulate_halloween(self): | 66 | def simulate_halloween(self): | ||
66 | visited_hosts = {kid: set() for kid in self.kids} | 67 | visited_hosts = {kid: set() for kid in self.kids} | ||
n | 67 | n | |||
68 | while self.hosts and not self.victims: | 68 | while self.hosts and not self.victims: | ||
69 | for kid in sorted(self.kids, key=lambda k: k.get_initiative(), reverse=True): | 69 | for kid in sorted(self.kids, key=lambda k: k.get_initiative(), reverse=True): | ||
70 | closest_host = self.find_closest_host(kid, visited_hosts[kid]) | 70 | closest_host = self.find_closest_host(kid, visited_hosts[kid]) | ||
71 | if closest_host: | 71 | if closest_host: | ||
72 | visited_hosts[kid].add(closest_host) | 72 | visited_hosts[kid].add(closest_host) | ||
73 | kid.move_to_host(closest_host) | 73 | kid.move_to_host(closest_host) | ||
n | 74 | n | |||
75 | candy = closest_host.remove_candy(lambda candies: max(candies, key=lambda c: c.get_mass())) | 74 | candy = closest_host.remove_candy(lambda candies: max(candies, key=lambda c: c.get_mass())) | ||
76 | if candy: | 75 | if candy: | ||
77 | kid.add_candy(candy) | 76 | kid.add_candy(candy) | ||
n | 78 | n | |||
79 | self.victims = {kid for kid in self.kids if kid.is_critical()} | 77 | self.victims = {kid for kid in self.kids if kid.is_critical()} | ||
80 | if self.victims: | 78 | if self.victims: | ||
81 | return self.victims | 79 | return self.victims | ||
n | 82 | n | |||
83 | self.hosts = {host for host in self.hosts if host.candies} | 80 | self.hosts = {host for host in self.hosts if host.candies} | ||
84 | if not any(visited_hosts[kid] != self.hosts for kid in self.kids): | 81 | if not any(visited_hosts[kid] != self.hosts for kid in self.kids): | ||
85 | return None | 82 | return None | ||
86 | 83 | ||||
87 | def find_closest_host(self, kid, visited_hosts): | 84 | def find_closest_host(self, kid, visited_hosts): | ||
88 | unvisited_hosts = [host for host in self.hosts if host not in visited_hosts] | 85 | unvisited_hosts = [host for host in self.hosts if host not in visited_hosts] | ||
89 | closest_host = None | 86 | closest_host = None | ||
90 | min_distance = float('inf') | 87 | min_distance = float('inf') | ||
91 | 88 | ||||
92 | for host in unvisited_hosts: | 89 | for host in unvisited_hosts: | ||
93 | distance = self.calculate_distance(kid.get_position(), host.get_position()) | 90 | distance = self.calculate_distance(kid.get_position(), host.get_position()) | ||
94 | if distance < min_distance or (distance == min_distance and self.is_closer_by_coordinates(host, closest_host)): | 91 | if distance < min_distance or (distance == min_distance and self.is_closer_by_coordinates(host, closest_host)): | ||
95 | min_distance = distance | 92 | min_distance = distance | ||
96 | closest_host = host | 93 | closest_host = host | ||
t | 97 | t | |||
98 | return closest_host | 94 | return closest_host | ||
99 | 95 | ||||
100 | def calculate_distance(self, position1, position2): | 96 | def calculate_distance(self, position1, position2): | ||
101 | return ((position1[0] - position2[0]) ** 2 + (position1[1] - position2[1]) ** 2) ** 0.5 | 97 | return ((position1[0] - position2[0]) ** 2 + (position1[1] - position2[1]) ** 2) ** 0.5 | ||
102 | 98 | ||||
103 | def is_closer_by_coordinates(self, host1, host2): | 99 | def is_closer_by_coordinates(self, host1, host2): | ||
104 | if not host2 or host1.get_position()[0] < host2.get_position()[0]: | 100 | if not host2 or host1.get_position()[0] < host2.get_position()[0]: | ||
105 | return True | 101 | return True | ||
106 | elif host1.get_position()[0] == host2.get_position()[0] and host1.get_position()[1] < host2.get_position()[1]: | 102 | elif host1.get_position()[0] == host2.get_position()[0] and host1.get_position()[1] < host2.get_position()[1]: | ||
107 | return True | 103 | return True | ||
108 | return False | 104 | return False |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|