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