1import math
2
3class Candy:
4 def __init__(self, mass: int, uranium: float):
5 self.mass = mass
6 self.uranium = uranium
7
8 def get_mass(self):
9 return self.mass
10
11 def get_uranium_quantity(self):
12 return self.mass * self.uranium
13
14
15class Person:
16 def __init__(self, position: tuple):
17 self.position = position
18
19 def get_position(self):
20 return self.position
21
22 def set_position(self, position: tuple):
23 self.position = position
24
25 @staticmethod
26 def dist_between(position1: tuple, position2: tuple):
27 return math.sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2)
28
29
30class Kid(Person):
31 CRITICAL_MASS_THRESHOLD = 20
32
33 def __init__(self, position: tuple, initiative: int):
34 self.initiative = initiative
35 self.basket = []
36 super().__init__(position)
37
38 def get_initiative(self):
39 return self.initiative
40
41 def add_candy(self, candy: Candy):
42 self.basket.append(candy)
43
44 def is_critical(self):
45 total_uranium = 0
46 for candy in self.basket:
47 total_uranium += candy.get_uranium_quantity()
48 return total_uranium > self.CRITICAL_MASS_THRESHOLD
49
50
51class Host(Person):
52 def __init__(self, position: tuple, candies: list):
53 self.basket = list()
54 for candy in candies:
55 self.basket.append(Candy(candy[0], candy[1]))
56 super().__init__(position)
57
58 def remove_candy(self, predicate):
59 if self.basket:
60 candy = predicate(self.basket)
61 self.basket.remove(predicate(self.basket))
62 return candy
63 return None
64
65
66class FluxCapacitor:
67 def __init__(self, participants: set):
68 self.participants = participants
69 self.hosts = [host for host in participants if isinstance(host, Host)]
70 self.kids = [kid for kid in participants if isinstance(kid, Kid)]
71
72 def get_victim(self):
73 hosts = self.hosts
74 kids = self.kids
75 kids_visited_hosts = {kid: [] for kid in kids}
76
77 while [len(visited_hosts) for visited_hosts in kids_visited_hosts.values()].count(len(hosts)) != len(kids):
78 host_expected_kids = {host: [] for host in hosts}
79
80 # Determine which children will be visiting each host
81 for kid in kids:
82 closest_host = Host(position=(float('inf'), float('inf')), candies=[])
83 for host in hosts:
84 if host not in kids_visited_hosts[kid]:
85 if (dist_a := Person.dist_between(kid.position, host.position)) < (
86 dist_b := Person.dist_between(kid.position, closest_host.position)):
87 closest_host = host
88 elif dist_a == dist_b:
89 if host.position[0] < closest_host.position[0]:
90 closest_host = host
91 elif host.position[0] == closest_host.position[0] and host.position[1] < closest_host.position[1]:
92 closest_host = host
93 if closest_host.position != (float('inf'), float('inf')):
94 host_expected_kids[closest_host].append(kid)
95
96 # Sort kids by initiative
97 for kids_list in host_expected_kids.values():
98 if len(kids_list) > 1:
99 kids_list.sort(key=lambda x: x.initiative, reverse=True)
100
101 # Give candy to kids in defined order
102 for host in hosts:
103 # For every kid that wants to visit the host
104 for visiting_kid in host_expected_kids[host]:
105 # Check if there is any candy left
106 visiting_kid.set_position(host.get_position())
107 if host.basket:
108 # Host removes the candy from their basket and gives it to the kid
109 visiting_kid.add_candy(host.remove_candy(lambda candy_basket: max(candy_basket, key=lambda candy: candy.get_mass())))
110 # Kid now has visited this host and will never meet them again!
111 kids_visited_hosts[visiting_kid].append(host)
112
113 # If there are any dead kids, return them
114 if dead_kids := set(kid for kid in kids if kid.is_critical()):
115 return dead_kids
116
117 return None
............
----------------------------------------------------------------------
Ran 12 tests in 0.001s
OK
t | 1 | import math | t | 1 | import math |
2 | 2 | ||||
3 | class Candy: | 3 | class Candy: | ||
4 | def __init__(self, mass: int, uranium: float): | 4 | def __init__(self, mass: int, uranium: float): | ||
5 | self.mass = mass | 5 | self.mass = mass | ||
6 | self.uranium = uranium | 6 | self.uranium = uranium | ||
7 | 7 | ||||
8 | def get_mass(self): | 8 | def get_mass(self): | ||
9 | return self.mass | 9 | return self.mass | ||
10 | 10 | ||||
11 | def get_uranium_quantity(self): | 11 | def get_uranium_quantity(self): | ||
12 | return self.mass * self.uranium | 12 | return self.mass * self.uranium | ||
13 | 13 | ||||
14 | 14 | ||||
15 | class Person: | 15 | class Person: | ||
16 | def __init__(self, position: tuple): | 16 | def __init__(self, position: tuple): | ||
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, position: tuple): | 22 | def set_position(self, position: tuple): | ||
23 | self.position = position | 23 | self.position = position | ||
24 | 24 | ||||
25 | @staticmethod | 25 | @staticmethod | ||
26 | def dist_between(position1: tuple, position2: tuple): | 26 | def dist_between(position1: tuple, position2: tuple): | ||
27 | return math.sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | 27 | return math.sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | ||
28 | 28 | ||||
29 | 29 | ||||
30 | class Kid(Person): | 30 | class Kid(Person): | ||
31 | CRITICAL_MASS_THRESHOLD = 20 | 31 | CRITICAL_MASS_THRESHOLD = 20 | ||
32 | 32 | ||||
33 | def __init__(self, position: tuple, initiative: int): | 33 | def __init__(self, position: tuple, initiative: int): | ||
34 | self.initiative = initiative | 34 | self.initiative = initiative | ||
35 | self.basket = [] | 35 | self.basket = [] | ||
36 | super().__init__(position) | 36 | super().__init__(position) | ||
37 | 37 | ||||
38 | def get_initiative(self): | 38 | def get_initiative(self): | ||
39 | return self.initiative | 39 | return self.initiative | ||
40 | 40 | ||||
41 | def add_candy(self, candy: Candy): | 41 | def add_candy(self, candy: Candy): | ||
42 | self.basket.append(candy) | 42 | self.basket.append(candy) | ||
43 | 43 | ||||
44 | def is_critical(self): | 44 | def is_critical(self): | ||
45 | total_uranium = 0 | 45 | total_uranium = 0 | ||
46 | for candy in self.basket: | 46 | for candy in self.basket: | ||
47 | total_uranium += candy.get_uranium_quantity() | 47 | total_uranium += candy.get_uranium_quantity() | ||
48 | return total_uranium > self.CRITICAL_MASS_THRESHOLD | 48 | return total_uranium > self.CRITICAL_MASS_THRESHOLD | ||
49 | 49 | ||||
50 | 50 | ||||
51 | class Host(Person): | 51 | class Host(Person): | ||
52 | def __init__(self, position: tuple, candies: list): | 52 | def __init__(self, position: tuple, candies: list): | ||
53 | self.basket = list() | 53 | self.basket = list() | ||
54 | for candy in candies: | 54 | for candy in candies: | ||
55 | self.basket.append(Candy(candy[0], candy[1])) | 55 | self.basket.append(Candy(candy[0], candy[1])) | ||
56 | super().__init__(position) | 56 | super().__init__(position) | ||
57 | 57 | ||||
58 | def remove_candy(self, predicate): | 58 | def remove_candy(self, predicate): | ||
59 | if self.basket: | 59 | if self.basket: | ||
60 | candy = predicate(self.basket) | 60 | candy = predicate(self.basket) | ||
61 | self.basket.remove(predicate(self.basket)) | 61 | self.basket.remove(predicate(self.basket)) | ||
62 | return candy | 62 | return candy | ||
63 | return None | 63 | return None | ||
64 | 64 | ||||
65 | 65 | ||||
66 | class FluxCapacitor: | 66 | class FluxCapacitor: | ||
67 | def __init__(self, participants: set): | 67 | def __init__(self, participants: set): | ||
68 | self.participants = participants | 68 | self.participants = participants | ||
69 | self.hosts = [host for host in participants if isinstance(host, Host)] | 69 | self.hosts = [host for host in participants if isinstance(host, Host)] | ||
70 | self.kids = [kid for kid in participants if isinstance(kid, Kid)] | 70 | self.kids = [kid for kid in participants if isinstance(kid, Kid)] | ||
71 | 71 | ||||
72 | def get_victim(self): | 72 | def get_victim(self): | ||
73 | hosts = self.hosts | 73 | hosts = self.hosts | ||
74 | kids = self.kids | 74 | kids = self.kids | ||
75 | kids_visited_hosts = {kid: [] for kid in kids} | 75 | kids_visited_hosts = {kid: [] for kid in kids} | ||
76 | 76 | ||||
77 | while [len(visited_hosts) for visited_hosts in kids_visited_hosts.values()].count(len(hosts)) != len(kids): | 77 | while [len(visited_hosts) for visited_hosts in kids_visited_hosts.values()].count(len(hosts)) != len(kids): | ||
78 | host_expected_kids = {host: [] for host in hosts} | 78 | host_expected_kids = {host: [] for host in hosts} | ||
79 | 79 | ||||
80 | # Determine which children will be visiting each host | 80 | # Determine which children will be visiting each host | ||
81 | for kid in kids: | 81 | for kid in kids: | ||
82 | closest_host = Host(position=(float('inf'), float('inf')), candies=[]) | 82 | closest_host = Host(position=(float('inf'), float('inf')), candies=[]) | ||
83 | for host in hosts: | 83 | for host in hosts: | ||
84 | if host not in kids_visited_hosts[kid]: | 84 | if host not in kids_visited_hosts[kid]: | ||
85 | if (dist_a := Person.dist_between(kid.position, host.position)) < ( | 85 | if (dist_a := Person.dist_between(kid.position, host.position)) < ( | ||
86 | dist_b := Person.dist_between(kid.position, closest_host.position)): | 86 | dist_b := Person.dist_between(kid.position, closest_host.position)): | ||
87 | closest_host = host | 87 | closest_host = host | ||
88 | elif dist_a == dist_b: | 88 | elif dist_a == dist_b: | ||
89 | if host.position[0] < closest_host.position[0]: | 89 | if host.position[0] < closest_host.position[0]: | ||
90 | closest_host = host | 90 | closest_host = host | ||
91 | elif host.position[0] == closest_host.position[0] and host.position[1] < closest_host.position[1]: | 91 | elif host.position[0] == closest_host.position[0] and host.position[1] < closest_host.position[1]: | ||
92 | closest_host = host | 92 | closest_host = host | ||
93 | if closest_host.position != (float('inf'), float('inf')): | 93 | if closest_host.position != (float('inf'), float('inf')): | ||
94 | host_expected_kids[closest_host].append(kid) | 94 | host_expected_kids[closest_host].append(kid) | ||
95 | 95 | ||||
96 | # Sort kids by initiative | 96 | # Sort kids by initiative | ||
97 | for kids_list in host_expected_kids.values(): | 97 | for kids_list in host_expected_kids.values(): | ||
98 | if len(kids_list) > 1: | 98 | if len(kids_list) > 1: | ||
99 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | 99 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | ||
100 | 100 | ||||
101 | # Give candy to kids in defined order | 101 | # Give candy to kids in defined order | ||
102 | for host in hosts: | 102 | for host in hosts: | ||
103 | # For every kid that wants to visit the host | 103 | # For every kid that wants to visit the host | ||
104 | for visiting_kid in host_expected_kids[host]: | 104 | for visiting_kid in host_expected_kids[host]: | ||
105 | # Check if there is any candy left | 105 | # Check if there is any candy left | ||
106 | visiting_kid.set_position(host.get_position()) | 106 | visiting_kid.set_position(host.get_position()) | ||
107 | if host.basket: | 107 | if host.basket: | ||
108 | # Host removes the candy from their basket and gives it to the kid | 108 | # Host removes the candy from their basket and gives it to the kid | ||
109 | visiting_kid.add_candy(host.remove_candy(lambda candy_basket: max(candy_basket, key=lambda candy: candy.get_mass()))) | 109 | visiting_kid.add_candy(host.remove_candy(lambda candy_basket: max(candy_basket, key=lambda candy: candy.get_mass()))) | ||
110 | # Kid now has visited this host and will never meet them again! | 110 | # Kid now has visited this host and will never meet them again! | ||
111 | kids_visited_hosts[visiting_kid].append(host) | 111 | kids_visited_hosts[visiting_kid].append(host) | ||
112 | 112 | ||||
113 | # If there are any dead kids, return them | 113 | # If there are any dead kids, return them | ||
114 | if dead_kids := set(kid for kid in kids if kid.is_critical()): | 114 | if dead_kids := set(kid for kid in kids if kid.is_critical()): | ||
115 | return dead_kids | 115 | return dead_kids | ||
116 | 116 | ||||
117 | return None | 117 | return None |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import math | f | 1 | import math |
2 | 2 | ||||
3 | class Candy: | 3 | class Candy: | ||
4 | def __init__(self, mass: int, uranium: float): | 4 | def __init__(self, mass: int, uranium: float): | ||
5 | self.mass = mass | 5 | self.mass = mass | ||
6 | self.uranium = uranium | 6 | self.uranium = uranium | ||
7 | 7 | ||||
8 | def get_mass(self): | 8 | def get_mass(self): | ||
9 | return self.mass | 9 | return self.mass | ||
10 | 10 | ||||
11 | def get_uranium_quantity(self): | 11 | def get_uranium_quantity(self): | ||
12 | return self.mass * self.uranium | 12 | return self.mass * self.uranium | ||
13 | 13 | ||||
14 | 14 | ||||
15 | class Person: | 15 | class Person: | ||
16 | def __init__(self, position: tuple): | 16 | def __init__(self, position: tuple): | ||
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, position: tuple): | 22 | def set_position(self, position: tuple): | ||
23 | self.position = position | 23 | self.position = position | ||
24 | 24 | ||||
25 | @staticmethod | 25 | @staticmethod | ||
26 | def dist_between(position1: tuple, position2: tuple): | 26 | def dist_between(position1: tuple, position2: tuple): | ||
27 | return math.sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | 27 | return math.sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | ||
28 | 28 | ||||
29 | 29 | ||||
30 | class Kid(Person): | 30 | class Kid(Person): | ||
31 | CRITICAL_MASS_THRESHOLD = 20 | 31 | CRITICAL_MASS_THRESHOLD = 20 | ||
32 | 32 | ||||
33 | def __init__(self, position: tuple, initiative: int): | 33 | def __init__(self, position: tuple, initiative: int): | ||
34 | self.initiative = initiative | 34 | self.initiative = initiative | ||
35 | self.basket = [] | 35 | self.basket = [] | ||
36 | super().__init__(position) | 36 | super().__init__(position) | ||
37 | 37 | ||||
38 | def get_initiative(self): | 38 | def get_initiative(self): | ||
39 | return self.initiative | 39 | return self.initiative | ||
40 | 40 | ||||
41 | def add_candy(self, candy: Candy): | 41 | def add_candy(self, candy: Candy): | ||
42 | self.basket.append(candy) | 42 | self.basket.append(candy) | ||
43 | 43 | ||||
44 | def is_critical(self): | 44 | def is_critical(self): | ||
45 | total_uranium = 0 | 45 | total_uranium = 0 | ||
46 | for candy in self.basket: | 46 | for candy in self.basket: | ||
47 | total_uranium += candy.get_uranium_quantity() | 47 | total_uranium += candy.get_uranium_quantity() | ||
48 | return total_uranium > self.CRITICAL_MASS_THRESHOLD | 48 | return total_uranium > self.CRITICAL_MASS_THRESHOLD | ||
49 | 49 | ||||
50 | 50 | ||||
51 | class Host(Person): | 51 | class Host(Person): | ||
52 | def __init__(self, position: tuple, candies: list): | 52 | def __init__(self, position: tuple, candies: list): | ||
53 | self.basket = list() | 53 | self.basket = list() | ||
54 | for candy in candies: | 54 | for candy in candies: | ||
55 | self.basket.append(Candy(candy[0], candy[1])) | 55 | self.basket.append(Candy(candy[0], candy[1])) | ||
56 | super().__init__(position) | 56 | super().__init__(position) | ||
57 | 57 | ||||
58 | def remove_candy(self, predicate): | 58 | def remove_candy(self, predicate): | ||
59 | if self.basket: | 59 | if self.basket: | ||
60 | candy = predicate(self.basket) | 60 | candy = predicate(self.basket) | ||
61 | self.basket.remove(predicate(self.basket)) | 61 | self.basket.remove(predicate(self.basket)) | ||
62 | return candy | 62 | return candy | ||
63 | return None | 63 | return None | ||
64 | 64 | ||||
65 | 65 | ||||
66 | class FluxCapacitor: | 66 | class FluxCapacitor: | ||
67 | def __init__(self, participants: set): | 67 | def __init__(self, participants: set): | ||
68 | self.participants = participants | 68 | self.participants = participants | ||
69 | self.hosts = [host for host in participants if isinstance(host, Host)] | 69 | self.hosts = [host for host in participants if isinstance(host, Host)] | ||
70 | self.kids = [kid for kid in participants if isinstance(kid, Kid)] | 70 | self.kids = [kid for kid in participants if isinstance(kid, Kid)] | ||
71 | 71 | ||||
72 | def get_victim(self): | 72 | def get_victim(self): | ||
73 | hosts = self.hosts | 73 | hosts = self.hosts | ||
74 | kids = self.kids | 74 | kids = self.kids | ||
75 | kids_visited_hosts = {kid: [] for kid in kids} | 75 | kids_visited_hosts = {kid: [] for kid in kids} | ||
76 | 76 | ||||
77 | while [len(visited_hosts) for visited_hosts in kids_visited_hosts.values()].count(len(hosts)) != len(kids): | 77 | while [len(visited_hosts) for visited_hosts in kids_visited_hosts.values()].count(len(hosts)) != len(kids): | ||
78 | host_expected_kids = {host: [] for host in hosts} | 78 | host_expected_kids = {host: [] for host in hosts} | ||
79 | 79 | ||||
80 | # Determine which children will be visiting each host | 80 | # Determine which children will be visiting each host | ||
81 | for kid in kids: | 81 | for kid in kids: | ||
82 | closest_host = Host(position=(float('inf'), float('inf')), candies=[]) | 82 | closest_host = Host(position=(float('inf'), float('inf')), candies=[]) | ||
83 | for host in hosts: | 83 | for host in hosts: | ||
84 | if host not in kids_visited_hosts[kid]: | 84 | if host not in kids_visited_hosts[kid]: | ||
n | 85 | if (distA := Person.dist_between(kid.position, host.position)) < ( | n | 85 | if (dist_a := Person.dist_between(kid.position, host.position)) < ( |
86 | distB := Person.dist_between(kid.position, closest_host.position)): | 86 | dist_b := Person.dist_between(kid.position, closest_host.position)): | ||
87 | closest_host = host | 87 | closest_host = host | ||
t | 88 | elif distA == distB: | t | 88 | elif dist_a == dist_b: |
89 | if host.position[0] < closest_host.position[0]: | 89 | if host.position[0] < closest_host.position[0]: | ||
90 | closest_host = host | 90 | closest_host = host | ||
91 | elif host.position[0] == closest_host.position[0] and host.position[1] < closest_host.position[1]: | 91 | elif host.position[0] == closest_host.position[0] and host.position[1] < closest_host.position[1]: | ||
92 | closest_host = host | 92 | closest_host = host | ||
93 | if closest_host.position != (float('inf'), float('inf')): | 93 | if closest_host.position != (float('inf'), float('inf')): | ||
94 | host_expected_kids[closest_host].append(kid) | 94 | host_expected_kids[closest_host].append(kid) | ||
95 | 95 | ||||
96 | # Sort kids by initiative | 96 | # Sort kids by initiative | ||
97 | for kids_list in host_expected_kids.values(): | 97 | for kids_list in host_expected_kids.values(): | ||
98 | if len(kids_list) > 1: | 98 | if len(kids_list) > 1: | ||
99 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | 99 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | ||
100 | 100 | ||||
101 | # Give candy to kids in defined order | 101 | # Give candy to kids in defined order | ||
102 | for host in hosts: | 102 | for host in hosts: | ||
103 | # For every kid that wants to visit the host | 103 | # For every kid that wants to visit the host | ||
104 | for visiting_kid in host_expected_kids[host]: | 104 | for visiting_kid in host_expected_kids[host]: | ||
105 | # Check if there is any candy left | 105 | # Check if there is any candy left | ||
106 | visiting_kid.set_position(host.get_position()) | 106 | visiting_kid.set_position(host.get_position()) | ||
107 | if host.basket: | 107 | if host.basket: | ||
108 | # Host removes the candy from their basket and gives it to the kid | 108 | # Host removes the candy from their basket and gives it to the kid | ||
109 | visiting_kid.add_candy(host.remove_candy(lambda candy_basket: max(candy_basket, key=lambda candy: candy.get_mass()))) | 109 | visiting_kid.add_candy(host.remove_candy(lambda candy_basket: max(candy_basket, key=lambda candy: candy.get_mass()))) | ||
110 | # Kid now has visited this host and will never meet them again! | 110 | # Kid now has visited this host and will never meet them again! | ||
111 | kids_visited_hosts[visiting_kid].append(host) | 111 | kids_visited_hosts[visiting_kid].append(host) | ||
112 | 112 | ||||
113 | # If there are any dead kids, return them | 113 | # If there are any dead kids, return them | ||
114 | if dead_kids := set(kid for kid in kids if kid.is_critical()): | 114 | if dead_kids := set(kid for kid in kids if kid.is_critical()): | ||
115 | return dead_kids | 115 | return dead_kids | ||
116 | 116 | ||||
117 | return None | 117 | return None |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
n | n | 1 | import math | ||
2 | |||||
1 | class Candy: | 3 | class Candy: | ||
2 | def __init__(self, mass: int, uranium: float): | 4 | def __init__(self, mass: int, uranium: float): | ||
3 | self.mass = mass | 5 | self.mass = mass | ||
4 | self.uranium = uranium | 6 | self.uranium = uranium | ||
5 | 7 | ||||
6 | def get_mass(self): | 8 | def get_mass(self): | ||
7 | return self.mass | 9 | return self.mass | ||
8 | 10 | ||||
9 | def get_uranium_quantity(self): | 11 | def get_uranium_quantity(self): | ||
10 | return self.mass * self.uranium | 12 | return self.mass * self.uranium | ||
11 | 13 | ||||
12 | 14 | ||||
13 | class Person: | 15 | class Person: | ||
14 | def __init__(self, position: tuple): | 16 | def __init__(self, position: tuple): | ||
15 | self.position = position | 17 | self.position = position | ||
16 | 18 | ||||
17 | def get_position(self): | 19 | def get_position(self): | ||
18 | return self.position | 20 | return self.position | ||
19 | 21 | ||||
20 | def set_position(self, position: tuple): | 22 | def set_position(self, position: tuple): | ||
21 | self.position = position | 23 | self.position = position | ||
22 | 24 | ||||
n | n | 25 | @staticmethod | ||
26 | def dist_between(position1: tuple, position2: tuple): | ||||
27 | return math.sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | ||||
28 | |||||
23 | 29 | ||||
24 | class Kid(Person): | 30 | class Kid(Person): | ||
n | n | 31 | CRITICAL_MASS_THRESHOLD = 20 | ||
32 | |||||
25 | def __init__(self, position: tuple, initiative: int): | 33 | def __init__(self, position: tuple, initiative: int): | ||
26 | self.initiative = initiative | 34 | self.initiative = initiative | ||
27 | self.basket = [] | 35 | self.basket = [] | ||
28 | super().__init__(position) | 36 | super().__init__(position) | ||
29 | 37 | ||||
30 | def get_initiative(self): | 38 | def get_initiative(self): | ||
31 | return self.initiative | 39 | return self.initiative | ||
32 | 40 | ||||
33 | def add_candy(self, candy: Candy): | 41 | def add_candy(self, candy: Candy): | ||
34 | self.basket.append(candy) | 42 | self.basket.append(candy) | ||
35 | 43 | ||||
36 | def is_critical(self): | 44 | def is_critical(self): | ||
37 | total_uranium = 0 | 45 | total_uranium = 0 | ||
38 | for candy in self.basket: | 46 | for candy in self.basket: | ||
n | 39 | total_uranium += candy.mass * candy.uranium | n | 47 | total_uranium += candy.get_uranium_quantity() |
40 | return total_uranium > 20 | 48 | return total_uranium > self.CRITICAL_MASS_THRESHOLD | ||
41 | 49 | ||||
42 | 50 | ||||
43 | class Host(Person): | 51 | class Host(Person): | ||
44 | def __init__(self, position: tuple, candies: list): | 52 | def __init__(self, position: tuple, candies: list): | ||
45 | self.basket = list() | 53 | self.basket = list() | ||
46 | for candy in candies: | 54 | for candy in candies: | ||
n | 47 | self.basket.append(candy) | n | 55 | self.basket.append(Candy(candy[0], candy[1])) |
48 | super().__init__(position) | 56 | super().__init__(position) | ||
49 | 57 | ||||
50 | def remove_candy(self, predicate): | 58 | def remove_candy(self, predicate): | ||
n | 51 | if self.basket.empty(): | n | 59 | if self.basket: |
52 | return None | ||||
53 | candy = predicate(self.basket) | 60 | candy = predicate(self.basket) | ||
54 | self.basket.remove(predicate(self.basket)) | 61 | self.basket.remove(predicate(self.basket)) | ||
55 | return candy | 62 | return candy | ||
56 | 63 | return None | |||
57 | |||||
58 | def dist_between(position1: tuple, position2: tuple): | ||||
59 | return sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | ||||
60 | 64 | ||||
61 | 65 | ||||
62 | class FluxCapacitor: | 66 | class FluxCapacitor: | ||
63 | def __init__(self, participants: set): | 67 | def __init__(self, participants: set): | ||
64 | self.participants = participants | 68 | self.participants = participants | ||
n | n | 69 | self.hosts = [host for host in participants if isinstance(host, Host)] | ||
70 | self.kids = [kid for kid in participants if isinstance(kid, Kid)] | ||||
65 | 71 | ||||
66 | def get_victim(self): | 72 | def get_victim(self): | ||
n | 67 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | n | 73 | hosts = self.hosts |
68 | kids = set(kid for kid in self.participants if isinstance(kid, Kid)) | 74 | kids = self.kids | ||
69 | kids_visited_hosts = {kid: () for kid in kids} | 75 | kids_visited_hosts = {kid: [] for kid in kids} | ||
70 | 76 | ||||
n | 71 | while len(kids) > 0 and len(hosts) > 0: | n | 77 | while [len(visited_hosts) for visited_hosts in kids_visited_hosts.values()].count(len(hosts)) != len(kids): |
72 | host_expected_kids = {host: () for host in hosts} | 78 | host_expected_kids = {host: [] for host in hosts} | ||
73 | 79 | ||||
74 | # Determine which children will be visiting each host | 80 | # Determine which children will be visiting each host | ||
75 | for kid in kids: | 81 | for kid in kids: | ||
n | 76 | closes_host: Host = Host(position=(int('inf'), int('inf')), candies=[]) | n | 82 | closest_host = Host(position=(float('inf'), float('inf')), candies=[]) |
77 | for host in hosts: | 83 | for host in hosts: | ||
78 | if host not in kids_visited_hosts[kid]: | 84 | if host not in kids_visited_hosts[kid]: | ||
n | 79 | if (distA := dist_between(kid.position, host.position)) < ( | n | 85 | if (distA := Person.dist_between(kid.position, host.position)) < ( |
80 | distB := dist_between(kid.position, closes_host.position)): | 86 | distB := Person.dist_between(kid.position, closest_host.position)): | ||
81 | closes_host = host | 87 | closest_host = host | ||
82 | elif distA == distB: | 88 | elif distA == distB: | ||
n | 83 | if host.position[0] < closes_host.position[0]: | n | 89 | if host.position[0] < closest_host.position[0]: |
84 | closes_host = host | 90 | closest_host = host | ||
85 | elif host.position[0] == closes_host.position[0]: | 91 | elif host.position[0] == closest_host.position[0] and host.position[1] < closest_host.position[1]: | ||
86 | if host.position[1] < closes_host.position[1]: | ||||
87 | closes_host = host | 92 | closest_host = host | ||
88 | if closes_host.position != (int('inf'), int('inf')): | 93 | if closest_host.position != (float('inf'), float('inf')): | ||
89 | host_expected_kids[closes_host].add(kid) | 94 | host_expected_kids[closest_host].append(kid) | ||
90 | 95 | ||||
91 | # Sort kids by initiative | 96 | # Sort kids by initiative | ||
n | 92 | for kids_list in host_expected_kids: | n | 97 | for kids_list in host_expected_kids.values(): |
93 | if len(kids_list) > 1: | 98 | if len(kids_list) > 1: | ||
94 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | 99 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | ||
n | 95 | n | |||
96 | # Sort host's candies in descending order | ||||
97 | for host in hosts: | ||||
98 | host.basket.sort(key=lambda x: x.mass, reverse=True) | ||||
99 | 100 | ||||
100 | # Give candy to kids in defined order | 101 | # Give candy to kids in defined order | ||
101 | for host in hosts: | 102 | for host in hosts: | ||
102 | # For every kid that wants to visit the host | 103 | # For every kid that wants to visit the host | ||
103 | for visiting_kid in host_expected_kids[host]: | 104 | for visiting_kid in host_expected_kids[host]: | ||
104 | # Check if there is any candy left | 105 | # Check if there is any candy left | ||
n | n | 106 | visiting_kid.set_position(host.get_position()) | ||
105 | if len(host.basket) == 0: | 107 | if host.basket: | ||
106 | # Kid does a trick to the owner, transforming them into a frog or smth | ||||
107 | pass | ||||
108 | else: | ||||
109 | # Host removes the candy from their basket and gives it to the kid | 108 | # Host removes the candy from their basket and gives it to the kid | ||
n | 110 | visiting_kid.add_candy(host.remove_candy(host.basket[0])) | n | 109 | visiting_kid.add_candy(host.remove_candy(lambda candy_basket: max(candy_basket, key=lambda candy: candy.get_mass()))) |
111 | # Kid now has visited this host and will never meet them again! | 110 | # Kid now has visited this host and will never meet them again! | ||
n | 112 | kids_visited_hosts[visiting_kid].add(host) | n | 111 | kids_visited_hosts[visiting_kid].append(host) |
113 | 112 | ||||
114 | # If there are any dead kids, return them | 113 | # If there are any dead kids, return them | ||
n | 115 | if len(dead_kids := set(kid for kid in kids if kid.is_critical())) > 0: | n | 114 | if dead_kids := set(kid for kid in kids if kid.is_critical()): |
116 | return dead_kids | 115 | return dead_kids | ||
117 | 116 | ||||
t | 118 | # Update kids and hosts to continue if there were no victims | t | 117 | return None |
119 | kids = [kid for kid in kids if not kid.is_critical()] | ||||
120 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | class Candy: | f | 1 | class Candy: |
2 | def __init__(self, mass: int, uranium: float): | 2 | def __init__(self, mass: int, uranium: float): | ||
3 | self.mass = mass | 3 | self.mass = mass | ||
4 | self.uranium = uranium | 4 | self.uranium = uranium | ||
5 | 5 | ||||
6 | def get_mass(self): | 6 | def get_mass(self): | ||
7 | return self.mass | 7 | return self.mass | ||
8 | 8 | ||||
9 | def get_uranium_quantity(self): | 9 | def get_uranium_quantity(self): | ||
10 | return self.mass * self.uranium | 10 | return self.mass * self.uranium | ||
11 | 11 | ||||
12 | 12 | ||||
13 | class Person: | 13 | class Person: | ||
14 | def __init__(self, position: tuple): | 14 | def __init__(self, position: tuple): | ||
15 | self.position = position | 15 | self.position = position | ||
16 | 16 | ||||
17 | def get_position(self): | 17 | def get_position(self): | ||
18 | return self.position | 18 | return self.position | ||
19 | 19 | ||||
20 | def set_position(self, position: tuple): | 20 | def set_position(self, position: tuple): | ||
21 | self.position = position | 21 | self.position = position | ||
22 | 22 | ||||
23 | 23 | ||||
24 | class Kid(Person): | 24 | class Kid(Person): | ||
25 | def __init__(self, position: tuple, initiative: int): | 25 | def __init__(self, position: tuple, initiative: int): | ||
26 | self.initiative = initiative | 26 | self.initiative = initiative | ||
27 | self.basket = [] | 27 | self.basket = [] | ||
28 | super().__init__(position) | 28 | super().__init__(position) | ||
29 | 29 | ||||
30 | def get_initiative(self): | 30 | def get_initiative(self): | ||
31 | return self.initiative | 31 | return self.initiative | ||
32 | 32 | ||||
33 | def add_candy(self, candy: Candy): | 33 | def add_candy(self, candy: Candy): | ||
34 | self.basket.append(candy) | 34 | self.basket.append(candy) | ||
35 | 35 | ||||
36 | def is_critical(self): | 36 | def is_critical(self): | ||
37 | total_uranium = 0 | 37 | total_uranium = 0 | ||
38 | for candy in self.basket: | 38 | for candy in self.basket: | ||
39 | total_uranium += candy.mass * candy.uranium | 39 | total_uranium += candy.mass * candy.uranium | ||
40 | return total_uranium > 20 | 40 | return total_uranium > 20 | ||
41 | 41 | ||||
42 | 42 | ||||
43 | class Host(Person): | 43 | class Host(Person): | ||
44 | def __init__(self, position: tuple, candies: list): | 44 | def __init__(self, position: tuple, candies: list): | ||
45 | self.basket = list() | 45 | self.basket = list() | ||
46 | for candy in candies: | 46 | for candy in candies: | ||
47 | self.basket.append(candy) | 47 | self.basket.append(candy) | ||
48 | super().__init__(position) | 48 | super().__init__(position) | ||
49 | 49 | ||||
50 | def remove_candy(self, predicate): | 50 | def remove_candy(self, predicate): | ||
51 | if self.basket.empty(): | 51 | if self.basket.empty(): | ||
52 | return None | 52 | return None | ||
53 | candy = predicate(self.basket) | 53 | candy = predicate(self.basket) | ||
54 | self.basket.remove(predicate(self.basket)) | 54 | self.basket.remove(predicate(self.basket)) | ||
55 | return candy | 55 | return candy | ||
56 | 56 | ||||
57 | 57 | ||||
58 | def dist_between(position1: tuple, position2: tuple): | 58 | def dist_between(position1: tuple, position2: tuple): | ||
59 | return sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | 59 | return sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | ||
60 | 60 | ||||
61 | 61 | ||||
62 | class FluxCapacitor: | 62 | class FluxCapacitor: | ||
63 | def __init__(self, participants: set): | 63 | def __init__(self, participants: set): | ||
64 | self.participants = participants | 64 | self.participants = participants | ||
65 | 65 | ||||
66 | def get_victim(self): | 66 | def get_victim(self): | ||
67 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | 67 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | ||
68 | kids = set(kid for kid in self.participants if isinstance(kid, Kid)) | 68 | kids = set(kid for kid in self.participants if isinstance(kid, Kid)) | ||
69 | kids_visited_hosts = {kid: () for kid in kids} | 69 | kids_visited_hosts = {kid: () for kid in kids} | ||
70 | 70 | ||||
71 | while len(kids) > 0 and len(hosts) > 0: | 71 | while len(kids) > 0 and len(hosts) > 0: | ||
72 | host_expected_kids = {host: () for host in hosts} | 72 | host_expected_kids = {host: () for host in hosts} | ||
73 | 73 | ||||
74 | # Determine which children will be visiting each host | 74 | # Determine which children will be visiting each host | ||
75 | for kid in kids: | 75 | for kid in kids: | ||
76 | closes_host: Host = Host(position=(int('inf'), int('inf')), candies=[]) | 76 | closes_host: Host = Host(position=(int('inf'), int('inf')), candies=[]) | ||
77 | for host in hosts: | 77 | for host in hosts: | ||
78 | if host not in kids_visited_hosts[kid]: | 78 | if host not in kids_visited_hosts[kid]: | ||
79 | if (distA := dist_between(kid.position, host.position)) < ( | 79 | if (distA := dist_between(kid.position, host.position)) < ( | ||
80 | distB := dist_between(kid.position, closes_host.position)): | 80 | distB := dist_between(kid.position, closes_host.position)): | ||
81 | closes_host = host | 81 | closes_host = host | ||
82 | elif distA == distB: | 82 | elif distA == distB: | ||
83 | if host.position[0] < closes_host.position[0]: | 83 | if host.position[0] < closes_host.position[0]: | ||
84 | closes_host = host | 84 | closes_host = host | ||
85 | elif host.position[0] == closes_host.position[0]: | 85 | elif host.position[0] == closes_host.position[0]: | ||
86 | if host.position[1] < closes_host.position[1]: | 86 | if host.position[1] < closes_host.position[1]: | ||
87 | closes_host = host | 87 | closes_host = host | ||
88 | if closes_host.position != (int('inf'), int('inf')): | 88 | if closes_host.position != (int('inf'), int('inf')): | ||
89 | host_expected_kids[closes_host].add(kid) | 89 | host_expected_kids[closes_host].add(kid) | ||
90 | 90 | ||||
91 | # Sort kids by initiative | 91 | # Sort kids by initiative | ||
92 | for kids_list in host_expected_kids: | 92 | for kids_list in host_expected_kids: | ||
93 | if len(kids_list) > 1: | 93 | if len(kids_list) > 1: | ||
94 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | 94 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | ||
95 | 95 | ||||
96 | # Sort host's candies in descending order | 96 | # Sort host's candies in descending order | ||
97 | for host in hosts: | 97 | for host in hosts: | ||
98 | host.basket.sort(key=lambda x: x.mass, reverse=True) | 98 | host.basket.sort(key=lambda x: x.mass, reverse=True) | ||
99 | 99 | ||||
100 | # Give candy to kids in defined order | 100 | # Give candy to kids in defined order | ||
101 | for host in hosts: | 101 | for host in hosts: | ||
102 | # For every kid that wants to visit the host | 102 | # For every kid that wants to visit the host | ||
103 | for visiting_kid in host_expected_kids[host]: | 103 | for visiting_kid in host_expected_kids[host]: | ||
104 | # Check if there is any candy left | 104 | # Check if there is any candy left | ||
105 | if len(host.basket) == 0: | 105 | if len(host.basket) == 0: | ||
106 | # Kid does a trick to the owner, transforming them into a frog or smth | 106 | # Kid does a trick to the owner, transforming them into a frog or smth | ||
107 | pass | 107 | pass | ||
108 | else: | 108 | else: | ||
109 | # Host removes the candy from their basket and gives it to the kid | 109 | # Host removes the candy from their basket and gives it to the kid | ||
110 | visiting_kid.add_candy(host.remove_candy(host.basket[0])) | 110 | visiting_kid.add_candy(host.remove_candy(host.basket[0])) | ||
111 | # Kid now has visited this host and will never meet them again! | 111 | # Kid now has visited this host and will never meet them again! | ||
112 | kids_visited_hosts[visiting_kid].add(host) | 112 | kids_visited_hosts[visiting_kid].add(host) | ||
113 | 113 | ||||
114 | # If there are any dead kids, return them | 114 | # If there are any dead kids, return them | ||
115 | if len(dead_kids := set(kid for kid in kids if kid.is_critical())) > 0: | 115 | if len(dead_kids := set(kid for kid in kids if kid.is_critical())) > 0: | ||
116 | return dead_kids | 116 | return dead_kids | ||
117 | 117 | ||||
118 | # Update kids and hosts to continue if there were no victims | 118 | # Update kids and hosts to continue if there were no victims | ||
119 | kids = [kid for kid in kids if not kid.is_critical()] | 119 | kids = [kid for kid in kids if not kid.is_critical()] | ||
120 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | 120 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | ||
t | 121 | t | |||
122 | |||||
123 | if __name__ == "__main__": | ||||
124 | kid = Kid((1, 1), 1) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | class Candy: | f | 1 | class Candy: |
2 | def __init__(self, mass: int, uranium: float): | 2 | def __init__(self, mass: int, uranium: float): | ||
3 | self.mass = mass | 3 | self.mass = mass | ||
4 | self.uranium = uranium | 4 | self.uranium = uranium | ||
5 | 5 | ||||
6 | def get_mass(self): | 6 | def get_mass(self): | ||
7 | return self.mass | 7 | return self.mass | ||
8 | 8 | ||||
9 | def get_uranium_quantity(self): | 9 | def get_uranium_quantity(self): | ||
10 | return self.mass * self.uranium | 10 | return self.mass * self.uranium | ||
11 | 11 | ||||
12 | 12 | ||||
13 | class Person: | 13 | class Person: | ||
14 | def __init__(self, position: tuple): | 14 | def __init__(self, position: tuple): | ||
15 | self.position = position | 15 | self.position = position | ||
16 | 16 | ||||
17 | def get_position(self): | 17 | def get_position(self): | ||
18 | return self.position | 18 | return self.position | ||
19 | 19 | ||||
20 | def set_position(self, position: tuple): | 20 | def set_position(self, position: tuple): | ||
21 | self.position = position | 21 | self.position = position | ||
22 | 22 | ||||
23 | 23 | ||||
24 | class Kid(Person): | 24 | class Kid(Person): | ||
n | 25 | def __int__(self, position: tuple, initiative: int): | n | 25 | def __init__(self, position: tuple, initiative: int): |
26 | self.initiative = initiative | 26 | self.initiative = initiative | ||
27 | self.basket = [] | 27 | self.basket = [] | ||
28 | super().__init__(position) | 28 | super().__init__(position) | ||
29 | 29 | ||||
30 | def get_initiative(self): | 30 | def get_initiative(self): | ||
31 | return self.initiative | 31 | return self.initiative | ||
32 | 32 | ||||
33 | def add_candy(self, candy: Candy): | 33 | def add_candy(self, candy: Candy): | ||
34 | self.basket.append(candy) | 34 | self.basket.append(candy) | ||
35 | 35 | ||||
36 | def is_critical(self): | 36 | def is_critical(self): | ||
37 | total_uranium = 0 | 37 | total_uranium = 0 | ||
38 | for candy in self.basket: | 38 | for candy in self.basket: | ||
39 | total_uranium += candy.mass * candy.uranium | 39 | total_uranium += candy.mass * candy.uranium | ||
40 | return total_uranium > 20 | 40 | return total_uranium > 20 | ||
41 | 41 | ||||
42 | 42 | ||||
43 | class Host(Person): | 43 | class Host(Person): | ||
44 | def __init__(self, position: tuple, candies: list): | 44 | def __init__(self, position: tuple, candies: list): | ||
45 | self.basket = list() | 45 | self.basket = list() | ||
46 | for candy in candies: | 46 | for candy in candies: | ||
47 | self.basket.append(candy) | 47 | self.basket.append(candy) | ||
48 | super().__init__(position) | 48 | super().__init__(position) | ||
49 | 49 | ||||
50 | def remove_candy(self, predicate): | 50 | def remove_candy(self, predicate): | ||
51 | if self.basket.empty(): | 51 | if self.basket.empty(): | ||
52 | return None | 52 | return None | ||
53 | candy = predicate(self.basket) | 53 | candy = predicate(self.basket) | ||
54 | self.basket.remove(predicate(self.basket)) | 54 | self.basket.remove(predicate(self.basket)) | ||
55 | return candy | 55 | return candy | ||
56 | 56 | ||||
57 | 57 | ||||
58 | def dist_between(position1: tuple, position2: tuple): | 58 | def dist_between(position1: tuple, position2: tuple): | ||
59 | return sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | 59 | return sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | ||
60 | 60 | ||||
61 | 61 | ||||
62 | class FluxCapacitor: | 62 | class FluxCapacitor: | ||
63 | def __init__(self, participants: set): | 63 | def __init__(self, participants: set): | ||
64 | self.participants = participants | 64 | self.participants = participants | ||
65 | 65 | ||||
66 | def get_victim(self): | 66 | def get_victim(self): | ||
67 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | 67 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | ||
68 | kids = set(kid for kid in self.participants if isinstance(kid, Kid)) | 68 | kids = set(kid for kid in self.participants if isinstance(kid, Kid)) | ||
69 | kids_visited_hosts = {kid: () for kid in kids} | 69 | kids_visited_hosts = {kid: () for kid in kids} | ||
70 | 70 | ||||
71 | while len(kids) > 0 and len(hosts) > 0: | 71 | while len(kids) > 0 and len(hosts) > 0: | ||
72 | host_expected_kids = {host: () for host in hosts} | 72 | host_expected_kids = {host: () for host in hosts} | ||
73 | 73 | ||||
74 | # Determine which children will be visiting each host | 74 | # Determine which children will be visiting each host | ||
75 | for kid in kids: | 75 | for kid in kids: | ||
76 | closes_host: Host = Host(position=(int('inf'), int('inf')), candies=[]) | 76 | closes_host: Host = Host(position=(int('inf'), int('inf')), candies=[]) | ||
77 | for host in hosts: | 77 | for host in hosts: | ||
78 | if host not in kids_visited_hosts[kid]: | 78 | if host not in kids_visited_hosts[kid]: | ||
79 | if (distA := dist_between(kid.position, host.position)) < ( | 79 | if (distA := dist_between(kid.position, host.position)) < ( | ||
80 | distB := dist_between(kid.position, closes_host.position)): | 80 | distB := dist_between(kid.position, closes_host.position)): | ||
81 | closes_host = host | 81 | closes_host = host | ||
82 | elif distA == distB: | 82 | elif distA == distB: | ||
83 | if host.position[0] < closes_host.position[0]: | 83 | if host.position[0] < closes_host.position[0]: | ||
84 | closes_host = host | 84 | closes_host = host | ||
85 | elif host.position[0] == closes_host.position[0]: | 85 | elif host.position[0] == closes_host.position[0]: | ||
86 | if host.position[1] < closes_host.position[1]: | 86 | if host.position[1] < closes_host.position[1]: | ||
87 | closes_host = host | 87 | closes_host = host | ||
88 | if closes_host.position != (int('inf'), int('inf')): | 88 | if closes_host.position != (int('inf'), int('inf')): | ||
89 | host_expected_kids[closes_host].add(kid) | 89 | host_expected_kids[closes_host].add(kid) | ||
90 | 90 | ||||
91 | # Sort kids by initiative | 91 | # Sort kids by initiative | ||
92 | for kids_list in host_expected_kids: | 92 | for kids_list in host_expected_kids: | ||
93 | if len(kids_list) > 1: | 93 | if len(kids_list) > 1: | ||
94 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | 94 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | ||
95 | 95 | ||||
96 | # Sort host's candies in descending order | 96 | # Sort host's candies in descending order | ||
97 | for host in hosts: | 97 | for host in hosts: | ||
98 | host.basket.sort(key=lambda x: x.mass, reverse=True) | 98 | host.basket.sort(key=lambda x: x.mass, reverse=True) | ||
99 | 99 | ||||
100 | # Give candy to kids in defined order | 100 | # Give candy to kids in defined order | ||
101 | for host in hosts: | 101 | for host in hosts: | ||
102 | # For every kid that wants to visit the host | 102 | # For every kid that wants to visit the host | ||
103 | for visiting_kid in host_expected_kids[host]: | 103 | for visiting_kid in host_expected_kids[host]: | ||
104 | # Check if there is any candy left | 104 | # Check if there is any candy left | ||
105 | if len(host.basket) == 0: | 105 | if len(host.basket) == 0: | ||
106 | # Kid does a trick to the owner, transforming them into a frog or smth | 106 | # Kid does a trick to the owner, transforming them into a frog or smth | ||
107 | pass | 107 | pass | ||
108 | else: | 108 | else: | ||
109 | # Host removes the candy from their basket and gives it to the kid | 109 | # Host removes the candy from their basket and gives it to the kid | ||
110 | visiting_kid.add_candy(host.remove_candy(host.basket[0])) | 110 | visiting_kid.add_candy(host.remove_candy(host.basket[0])) | ||
111 | # Kid now has visited this host and will never meet them again! | 111 | # Kid now has visited this host and will never meet them again! | ||
112 | kids_visited_hosts[visiting_kid].add(host) | 112 | kids_visited_hosts[visiting_kid].add(host) | ||
113 | 113 | ||||
114 | # If there are any dead kids, return them | 114 | # If there are any dead kids, return them | ||
115 | if len(dead_kids := set(kid for kid in kids if kid.is_critical())) > 0: | 115 | if len(dead_kids := set(kid for kid in kids if kid.is_critical())) > 0: | ||
116 | return dead_kids | 116 | return dead_kids | ||
117 | 117 | ||||
118 | # Update kids and hosts to continue if there were no victims | 118 | # Update kids and hosts to continue if there were no victims | ||
119 | kids = [kid for kid in kids if not kid.is_critical()] | 119 | kids = [kid for kid in kids if not kid.is_critical()] | ||
120 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | 120 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | ||
t | t | 121 | |||
122 | |||||
123 | if __name__ == "__main__": | ||||
124 | kid = Kid((1, 1), 1) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
t | 1 | class Candy: | t | 1 | class Candy: |
2 | def __init__(self, mass: int, uranium: float): | 2 | def __init__(self, mass: int, uranium: float): | ||
3 | self.mass = mass | 3 | self.mass = mass | ||
4 | self.uranium = uranium | 4 | self.uranium = uranium | ||
5 | 5 | ||||
6 | def get_mass(self): | 6 | def get_mass(self): | ||
7 | return self.mass | 7 | return self.mass | ||
8 | 8 | ||||
9 | def get_uranium_quantity(self): | 9 | def get_uranium_quantity(self): | ||
10 | return self.mass * self.uranium | 10 | return self.mass * self.uranium | ||
11 | 11 | ||||
12 | 12 | ||||
13 | class Person: | 13 | class Person: | ||
14 | def __init__(self, position: tuple): | 14 | def __init__(self, position: tuple): | ||
15 | self.position = position | 15 | self.position = position | ||
16 | 16 | ||||
17 | def get_position(self): | 17 | def get_position(self): | ||
18 | return self.position | 18 | return self.position | ||
19 | 19 | ||||
20 | def set_position(self, position: tuple): | 20 | def set_position(self, position: tuple): | ||
21 | self.position = position | 21 | self.position = position | ||
22 | 22 | ||||
23 | 23 | ||||
24 | class Kid(Person): | 24 | class Kid(Person): | ||
25 | def __int__(self, position: tuple, initiative: int): | 25 | def __int__(self, position: tuple, initiative: int): | ||
26 | self.initiative = initiative | 26 | self.initiative = initiative | ||
27 | self.basket = [] | 27 | self.basket = [] | ||
28 | super().__init__(position) | 28 | super().__init__(position) | ||
29 | 29 | ||||
30 | def get_initiative(self): | 30 | def get_initiative(self): | ||
31 | return self.initiative | 31 | return self.initiative | ||
32 | 32 | ||||
33 | def add_candy(self, candy: Candy): | 33 | def add_candy(self, candy: Candy): | ||
34 | self.basket.append(candy) | 34 | self.basket.append(candy) | ||
35 | 35 | ||||
36 | def is_critical(self): | 36 | def is_critical(self): | ||
37 | total_uranium = 0 | 37 | total_uranium = 0 | ||
38 | for candy in self.basket: | 38 | for candy in self.basket: | ||
39 | total_uranium += candy.mass * candy.uranium | 39 | total_uranium += candy.mass * candy.uranium | ||
40 | return total_uranium > 20 | 40 | return total_uranium > 20 | ||
41 | 41 | ||||
42 | 42 | ||||
43 | class Host(Person): | 43 | class Host(Person): | ||
44 | def __init__(self, position: tuple, candies: list): | 44 | def __init__(self, position: tuple, candies: list): | ||
45 | self.basket = list() | 45 | self.basket = list() | ||
46 | for candy in candies: | 46 | for candy in candies: | ||
47 | self.basket.append(candy) | 47 | self.basket.append(candy) | ||
48 | super().__init__(position) | 48 | super().__init__(position) | ||
49 | 49 | ||||
50 | def remove_candy(self, predicate): | 50 | def remove_candy(self, predicate): | ||
51 | if self.basket.empty(): | 51 | if self.basket.empty(): | ||
52 | return None | 52 | return None | ||
53 | candy = predicate(self.basket) | 53 | candy = predicate(self.basket) | ||
54 | self.basket.remove(predicate(self.basket)) | 54 | self.basket.remove(predicate(self.basket)) | ||
55 | return candy | 55 | return candy | ||
56 | 56 | ||||
57 | 57 | ||||
58 | def dist_between(position1: tuple, position2: tuple): | 58 | def dist_between(position1: tuple, position2: tuple): | ||
59 | return sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | 59 | return sqrt((position2[0] - position1[0]) ** 2 + (position2[1] - position1[1]) ** 2) | ||
60 | 60 | ||||
61 | 61 | ||||
62 | class FluxCapacitor: | 62 | class FluxCapacitor: | ||
63 | def __init__(self, participants: set): | 63 | def __init__(self, participants: set): | ||
64 | self.participants = participants | 64 | self.participants = participants | ||
65 | 65 | ||||
66 | def get_victim(self): | 66 | def get_victim(self): | ||
67 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | 67 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | ||
68 | kids = set(kid for kid in self.participants if isinstance(kid, Kid)) | 68 | kids = set(kid for kid in self.participants if isinstance(kid, Kid)) | ||
69 | kids_visited_hosts = {kid: () for kid in kids} | 69 | kids_visited_hosts = {kid: () for kid in kids} | ||
70 | 70 | ||||
71 | while len(kids) > 0 and len(hosts) > 0: | 71 | while len(kids) > 0 and len(hosts) > 0: | ||
72 | host_expected_kids = {host: () for host in hosts} | 72 | host_expected_kids = {host: () for host in hosts} | ||
73 | 73 | ||||
74 | # Determine which children will be visiting each host | 74 | # Determine which children will be visiting each host | ||
75 | for kid in kids: | 75 | for kid in kids: | ||
76 | closes_host: Host = Host(position=(int('inf'), int('inf')), candies=[]) | 76 | closes_host: Host = Host(position=(int('inf'), int('inf')), candies=[]) | ||
77 | for host in hosts: | 77 | for host in hosts: | ||
78 | if host not in kids_visited_hosts[kid]: | 78 | if host not in kids_visited_hosts[kid]: | ||
79 | if (distA := dist_between(kid.position, host.position)) < ( | 79 | if (distA := dist_between(kid.position, host.position)) < ( | ||
80 | distB := dist_between(kid.position, closes_host.position)): | 80 | distB := dist_between(kid.position, closes_host.position)): | ||
81 | closes_host = host | 81 | closes_host = host | ||
82 | elif distA == distB: | 82 | elif distA == distB: | ||
83 | if host.position[0] < closes_host.position[0]: | 83 | if host.position[0] < closes_host.position[0]: | ||
84 | closes_host = host | 84 | closes_host = host | ||
85 | elif host.position[0] == closes_host.position[0]: | 85 | elif host.position[0] == closes_host.position[0]: | ||
86 | if host.position[1] < closes_host.position[1]: | 86 | if host.position[1] < closes_host.position[1]: | ||
87 | closes_host = host | 87 | closes_host = host | ||
88 | if closes_host.position != (int('inf'), int('inf')): | 88 | if closes_host.position != (int('inf'), int('inf')): | ||
89 | host_expected_kids[closes_host].add(kid) | 89 | host_expected_kids[closes_host].add(kid) | ||
90 | 90 | ||||
91 | # Sort kids by initiative | 91 | # Sort kids by initiative | ||
92 | for kids_list in host_expected_kids: | 92 | for kids_list in host_expected_kids: | ||
93 | if len(kids_list) > 1: | 93 | if len(kids_list) > 1: | ||
94 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | 94 | kids_list.sort(key=lambda x: x.initiative, reverse=True) | ||
95 | 95 | ||||
96 | # Sort host's candies in descending order | 96 | # Sort host's candies in descending order | ||
97 | for host in hosts: | 97 | for host in hosts: | ||
98 | host.basket.sort(key=lambda x: x.mass, reverse=True) | 98 | host.basket.sort(key=lambda x: x.mass, reverse=True) | ||
99 | 99 | ||||
100 | # Give candy to kids in defined order | 100 | # Give candy to kids in defined order | ||
101 | for host in hosts: | 101 | for host in hosts: | ||
102 | # For every kid that wants to visit the host | 102 | # For every kid that wants to visit the host | ||
103 | for visiting_kid in host_expected_kids[host]: | 103 | for visiting_kid in host_expected_kids[host]: | ||
104 | # Check if there is any candy left | 104 | # Check if there is any candy left | ||
105 | if len(host.basket) == 0: | 105 | if len(host.basket) == 0: | ||
106 | # Kid does a trick to the owner, transforming them into a frog or smth | 106 | # Kid does a trick to the owner, transforming them into a frog or smth | ||
107 | pass | 107 | pass | ||
108 | else: | 108 | else: | ||
109 | # Host removes the candy from their basket and gives it to the kid | 109 | # Host removes the candy from their basket and gives it to the kid | ||
110 | visiting_kid.add_candy(host.remove_candy(host.basket[0])) | 110 | visiting_kid.add_candy(host.remove_candy(host.basket[0])) | ||
111 | # Kid now has visited this host and will never meet them again! | 111 | # Kid now has visited this host and will never meet them again! | ||
112 | kids_visited_hosts[visiting_kid].add(host) | 112 | kids_visited_hosts[visiting_kid].add(host) | ||
113 | 113 | ||||
114 | # If there are any dead kids, return them | 114 | # If there are any dead kids, return them | ||
115 | if len(dead_kids := set(kid for kid in kids if kid.is_critical())) > 0: | 115 | if len(dead_kids := set(kid for kid in kids if kid.is_critical())) > 0: | ||
116 | return dead_kids | 116 | return dead_kids | ||
117 | 117 | ||||
118 | # Update kids and hosts to continue if there were no victims | 118 | # Update kids and hosts to continue if there were no victims | ||
119 | kids = [kid for kid in kids if not kid.is_critical()] | 119 | kids = [kid for kid in kids if not kid.is_critical()] | ||
120 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) | 120 | hosts = set(host for host in self.participants if isinstance(host, Host) and len(host.basket) > 0) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|