1import math
2
3
4class Candy:
5
6 def __init__(self, mass, uranium):
7 self.mass = mass
8 self.uranium = uranium
9
10 def get_uranium_quantity(self):
11 """Return the quantity of uranium in grams."""
12 return self.mass * self.uranium
13
14 def get_mass(self):
15 return self.mass
16
17
18class Person:
19
20 def __init__(self, position):
21 self.position = position
22
23 def get_position(self):
24 return self.position
25
26 def set_position(self, position):
27 self.position = position
28
29 @staticmethod
30 def get_distance(person_1, person_2):
31 """Calculate the distance between two people."""
32 dx = person_1.position[0] - person_2.position[0]
33 dy = person_1.position[1] - person_2.position[1]
34 return math.sqrt(dx ** 2 + dy ** 2)
35
36
37class Kid(Person):
38
39 CRITICAL_MASS = 20
40
41 def __init__(self, position, initiative):
42 super().__init__(position)
43 self.initiative = initiative
44 self.basket = list()
45
46 def get_initiative(self):
47 return self.initiative
48
49 def add_candy(self, candy_to_add):
50 self.basket.append(candy_to_add)
51
52 def is_critical(self):
53 """Sum the uranium contents of all candies and returns true if sum > 20."""
54 uranium_sum = sum(candy.get_uranium_quantity() for candy in self.basket)
55 return uranium_sum > Kid.CRITICAL_MASS
56
57
58class Host(Person):
59
60 def __init__(self, position, candies):
61 super().__init__(position)
62 self.candies = [Candy(x, y) for x, y in candies]
63 self.visited_from = [] # add children that already visited a given host here
64 self.current_visitors = [] # add children that are visiting the host at the moment
65
66 def remove_candy(self, func_remove_candy):
67 # if the host doesn't have candy, do nothing
68 if not self.candies:
69 return None
70 # save the candy to delete from the list
71 candy_to_remove = func_remove_candy(self.candies)
72 self.candies.remove(candy_to_remove)
73 return candy_to_remove
74
75
76class FluxCapacitor:
77
78 def __init__(self, participants):
79 self.kids = [person for person in participants if type(person) == Kid]
80 self.hosts = [person for person in participants if type(person) == Host]
81
82 @staticmethod
83 def find_candy_with_biggest_mass(candies):
84 return max(candies, key=lambda some_candy: some_candy.mass)
85
86 def get_victim(self):
87 while True:
88 all_kids_visited_all_hosts = all(len(host.visited_from) == len(self.kids) for host in self.hosts)
89 if all_kids_visited_all_hosts:
90 break
91
92 # first, determine for each kid which house it's going to visit
93 for kid in self.kids:
94 try:
95 closest_unvisited_house = min([host for host in self.hosts if kid not in host.visited_from],
96 key=lambda host: (
97 Person.get_distance(kid, host), host.position[0],
98 host.position[1]))
99 # ValueError will be thrown if the iterable is empty (there are no unvisited hosts for the current kid)
100 except ValueError:
101 continue
102
103 # mark closest_unvisited_house as being actively visited by the respective kid
104 closest_unvisited_house.current_visitors.append(kid)
105 # the kid moves to the closest house, so change its coordinates
106 kid.set_position(closest_unvisited_house.position)
107
108 # secondly, make the hosts distribute the candy
109 for host in self.hosts:
110 while host.current_visitors: # aim to empty the active visitors list
111 # if the host doesn't have candy, remove all current visitors
112 # and add them to the list of past visitors
113 if not host.candies:
114 host.visited_from += host.current_visitors
115 host.current_visitors = []
116 break
117
118 # determine the next kid by comparing initiatives
119 next_kid = max(host.current_visitors, key=lambda some_kid: some_kid.initiative)
120 # find candy for the next kid
121 next_candy = host.remove_candy(FluxCapacitor.find_candy_with_biggest_mass)
122 # add candy to kid's basket
123 next_kid.add_candy(next_candy)
124 # save the kid in the list of past visitors and remove it from active visitors
125 host.visited_from.append(next_kid)
126 host.current_visitors.remove(next_kid)
127
128 # the last step is to add all children that have received critical mass to a set
129 irridated_kids = set()
130 for kid in self.kids:
131 if kid.is_critical():
132 irridated_kids.add(kid)
133 if irridated_kids:
134 return irridated_kids
135
136 return None
............
----------------------------------------------------------------------
Ran 12 tests in 0.001s
OK
Георги Кунчев
03.11.2023 14:49Сега е ок. Няма безкраен цикъл.
|
Георги Кунчев
03.11.2023 11:29При тестване се получава безкраен цикъл. Моля изтествай си решението за `FluxCapacitor` с някакъв реален случай.
|
| f | 1 | import math | f | 1 | import math |
| 2 | 2 | ||||
| 3 | 3 | ||||
| 4 | class Candy: | 4 | class Candy: | ||
| 5 | 5 | ||||
| 6 | def __init__(self, mass, uranium): | 6 | def __init__(self, mass, uranium): | ||
| 7 | self.mass = mass | 7 | self.mass = mass | ||
| 8 | self.uranium = uranium | 8 | self.uranium = uranium | ||
| 9 | 9 | ||||
| 10 | def get_uranium_quantity(self): | 10 | def get_uranium_quantity(self): | ||
| 11 | """Return the quantity of uranium in grams.""" | 11 | """Return the quantity of uranium in grams.""" | ||
| 12 | return self.mass * self.uranium | 12 | return self.mass * self.uranium | ||
| 13 | 13 | ||||
| 14 | def get_mass(self): | 14 | def get_mass(self): | ||
| 15 | return self.mass | 15 | return self.mass | ||
| 16 | 16 | ||||
| 17 | 17 | ||||
| 18 | class Person: | 18 | class Person: | ||
| 19 | 19 | ||||
| 20 | def __init__(self, position): | 20 | def __init__(self, position): | ||
| 21 | self.position = position | 21 | self.position = position | ||
| 22 | 22 | ||||
| 23 | def get_position(self): | 23 | def get_position(self): | ||
| 24 | return self.position | 24 | return self.position | ||
| 25 | 25 | ||||
| 26 | def set_position(self, position): | 26 | def set_position(self, position): | ||
| 27 | self.position = position | 27 | self.position = position | ||
| 28 | 28 | ||||
| 29 | @staticmethod | 29 | @staticmethod | ||
| 30 | def get_distance(person_1, person_2): | 30 | def get_distance(person_1, person_2): | ||
| 31 | """Calculate the distance between two people.""" | 31 | """Calculate the distance between two people.""" | ||
| 32 | dx = person_1.position[0] - person_2.position[0] | 32 | dx = person_1.position[0] - person_2.position[0] | ||
| 33 | dy = person_1.position[1] - person_2.position[1] | 33 | dy = person_1.position[1] - person_2.position[1] | ||
| 34 | return math.sqrt(dx ** 2 + dy ** 2) | 34 | return math.sqrt(dx ** 2 + dy ** 2) | ||
| 35 | 35 | ||||
| 36 | 36 | ||||
| 37 | class Kid(Person): | 37 | class Kid(Person): | ||
| 38 | 38 | ||||
| 39 | CRITICAL_MASS = 20 | 39 | CRITICAL_MASS = 20 | ||
| 40 | 40 | ||||
| 41 | def __init__(self, position, initiative): | 41 | def __init__(self, position, initiative): | ||
| 42 | super().__init__(position) | 42 | super().__init__(position) | ||
| 43 | self.initiative = initiative | 43 | self.initiative = initiative | ||
| 44 | self.basket = list() | 44 | self.basket = list() | ||
| 45 | 45 | ||||
| 46 | def get_initiative(self): | 46 | def get_initiative(self): | ||
| 47 | return self.initiative | 47 | return self.initiative | ||
| 48 | 48 | ||||
| 49 | def add_candy(self, candy_to_add): | 49 | def add_candy(self, candy_to_add): | ||
| 50 | self.basket.append(candy_to_add) | 50 | self.basket.append(candy_to_add) | ||
| 51 | 51 | ||||
| 52 | def is_critical(self): | 52 | def is_critical(self): | ||
| 53 | """Sum the uranium contents of all candies and returns true if sum > 20.""" | 53 | """Sum the uranium contents of all candies and returns true if sum > 20.""" | ||
| 54 | uranium_sum = sum(candy.get_uranium_quantity() for candy in self.basket) | 54 | uranium_sum = sum(candy.get_uranium_quantity() for candy in self.basket) | ||
| 55 | return uranium_sum > Kid.CRITICAL_MASS | 55 | return uranium_sum > Kid.CRITICAL_MASS | ||
| 56 | 56 | ||||
| 57 | 57 | ||||
| 58 | class Host(Person): | 58 | class Host(Person): | ||
| 59 | 59 | ||||
| 60 | def __init__(self, position, candies): | 60 | def __init__(self, position, candies): | ||
| 61 | super().__init__(position) | 61 | super().__init__(position) | ||
| 62 | self.candies = [Candy(x, y) for x, y in candies] | 62 | self.candies = [Candy(x, y) for x, y in candies] | ||
| 63 | self.visited_from = [] # add children that already visited a given host here | 63 | self.visited_from = [] # add children that already visited a given host here | ||
| 64 | self.current_visitors = [] # add children that are visiting the host at the moment | 64 | self.current_visitors = [] # add children that are visiting the host at the moment | ||
| 65 | 65 | ||||
| 66 | def remove_candy(self, func_remove_candy): | 66 | def remove_candy(self, func_remove_candy): | ||
| 67 | # if the host doesn't have candy, do nothing | 67 | # if the host doesn't have candy, do nothing | ||
| 68 | if not self.candies: | 68 | if not self.candies: | ||
| 69 | return None | 69 | return None | ||
| 70 | # save the candy to delete from the list | 70 | # save the candy to delete from the list | ||
| 71 | candy_to_remove = func_remove_candy(self.candies) | 71 | candy_to_remove = func_remove_candy(self.candies) | ||
| 72 | self.candies.remove(candy_to_remove) | 72 | self.candies.remove(candy_to_remove) | ||
| 73 | return candy_to_remove | 73 | return candy_to_remove | ||
| 74 | 74 | ||||
| 75 | 75 | ||||
| 76 | class FluxCapacitor: | 76 | class FluxCapacitor: | ||
| 77 | 77 | ||||
| 78 | def __init__(self, participants): | 78 | def __init__(self, participants): | ||
| 79 | self.kids = [person for person in participants if type(person) == Kid] | 79 | self.kids = [person for person in participants if type(person) == Kid] | ||
| 80 | self.hosts = [person for person in participants if type(person) == Host] | 80 | self.hosts = [person for person in participants if type(person) == Host] | ||
| 81 | 81 | ||||
| 82 | @staticmethod | 82 | @staticmethod | ||
| 83 | def find_candy_with_biggest_mass(candies): | 83 | def find_candy_with_biggest_mass(candies): | ||
| 84 | return max(candies, key=lambda some_candy: some_candy.mass) | 84 | return max(candies, key=lambda some_candy: some_candy.mass) | ||
| 85 | 85 | ||||
| 86 | def get_victim(self): | 86 | def get_victim(self): | ||
| 87 | while True: | 87 | while True: | ||
| 88 | all_kids_visited_all_hosts = all(len(host.visited_from) == len(self.kids) for host in self.hosts) | 88 | all_kids_visited_all_hosts = all(len(host.visited_from) == len(self.kids) for host in self.hosts) | ||
| 89 | if all_kids_visited_all_hosts: | 89 | if all_kids_visited_all_hosts: | ||
| 90 | break | 90 | break | ||
| 91 | 91 | ||||
| 92 | # first, determine for each kid which house it's going to visit | 92 | # first, determine for each kid which house it's going to visit | ||
| 93 | for kid in self.kids: | 93 | for kid in self.kids: | ||
| 94 | try: | 94 | try: | ||
| 95 | closest_unvisited_house = min([host for host in self.hosts if kid not in host.visited_from], | 95 | closest_unvisited_house = min([host for host in self.hosts if kid not in host.visited_from], | ||
| 96 | key=lambda host: ( | 96 | key=lambda host: ( | ||
| 97 | Person.get_distance(kid, host), host.position[0], | 97 | Person.get_distance(kid, host), host.position[0], | ||
| 98 | host.position[1])) | 98 | host.position[1])) | ||
| n | 99 | # ValueError will be thrown if the iterable is empty (there are no unvisited self.hosts for the current kid) | n | 99 | # ValueError will be thrown if the iterable is empty (there are no unvisited hosts for the current kid) |
| 100 | except ValueError: | 100 | except ValueError: | ||
| 101 | continue | 101 | continue | ||
| 102 | 102 | ||||
| n | 103 | # mark the closest_unvisited_house as being actively visited by the respective kid | n | 103 | # mark closest_unvisited_house as being actively visited by the respective kid |
| 104 | closest_unvisited_house.current_visitors.append(kid) | 104 | closest_unvisited_house.current_visitors.append(kid) | ||
| 105 | # the kid moves to the closest house, so change its coordinates | 105 | # the kid moves to the closest house, so change its coordinates | ||
| 106 | kid.set_position(closest_unvisited_house.position) | 106 | kid.set_position(closest_unvisited_house.position) | ||
| 107 | 107 | ||||
| t | 108 | # secondly, make the self.hosts distribute the candy | t | 108 | # secondly, make the hosts distribute the candy |
| 109 | for host in self.hosts: | 109 | for host in self.hosts: | ||
| 110 | while host.current_visitors: # aim to empty the active visitors list | 110 | while host.current_visitors: # aim to empty the active visitors list | ||
| 111 | # if the host doesn't have candy, remove all current visitors | 111 | # if the host doesn't have candy, remove all current visitors | ||
| 112 | # and add them to the list of past visitors | 112 | # and add them to the list of past visitors | ||
| 113 | if not host.candies: | 113 | if not host.candies: | ||
| 114 | host.visited_from += host.current_visitors | 114 | host.visited_from += host.current_visitors | ||
| 115 | host.current_visitors = [] | 115 | host.current_visitors = [] | ||
| 116 | break | 116 | break | ||
| 117 | 117 | ||||
| 118 | # determine the next kid by comparing initiatives | 118 | # determine the next kid by comparing initiatives | ||
| 119 | next_kid = max(host.current_visitors, key=lambda some_kid: some_kid.initiative) | 119 | next_kid = max(host.current_visitors, key=lambda some_kid: some_kid.initiative) | ||
| 120 | # find candy for the next kid | 120 | # find candy for the next kid | ||
| 121 | next_candy = host.remove_candy(FluxCapacitor.find_candy_with_biggest_mass) | 121 | next_candy = host.remove_candy(FluxCapacitor.find_candy_with_biggest_mass) | ||
| 122 | # add candy to kid's basket | 122 | # add candy to kid's basket | ||
| 123 | next_kid.add_candy(next_candy) | 123 | next_kid.add_candy(next_candy) | ||
| 124 | # save the kid in the list of past visitors and remove it from active visitors | 124 | # save the kid in the list of past visitors and remove it from active visitors | ||
| 125 | host.visited_from.append(next_kid) | 125 | host.visited_from.append(next_kid) | ||
| 126 | host.current_visitors.remove(next_kid) | 126 | host.current_visitors.remove(next_kid) | ||
| 127 | 127 | ||||
| 128 | # the last step is to add all children that have received critical mass to a set | 128 | # the last step is to add all children that have received critical mass to a set | ||
| 129 | irridated_kids = set() | 129 | irridated_kids = set() | ||
| 130 | for kid in self.kids: | 130 | for kid in self.kids: | ||
| 131 | if kid.is_critical(): | 131 | if kid.is_critical(): | ||
| 132 | irridated_kids.add(kid) | 132 | irridated_kids.add(kid) | ||
| 133 | if irridated_kids: | 133 | if irridated_kids: | ||
| 134 | return irridated_kids | 134 | return irridated_kids | ||
| 135 | 135 | ||||
| 136 | return None | 136 | return None |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import math | f | 1 | import math |
| 2 | 2 | ||||
| 3 | 3 | ||||
| 4 | class Candy: | 4 | class Candy: | ||
| n | n | 5 | |||
| 5 | def __init__(self, mass, uranium): | 6 | def __init__(self, mass, uranium): | ||
| 6 | self.mass = mass | 7 | self.mass = mass | ||
| 7 | self.uranium = uranium | 8 | self.uranium = uranium | ||
| 8 | 9 | ||||
| 9 | def get_uranium_quantity(self): | 10 | def get_uranium_quantity(self): | ||
| 10 | """Return the quantity of uranium in grams.""" | 11 | """Return the quantity of uranium in grams.""" | ||
| 11 | return self.mass * self.uranium | 12 | return self.mass * self.uranium | ||
| 12 | 13 | ||||
| 13 | def get_mass(self): | 14 | def get_mass(self): | ||
| 14 | return self.mass | 15 | return self.mass | ||
| 15 | 16 | ||||
| 16 | 17 | ||||
| 17 | class Person: | 18 | class Person: | ||
| n | n | 19 | |||
| 18 | def __init__(self, position): | 20 | def __init__(self, position): | ||
| 19 | self.position = position | 21 | self.position = position | ||
| 20 | 22 | ||||
| 21 | def get_position(self): | 23 | def get_position(self): | ||
| 22 | return self.position | 24 | return self.position | ||
| 23 | 25 | ||||
| 24 | def set_position(self, position): | 26 | def set_position(self, position): | ||
| 25 | self.position = position | 27 | self.position = position | ||
| 26 | 28 | ||||
| 27 | @staticmethod | 29 | @staticmethod | ||
| 28 | def get_distance(person_1, person_2): | 30 | def get_distance(person_1, person_2): | ||
| n | 29 | """This function calculates the distance between two people.""" | n | 31 | """Calculate the distance between two people.""" |
| 30 | dx = person_1.position[0] - person_2.position[0] | 32 | dx = person_1.position[0] - person_2.position[0] | ||
| 31 | dy = person_1.position[1] - person_2.position[1] | 33 | dy = person_1.position[1] - person_2.position[1] | ||
| 32 | return math.sqrt(dx ** 2 + dy ** 2) | 34 | return math.sqrt(dx ** 2 + dy ** 2) | ||
| 33 | 35 | ||||
| 34 | 36 | ||||
| 35 | class Kid(Person): | 37 | class Kid(Person): | ||
| n | n | 38 | |||
| 39 | CRITICAL_MASS = 20 | ||||
| 40 | |||||
| 36 | def __init__(self, position, initiative): | 41 | def __init__(self, position, initiative): | ||
| 37 | super().__init__(position) | 42 | super().__init__(position) | ||
| 38 | self.initiative = initiative | 43 | self.initiative = initiative | ||
| 39 | self.basket = list() | 44 | self.basket = list() | ||
| 40 | 45 | ||||
| 41 | def get_initiative(self): | 46 | def get_initiative(self): | ||
| 42 | return self.initiative | 47 | return self.initiative | ||
| 43 | 48 | ||||
| 44 | def add_candy(self, candy_to_add): | 49 | def add_candy(self, candy_to_add): | ||
| 45 | self.basket.append(candy_to_add) | 50 | self.basket.append(candy_to_add) | ||
| 46 | 51 | ||||
| 47 | def is_critical(self): | 52 | def is_critical(self): | ||
| n | 48 | """This function sums the uranium contents of all candies and returns true if sum > 20.""" | n | 53 | """Sum the uranium contents of all candies and returns true if sum > 20.""" |
| 49 | uranium_sum = 0.0 | 54 | uranium_sum = sum(candy.get_uranium_quantity() for candy in self.basket) | ||
| 50 | for candy in self.basket: | ||||
| 51 | uranium_sum += candy.get_uranium_quantity() | ||||
| 52 | return uranium_sum > 20 | 55 | return uranium_sum > Kid.CRITICAL_MASS | ||
| 53 | 56 | ||||
| 54 | 57 | ||||
| 55 | class Host(Person): | 58 | class Host(Person): | ||
| n | n | 59 | |||
| 56 | def __init__(self, position, candies): | 60 | def __init__(self, position, candies): | ||
| 57 | super().__init__(position) | 61 | super().__init__(position) | ||
| 58 | self.candies = [Candy(x, y) for x, y in candies] | 62 | self.candies = [Candy(x, y) for x, y in candies] | ||
| 59 | self.visited_from = [] # add children that already visited a given host here | 63 | self.visited_from = [] # add children that already visited a given host here | ||
| 60 | self.current_visitors = [] # add children that are visiting the host at the moment | 64 | self.current_visitors = [] # add children that are visiting the host at the moment | ||
| 61 | 65 | ||||
| 62 | def remove_candy(self, func_remove_candy): | 66 | def remove_candy(self, func_remove_candy): | ||
| 63 | # if the host doesn't have candy, do nothing | 67 | # if the host doesn't have candy, do nothing | ||
| 64 | if not self.candies: | 68 | if not self.candies: | ||
| 65 | return None | 69 | return None | ||
| 66 | # save the candy to delete from the list | 70 | # save the candy to delete from the list | ||
| 67 | candy_to_remove = func_remove_candy(self.candies) | 71 | candy_to_remove = func_remove_candy(self.candies) | ||
| 68 | self.candies.remove(candy_to_remove) | 72 | self.candies.remove(candy_to_remove) | ||
| 69 | return candy_to_remove | 73 | return candy_to_remove | ||
| 70 | 74 | ||||
| 71 | 75 | ||||
| n | 72 | def find_candy_with_biggest_mass(candies): | n | 76 | class FluxCapacitor: |
| 73 | return max(candies, key=lambda some_candy: some_candy.mass) | ||||
| 74 | 77 | ||||
| n | n | 78 | def __init__(self, participants): | ||
| 79 | self.kids = [person for person in participants if type(person) == Kid] | ||||
| 80 | self.hosts = [person for person in participants if type(person) == Host] | ||||
| 75 | 81 | ||||
| n | 76 | class FluxCapacitor: | n | 82 | @staticmethod |
| 77 | def __init__(self, participants): | 83 | def find_candy_with_biggest_mass(candies): | ||
| 78 | self.participants = participants | 84 | return max(candies, key=lambda some_candy: some_candy.mass) | ||
| 79 | 85 | ||||
| 80 | def get_victim(self): | 86 | def get_victim(self): | ||
| n | 81 | kids = [person for person in self.participants if type(person) == Kid] | n | ||
| 82 | hosts = [person for person in self.participants if type(person) == Host] | ||||
| 83 | |||||
| 84 | while True: | 87 | while True: | ||
| n | 85 | all_kids_visited_all_hosts = all(len(host.visited_from) == len(kids) for host in hosts) | n | 88 | all_kids_visited_all_hosts = all(len(host.visited_from) == len(self.kids) for host in self.hosts) |
| 86 | if all_kids_visited_all_hosts: | 89 | if all_kids_visited_all_hosts: | ||
| 87 | break | 90 | break | ||
| 88 | 91 | ||||
| 89 | # first, determine for each kid which house it's going to visit | 92 | # first, determine for each kid which house it's going to visit | ||
| n | 90 | for kid in kids: | n | 93 | for kid in self.kids: |
| 91 | try: | 94 | try: | ||
| n | 92 | closest_unvisited_house = min([host for host in hosts if kid not in host.visited_from], | n | 95 | closest_unvisited_house = min([host for host in self.hosts if kid not in host.visited_from], |
| 93 | key=lambda host: ( | 96 | key=lambda host: ( | ||
| 94 | Person.get_distance(kid, host), host.position[0], | 97 | Person.get_distance(kid, host), host.position[0], | ||
| 95 | host.position[1])) | 98 | host.position[1])) | ||
| n | 96 | # ValueError will be thrown if the iterable is empty (there are no unvisited hosts for the current kid) | n | 99 | # ValueError will be thrown if the iterable is empty (there are no unvisited self.hosts for the current kid) |
| 97 | except ValueError: | 100 | except ValueError: | ||
| n | 98 | break | n | 101 | continue |
| 99 | 102 | ||||
| 100 | # mark the closest_unvisited_house as being actively visited by the respective kid | 103 | # mark the closest_unvisited_house as being actively visited by the respective kid | ||
| 101 | closest_unvisited_house.current_visitors.append(kid) | 104 | closest_unvisited_house.current_visitors.append(kid) | ||
| 102 | # the kid moves to the closest house, so change its coordinates | 105 | # the kid moves to the closest house, so change its coordinates | ||
| 103 | kid.set_position(closest_unvisited_house.position) | 106 | kid.set_position(closest_unvisited_house.position) | ||
| 104 | 107 | ||||
| n | 105 | # secondly, make the hosts distribute the candy | n | 108 | # secondly, make the self.hosts distribute the candy |
| 106 | for host in hosts: | 109 | for host in self.hosts: | ||
| 107 | while host.current_visitors: # aim to empty the active visitors list | 110 | while host.current_visitors: # aim to empty the active visitors list | ||
| 108 | # if the host doesn't have candy, remove all current visitors | 111 | # if the host doesn't have candy, remove all current visitors | ||
| 109 | # and add them to the list of past visitors | 112 | # and add them to the list of past visitors | ||
| 110 | if not host.candies: | 113 | if not host.candies: | ||
| 111 | host.visited_from += host.current_visitors | 114 | host.visited_from += host.current_visitors | ||
| 112 | host.current_visitors = [] | 115 | host.current_visitors = [] | ||
| 113 | break | 116 | break | ||
| 114 | 117 | ||||
| 115 | # determine the next kid by comparing initiatives | 118 | # determine the next kid by comparing initiatives | ||
| 116 | next_kid = max(host.current_visitors, key=lambda some_kid: some_kid.initiative) | 119 | next_kid = max(host.current_visitors, key=lambda some_kid: some_kid.initiative) | ||
| 117 | # find candy for the next kid | 120 | # find candy for the next kid | ||
| n | 118 | next_candy = host.remove_candy(find_candy_with_biggest_mass) | n | 121 | next_candy = host.remove_candy(FluxCapacitor.find_candy_with_biggest_mass) |
| 119 | # add candy to kid's basket | 122 | # add candy to kid's basket | ||
| 120 | next_kid.add_candy(next_candy) | 123 | next_kid.add_candy(next_candy) | ||
| 121 | # save the kid in the list of past visitors and remove it from active visitors | 124 | # save the kid in the list of past visitors and remove it from active visitors | ||
| 122 | host.visited_from.append(next_kid) | 125 | host.visited_from.append(next_kid) | ||
| 123 | host.current_visitors.remove(next_kid) | 126 | host.current_visitors.remove(next_kid) | ||
| 124 | 127 | ||||
| 125 | # the last step is to add all children that have received critical mass to a set | 128 | # the last step is to add all children that have received critical mass to a set | ||
| 126 | irridated_kids = set() | 129 | irridated_kids = set() | ||
| t | 127 | for kid in kids: | t | 130 | for kid in self.kids: |
| 128 | if kid.is_critical(): | 131 | if kid.is_critical(): | ||
| 129 | irridated_kids.add(kid) | 132 | irridated_kids.add(kid) | ||
| 130 | if irridated_kids: | 133 | if irridated_kids: | ||
| 131 | return irridated_kids | 134 | return irridated_kids | ||
| 132 | 135 | ||||
| 133 | return None | 136 | return None |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import math | f | 1 | import math |
| 2 | 2 | ||||
| 3 | 3 | ||||
| 4 | class Candy: | 4 | class Candy: | ||
| 5 | def __init__(self, mass, uranium): | 5 | def __init__(self, mass, uranium): | ||
| 6 | self.mass = mass | 6 | self.mass = mass | ||
| 7 | self.uranium = uranium | 7 | self.uranium = uranium | ||
| 8 | 8 | ||||
| 9 | def get_uranium_quantity(self): | 9 | def get_uranium_quantity(self): | ||
| 10 | """Return the quantity of uranium in grams.""" | 10 | """Return the quantity of uranium in grams.""" | ||
| 11 | return self.mass * self.uranium | 11 | return self.mass * self.uranium | ||
| 12 | 12 | ||||
| 13 | def get_mass(self): | 13 | def get_mass(self): | ||
| 14 | return self.mass | 14 | return self.mass | ||
| 15 | 15 | ||||
| 16 | 16 | ||||
| 17 | class Person: | 17 | class Person: | ||
| 18 | def __init__(self, position): | 18 | def __init__(self, position): | ||
| 19 | self.position = position | 19 | self.position = position | ||
| 20 | 20 | ||||
| 21 | def get_position(self): | 21 | def get_position(self): | ||
| 22 | return self.position | 22 | return self.position | ||
| 23 | 23 | ||||
| 24 | def set_position(self, position): | 24 | def set_position(self, position): | ||
| 25 | self.position = position | 25 | self.position = position | ||
| 26 | 26 | ||||
| 27 | @staticmethod | 27 | @staticmethod | ||
| 28 | def get_distance(person_1, person_2): | 28 | def get_distance(person_1, person_2): | ||
| 29 | """This function calculates the distance between two people.""" | 29 | """This function calculates the distance between two people.""" | ||
| 30 | dx = person_1.position[0] - person_2.position[0] | 30 | dx = person_1.position[0] - person_2.position[0] | ||
| 31 | dy = person_1.position[1] - person_2.position[1] | 31 | dy = person_1.position[1] - person_2.position[1] | ||
| 32 | return math.sqrt(dx ** 2 + dy ** 2) | 32 | return math.sqrt(dx ** 2 + dy ** 2) | ||
| 33 | 33 | ||||
| 34 | 34 | ||||
| 35 | class Kid(Person): | 35 | class Kid(Person): | ||
| 36 | def __init__(self, position, initiative): | 36 | def __init__(self, position, initiative): | ||
| 37 | super().__init__(position) | 37 | super().__init__(position) | ||
| 38 | self.initiative = initiative | 38 | self.initiative = initiative | ||
| 39 | self.basket = list() | 39 | self.basket = list() | ||
| 40 | 40 | ||||
| 41 | def get_initiative(self): | 41 | def get_initiative(self): | ||
| 42 | return self.initiative | 42 | return self.initiative | ||
| 43 | 43 | ||||
| 44 | def add_candy(self, candy_to_add): | 44 | def add_candy(self, candy_to_add): | ||
| 45 | self.basket.append(candy_to_add) | 45 | self.basket.append(candy_to_add) | ||
| 46 | 46 | ||||
| 47 | def is_critical(self): | 47 | def is_critical(self): | ||
| 48 | """This function sums the uranium contents of all candies and returns true if sum > 20.""" | 48 | """This function sums the uranium contents of all candies and returns true if sum > 20.""" | ||
| 49 | uranium_sum = 0.0 | 49 | uranium_sum = 0.0 | ||
| 50 | for candy in self.basket: | 50 | for candy in self.basket: | ||
| 51 | uranium_sum += candy.get_uranium_quantity() | 51 | uranium_sum += candy.get_uranium_quantity() | ||
| 52 | return uranium_sum > 20 | 52 | return uranium_sum > 20 | ||
| 53 | 53 | ||||
| 54 | 54 | ||||
| 55 | class Host(Person): | 55 | class Host(Person): | ||
| 56 | def __init__(self, position, candies): | 56 | def __init__(self, position, candies): | ||
| 57 | super().__init__(position) | 57 | super().__init__(position) | ||
| 58 | self.candies = [Candy(x, y) for x, y in candies] | 58 | self.candies = [Candy(x, y) for x, y in candies] | ||
| 59 | self.visited_from = [] # add children that already visited a given host here | 59 | self.visited_from = [] # add children that already visited a given host here | ||
| 60 | self.current_visitors = [] # add children that are visiting the host at the moment | 60 | self.current_visitors = [] # add children that are visiting the host at the moment | ||
| 61 | 61 | ||||
| 62 | def remove_candy(self, func_remove_candy): | 62 | def remove_candy(self, func_remove_candy): | ||
| 63 | # if the host doesn't have candy, do nothing | 63 | # if the host doesn't have candy, do nothing | ||
| 64 | if not self.candies: | 64 | if not self.candies: | ||
| 65 | return None | 65 | return None | ||
| 66 | # save the candy to delete from the list | 66 | # save the candy to delete from the list | ||
| 67 | candy_to_remove = func_remove_candy(self.candies) | 67 | candy_to_remove = func_remove_candy(self.candies) | ||
| 68 | self.candies.remove(candy_to_remove) | 68 | self.candies.remove(candy_to_remove) | ||
| 69 | return candy_to_remove | 69 | return candy_to_remove | ||
| 70 | 70 | ||||
| 71 | 71 | ||||
| 72 | def find_candy_with_biggest_mass(candies): | 72 | def find_candy_with_biggest_mass(candies): | ||
| 73 | return max(candies, key=lambda some_candy: some_candy.mass) | 73 | return max(candies, key=lambda some_candy: some_candy.mass) | ||
| 74 | 74 | ||||
| 75 | 75 | ||||
| 76 | class FluxCapacitor: | 76 | class FluxCapacitor: | ||
| 77 | def __init__(self, participants): | 77 | def __init__(self, participants): | ||
| 78 | self.participants = participants | 78 | self.participants = participants | ||
| 79 | 79 | ||||
| 80 | def get_victim(self): | 80 | def get_victim(self): | ||
| 81 | kids = [person for person in self.participants if type(person) == Kid] | 81 | kids = [person for person in self.participants if type(person) == Kid] | ||
| 82 | hosts = [person for person in self.participants if type(person) == Host] | 82 | hosts = [person for person in self.participants if type(person) == Host] | ||
| 83 | 83 | ||||
| n | 84 | children_visited_all_hosts = False | n | ||
| 85 | while True: | 84 | while True: | ||
| n | n | 85 | all_kids_visited_all_hosts = all(len(host.visited_from) == len(kids) for host in hosts) | ||
| 86 | if all_kids_visited_all_hosts: | ||||
| 87 | break | ||||
| 88 | |||||
| 86 | # first, determine for each kid which house it's going to visit | 89 | # first, determine for each kid which house it's going to visit | ||
| 87 | for kid in kids: | 90 | for kid in kids: | ||
| 88 | try: | 91 | try: | ||
| 89 | closest_unvisited_house = min([host for host in hosts if kid not in host.visited_from], | 92 | closest_unvisited_house = min([host for host in hosts if kid not in host.visited_from], | ||
| 90 | key=lambda host: ( | 93 | key=lambda host: ( | ||
| 91 | Person.get_distance(kid, host), host.position[0], | 94 | Person.get_distance(kid, host), host.position[0], | ||
| 92 | host.position[1])) | 95 | host.position[1])) | ||
| 93 | # ValueError will be thrown if the iterable is empty (there are no unvisited hosts for the current kid) | 96 | # ValueError will be thrown if the iterable is empty (there are no unvisited hosts for the current kid) | ||
| 94 | except ValueError: | 97 | except ValueError: | ||
| n | 95 | children_visited_all_hosts = True | n | ||
| 96 | break | 98 | break | ||
| 97 | 99 | ||||
| 98 | # mark the closest_unvisited_house as being actively visited by the respective kid | 100 | # mark the closest_unvisited_house as being actively visited by the respective kid | ||
| 99 | closest_unvisited_house.current_visitors.append(kid) | 101 | closest_unvisited_house.current_visitors.append(kid) | ||
| 100 | # the kid moves to the closest house, so change its coordinates | 102 | # the kid moves to the closest house, so change its coordinates | ||
| 101 | kid.set_position(closest_unvisited_house.position) | 103 | kid.set_position(closest_unvisited_house.position) | ||
| t | 102 | t | |||
| 103 | # this line of code will break from the main loop if all hosts were visited | ||||
| 104 | if children_visited_all_hosts: | ||||
| 105 | break | ||||
| 106 | 104 | ||||
| 107 | # secondly, make the hosts distribute the candy | 105 | # secondly, make the hosts distribute the candy | ||
| 108 | for host in hosts: | 106 | for host in hosts: | ||
| 109 | while host.current_visitors: # aim to empty the active visitors list | 107 | while host.current_visitors: # aim to empty the active visitors list | ||
| 110 | # if the host doesn't have candy, remove all current visitors | 108 | # if the host doesn't have candy, remove all current visitors | ||
| 111 | # and add them to the list of past visitors | 109 | # and add them to the list of past visitors | ||
| 112 | if not host.candies: | 110 | if not host.candies: | ||
| 113 | host.visited_from += host.current_visitors | 111 | host.visited_from += host.current_visitors | ||
| 114 | host.current_visitors = [] | 112 | host.current_visitors = [] | ||
| 115 | break | 113 | break | ||
| 116 | 114 | ||||
| 117 | # determine the next kid by comparing initiatives | 115 | # determine the next kid by comparing initiatives | ||
| 118 | next_kid = max(host.current_visitors, key=lambda some_kid: some_kid.initiative) | 116 | next_kid = max(host.current_visitors, key=lambda some_kid: some_kid.initiative) | ||
| 119 | # find candy for the next kid | 117 | # find candy for the next kid | ||
| 120 | next_candy = host.remove_candy(find_candy_with_biggest_mass) | 118 | next_candy = host.remove_candy(find_candy_with_biggest_mass) | ||
| 121 | # add candy to kid's basket | 119 | # add candy to kid's basket | ||
| 122 | next_kid.add_candy(next_candy) | 120 | next_kid.add_candy(next_candy) | ||
| 123 | # save the kid in the list of past visitors and remove it from active visitors | 121 | # save the kid in the list of past visitors and remove it from active visitors | ||
| 124 | host.visited_from.append(next_kid) | 122 | host.visited_from.append(next_kid) | ||
| 125 | host.current_visitors.remove(next_kid) | 123 | host.current_visitors.remove(next_kid) | ||
| 126 | 124 | ||||
| 127 | # the last step is to add all children that have received critical mass to a set | 125 | # the last step is to add all children that have received critical mass to a set | ||
| 128 | irridated_kids = set() | 126 | irridated_kids = set() | ||
| 129 | for kid in kids: | 127 | for kid in kids: | ||
| 130 | if kid.is_critical(): | 128 | if kid.is_critical(): | ||
| 131 | irridated_kids.add(kid) | 129 | irridated_kids.add(kid) | ||
| 132 | if irridated_kids: | 130 | if irridated_kids: | ||
| 133 | return irridated_kids | 131 | return irridated_kids | ||
| 134 | 132 | ||||
| 135 | return None | 133 | return None |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||