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 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||