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 self.uranium * self.mass
12
13 def get_mass(self):
14 return self.mass
15
16
17class Person:
18
19 def __init__(self, position):
20 self.position = position
21 self.id = position
22
23 def get_position(self):
24 return self.position
25
26 def set_position(self, position):
27 self.position = position
28
29
30class Kid(Person):
31
32 MAX_URANIUM = 20
33
34 def __init__(self, position, initiative):
35 self.basket = []
36 super().__init__(position)
37 self.initiative = initiative
38
39 def get_initiative(self):
40 return self.initiative
41
42 def add_candy(self, candy):
43 self.basket.append(candy)
44
45 def is_critical(self):
46 uranium = 0
47 for candy in self.basket:
48 uranium += candy.get_uranium_quantity()
49 return uranium > self.MAX_URANIUM
50
51
52class Host(Person):
53
54 def __init__(self, position, candies):
55 super().__init__(position)
56 self.candies = candies.copy()
57
58 def remove_candy(self, choose_candy):
59 if not self.candies:
60 return None
61 candy = choose_candy(self.candies)
62 self.candies.remove(candy)
63 return candy
64
65
66def fancy_get_closest_host(kid, hosts):
67 return min([(math.dist(kid.position, host.position), host.position[0], host.position[1], host) for host in hosts])[-1]
68
69
70class FluxCapacitor:
71
72 def __init__(self, participants):
73 self.all_kids = []
74 self.all_hosts = []
75 for person in participants:
76 if type(person) is Kid:
77 self.all_kids.append(person)
78 else:
79 self.all_hosts.append(person)
80
81 @staticmethod
82 def choose_heaviest_candy(candies):
83 heaviest_candy = Candy(0, 0)
84 for candy in candies:
85 if heaviest_candy.mass < candy.mass:
86 heaviest_candy = candy
87 return heaviest_candy
88
89 def __check_for_victims(self):
90 dead_kids = set()
91 for kid in self.all_kids:
92 if kid.is_critical():
93 dead_kids.add(kid)
94 return dead_kids
95
96 def get_victims(self):
97 if not self.all_kids:
98 return None
99
100 hosts_to_visit = []
101 for kid in self.all_kids:
102 hosts_to_visit.append([kid, []])
103 for host in self.all_hosts:
104 hosts_to_visit[-1][1].append(host)
105 hosts_to_visit.sort(reverse=True, key=(lambda x: x[0].initiative))
106
107 while not (dead_kids := self.__check_for_victims()):
108 for kid_and_hosts in hosts_to_visit:
109 kid = kid_and_hosts[0]
110 hosts = kid_and_hosts[1]
111 if not hosts:
112 return None
113 closest_host = fancy_get_closest_host(kid, hosts)
114 hosts.remove(closest_host)
115 kid.position = closest_host.position
116 if (candy := closest_host.remove_candy(FluxCapacitor.choose_heaviest_candy)):
117 kid.add_candy(candy)
118
119 if not dead_kids:
120 return None
121 return dead_kids
122
.EEEEEE.....
======================================================================
ERROR: test_empty (test.FluxCapacitorTest)
Test with empty collection.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/timeout_decorator/timeout_decorator.py", line 82, in new_function
return function(*args, **kwargs)
File "/tmp/test.py", line 80, in test_empty
self.assertEqual(flux_capacitor.get_victim(), None)
AttributeError: 'FluxCapacitor' object has no attribute 'get_victim'
======================================================================
ERROR: test_empty_hosts (test.FluxCapacitorTest)
Test with empty hosts.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/timeout_decorator/timeout_decorator.py", line 82, in new_function
return function(*args, **kwargs)
File "/tmp/test.py", line 88, in test_empty_hosts
self.assertEqual(flux_capacitor.get_victim(), None)
AttributeError: 'FluxCapacitor' object has no attribute 'get_victim'
======================================================================
ERROR: test_empty_kids (test.FluxCapacitorTest)
Test with empty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/timeout_decorator/timeout_decorator.py", line 82, in new_function
return function(*args, **kwargs)
File "/tmp/test.py", line 96, in test_empty_kids
self.assertEqual(flux_capacitor.get_victim(), None)
AttributeError: 'FluxCapacitor' object has no attribute 'get_victim'
======================================================================
ERROR: test_no_candies (test.FluxCapacitorTest)
Test with no candies.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/timeout_decorator/timeout_decorator.py", line 82, in new_function
return function(*args, **kwargs)
File "/tmp/test.py", line 106, in test_no_candies
self.assertEqual(flux_capacitor.get_victim(), None)
AttributeError: 'FluxCapacitor' object has no attribute 'get_victim'
======================================================================
ERROR: test_real_case (test.FluxCapacitorTest)
Test with real case.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/timeout_decorator/timeout_decorator.py", line 82, in new_function
return function(*args, **kwargs)
File "/tmp/test.py", line 115, in test_real_case
self.assertEqual(FluxCapacitor({kid1, kid2, host1, host2}).get_victim(), {kid1, kid2})
AttributeError: 'FluxCapacitor' object has no attribute 'get_victim'
======================================================================
ERROR: test_basic_usage (test.HostTest)
Test basic usage of Host class.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 65, in test_basic_usage
candy = host.remove_candy(compare_fun)
File "/tmp/solution.py", line 62, in remove_candy
candy = choose_candy(self.candies)
File "/tmp/test.py", line 63, in <lambda>
compare_fun = lambda candies: min(candies, key=lambda candy: candy.get_mass())
File "/tmp/test.py", line 63, in <lambda>
compare_fun = lambda candies: min(candies, key=lambda candy: candy.get_mass())
AttributeError: 'tuple' object has no attribute 'get_mass'
----------------------------------------------------------------------
Ran 12 tests in 0.001s
FAILED (errors=6)
f | 1 | f | 1 | ||
2 | import math | 2 | import math | ||
3 | 3 | ||||
4 | 4 | ||||
5 | class Candy: | 5 | class Candy: | ||
6 | 6 | ||||
7 | def __init__(self, mass, uranium): | 7 | def __init__(self, mass, uranium): | ||
8 | self.mass = mass | 8 | self.mass = mass | ||
9 | self.uranium = uranium | 9 | self.uranium = uranium | ||
10 | 10 | ||||
11 | def get_uranium_quantity(self): | 11 | def get_uranium_quantity(self): | ||
12 | return self.uranium * self.mass | 12 | return self.uranium * self.mass | ||
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 | self.id = position | 22 | self.id = position | ||
23 | 23 | ||||
24 | def get_position(self): | 24 | def get_position(self): | ||
25 | return self.position | 25 | return self.position | ||
26 | 26 | ||||
27 | def set_position(self, position): | 27 | def set_position(self, position): | ||
28 | self.position = position | 28 | self.position = position | ||
29 | 29 | ||||
30 | 30 | ||||
31 | class Kid(Person): | 31 | class Kid(Person): | ||
32 | 32 | ||||
33 | MAX_URANIUM = 20 | 33 | MAX_URANIUM = 20 | ||
34 | 34 | ||||
35 | def __init__(self, position, initiative): | 35 | def __init__(self, position, initiative): | ||
36 | self.basket = [] | 36 | self.basket = [] | ||
37 | super().__init__(position) | 37 | super().__init__(position) | ||
38 | self.initiative = initiative | 38 | self.initiative = initiative | ||
39 | 39 | ||||
40 | def get_initiative(self): | 40 | def get_initiative(self): | ||
41 | return self.initiative | 41 | return self.initiative | ||
42 | 42 | ||||
43 | def add_candy(self, candy): | 43 | def add_candy(self, candy): | ||
44 | self.basket.append(candy) | 44 | self.basket.append(candy) | ||
45 | 45 | ||||
46 | def is_critical(self): | 46 | def is_critical(self): | ||
47 | uranium = 0 | 47 | uranium = 0 | ||
48 | for candy in self.basket: | 48 | for candy in self.basket: | ||
49 | uranium += candy.get_uranium_quantity() | 49 | uranium += candy.get_uranium_quantity() | ||
50 | return uranium > self.MAX_URANIUM | 50 | return uranium > self.MAX_URANIUM | ||
51 | 51 | ||||
52 | 52 | ||||
53 | class Host(Person): | 53 | class Host(Person): | ||
54 | 54 | ||||
55 | def __init__(self, position, candies): | 55 | def __init__(self, position, candies): | ||
56 | super().__init__(position) | 56 | super().__init__(position) | ||
57 | self.candies = candies.copy() | 57 | self.candies = candies.copy() | ||
58 | 58 | ||||
59 | def remove_candy(self, choose_candy): | 59 | def remove_candy(self, choose_candy): | ||
60 | if not self.candies: | 60 | if not self.candies: | ||
61 | return None | 61 | return None | ||
62 | candy = choose_candy(self.candies) | 62 | candy = choose_candy(self.candies) | ||
63 | self.candies.remove(candy) | 63 | self.candies.remove(candy) | ||
64 | return candy | 64 | return candy | ||
65 | 65 | ||||
66 | 66 | ||||
n | 67 | class CandyChooser: | n | ||
68 | |||||
69 | @staticmethod | ||||
70 | def choose_heaviest_candy(candies): | ||||
71 | heaviest_candy = Candy(0, 0) | ||||
72 | for candy in candies: | ||||
73 | if heaviest_candy.mass < candy.mass: | ||||
74 | heaviest_candy = candy | ||||
75 | return heaviest_candy | ||||
76 | |||||
77 | |||||
78 | def fancy_get_closest_host(kid, hosts): | 67 | def fancy_get_closest_host(kid, hosts): | ||
79 | return min([(math.dist(kid.position, host.position), host.position[0], host.position[1], host) for host in hosts])[-1] | 68 | return min([(math.dist(kid.position, host.position), host.position[0], host.position[1], host) for host in hosts])[-1] | ||
80 | 69 | ||||
81 | 70 | ||||
82 | class FluxCapacitor: | 71 | class FluxCapacitor: | ||
83 | 72 | ||||
84 | def __init__(self, participants): | 73 | def __init__(self, participants): | ||
85 | self.all_kids = [] | 74 | self.all_kids = [] | ||
86 | self.all_hosts = [] | 75 | self.all_hosts = [] | ||
87 | for person in participants: | 76 | for person in participants: | ||
88 | if type(person) is Kid: | 77 | if type(person) is Kid: | ||
89 | self.all_kids.append(person) | 78 | self.all_kids.append(person) | ||
90 | else: | 79 | else: | ||
91 | self.all_hosts.append(person) | 80 | self.all_hosts.append(person) | ||
92 | 81 | ||||
n | n | 82 | @staticmethod | ||
83 | def choose_heaviest_candy(candies): | ||||
84 | heaviest_candy = Candy(0, 0) | ||||
85 | for candy in candies: | ||||
86 | if heaviest_candy.mass < candy.mass: | ||||
87 | heaviest_candy = candy | ||||
88 | return heaviest_candy | ||||
89 | |||||
93 | def __check_for_victims(self): | 90 | def __check_for_victims(self): | ||
94 | dead_kids = set() | 91 | dead_kids = set() | ||
95 | for kid in self.all_kids: | 92 | for kid in self.all_kids: | ||
96 | if kid.is_critical(): | 93 | if kid.is_critical(): | ||
97 | dead_kids.add(kid) | 94 | dead_kids.add(kid) | ||
98 | return dead_kids | 95 | return dead_kids | ||
99 | 96 | ||||
100 | def get_victims(self): | 97 | def get_victims(self): | ||
n | n | 98 | if not self.all_kids: | ||
99 | return None | ||||
100 | |||||
101 | hosts_to_visit = [] | 101 | hosts_to_visit = [] | ||
102 | for kid in self.all_kids: | 102 | for kid in self.all_kids: | ||
103 | hosts_to_visit.append([kid, []]) | 103 | hosts_to_visit.append([kid, []]) | ||
104 | for host in self.all_hosts: | 104 | for host in self.all_hosts: | ||
105 | hosts_to_visit[-1][1].append(host) | 105 | hosts_to_visit[-1][1].append(host) | ||
106 | hosts_to_visit.sort(reverse=True, key=(lambda x: x[0].initiative)) | 106 | hosts_to_visit.sort(reverse=True, key=(lambda x: x[0].initiative)) | ||
107 | 107 | ||||
108 | while not (dead_kids := self.__check_for_victims()): | 108 | while not (dead_kids := self.__check_for_victims()): | ||
109 | for kid_and_hosts in hosts_to_visit: | 109 | for kid_and_hosts in hosts_to_visit: | ||
110 | kid = kid_and_hosts[0] | 110 | kid = kid_and_hosts[0] | ||
111 | hosts = kid_and_hosts[1] | 111 | hosts = kid_and_hosts[1] | ||
112 | if not hosts: | 112 | if not hosts: | ||
113 | return None | 113 | return None | ||
114 | closest_host = fancy_get_closest_host(kid, hosts) | 114 | closest_host = fancy_get_closest_host(kid, hosts) | ||
115 | hosts.remove(closest_host) | 115 | hosts.remove(closest_host) | ||
116 | kid.position = closest_host.position | 116 | kid.position = closest_host.position | ||
n | 117 | if (candy := closest_host.remove_candy(CandyChooser.choose_heaviest_candy)): | n | 117 | if (candy := closest_host.remove_candy(FluxCapacitor.choose_heaviest_candy)): |
118 | kid.add_candy(candy) | 118 | kid.add_candy(candy) | ||
119 | 119 | ||||
120 | if not dead_kids: | 120 | if not dead_kids: | ||
121 | return None | 121 | return None | ||
122 | return dead_kids | 122 | return dead_kids | ||
123 | 123 | ||||
t | 124 | t |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
n | n | 1 | |||
2 | import math | ||||
3 | |||||
4 | |||||
1 | class Candy: | 5 | class Candy: | ||
2 | 6 | ||||
3 | def __init__(self, mass, uranium): | 7 | def __init__(self, mass, uranium): | ||
4 | self.mass = mass | 8 | self.mass = mass | ||
5 | self.uranium = uranium | 9 | self.uranium = uranium | ||
6 | 10 | ||||
7 | def get_uranium_quantity(self): | 11 | def get_uranium_quantity(self): | ||
8 | return self.uranium * self.mass | 12 | return self.uranium * self.mass | ||
9 | 13 | ||||
10 | def get_mass(self): | 14 | def get_mass(self): | ||
11 | return self.mass | 15 | return self.mass | ||
12 | 16 | ||||
13 | 17 | ||||
14 | class Person: | 18 | class Person: | ||
15 | 19 | ||||
16 | def __init__(self, position): | 20 | def __init__(self, position): | ||
17 | self.position = position | 21 | self.position = position | ||
18 | self.id = position | 22 | self.id = position | ||
19 | 23 | ||||
20 | def get_position(self): | 24 | def get_position(self): | ||
21 | return self.position | 25 | return self.position | ||
22 | 26 | ||||
23 | def set_position(self, position): | 27 | def set_position(self, position): | ||
24 | self.position = position | 28 | self.position = position | ||
25 | 29 | ||||
26 | 30 | ||||
27 | class Kid(Person): | 31 | class Kid(Person): | ||
28 | 32 | ||||
29 | MAX_URANIUM = 20 | 33 | MAX_URANIUM = 20 | ||
30 | 34 | ||||
31 | def __init__(self, position, initiative): | 35 | def __init__(self, position, initiative): | ||
32 | self.basket = [] | 36 | self.basket = [] | ||
33 | super().__init__(position) | 37 | super().__init__(position) | ||
34 | self.initiative = initiative | 38 | self.initiative = initiative | ||
35 | 39 | ||||
36 | def get_initiative(self): | 40 | def get_initiative(self): | ||
37 | return self.initiative | 41 | return self.initiative | ||
38 | 42 | ||||
39 | def add_candy(self, candy): | 43 | def add_candy(self, candy): | ||
40 | self.basket.append(candy) | 44 | self.basket.append(candy) | ||
41 | 45 | ||||
42 | def is_critical(self): | 46 | def is_critical(self): | ||
43 | uranium = 0 | 47 | uranium = 0 | ||
44 | for candy in self.basket: | 48 | for candy in self.basket: | ||
45 | uranium += candy.get_uranium_quantity() | 49 | uranium += candy.get_uranium_quantity() | ||
46 | return uranium > self.MAX_URANIUM | 50 | return uranium > self.MAX_URANIUM | ||
47 | 51 | ||||
48 | 52 | ||||
49 | class Host(Person): | 53 | class Host(Person): | ||
50 | 54 | ||||
51 | def __init__(self, position, candies): | 55 | def __init__(self, position, candies): | ||
52 | super().__init__(position) | 56 | super().__init__(position) | ||
53 | self.candies = candies.copy() | 57 | self.candies = candies.copy() | ||
54 | 58 | ||||
55 | def remove_candy(self, choose_candy): | 59 | def remove_candy(self, choose_candy): | ||
56 | if not self.candies: | 60 | if not self.candies: | ||
57 | return None | 61 | return None | ||
58 | candy = choose_candy(self.candies) | 62 | candy = choose_candy(self.candies) | ||
59 | self.candies.remove(candy) | 63 | self.candies.remove(candy) | ||
60 | return candy | 64 | return candy | ||
61 | 65 | ||||
62 | 66 | ||||
n | 63 | def choose(candies): | n | 67 | class CandyChooser: |
68 | |||||
69 | @staticmethod | ||||
70 | def choose_heaviest_candy(candies): | ||||
64 | heaviest_candy = Candy(0,0) | 71 | heaviest_candy = Candy(0, 0) | ||
65 | for candy in candies: | 72 | for candy in candies: | ||
66 | if heaviest_candy.mass < candy.mass: | 73 | if heaviest_candy.mass < candy.mass: | ||
67 | heaviest_candy = candy | 74 | heaviest_candy = candy | ||
68 | return heaviest_candy | 75 | return heaviest_candy | ||
69 | 76 | ||||
70 | 77 | ||||
n | 71 | def get_closest_host(kid, hosts): | n | 78 | def fancy_get_closest_host(kid, hosts): |
72 | closest_host_dist = (kid.position[0] - hosts[0].position[0])**2 + (kid.position[1] - hosts[0].position[1])**2 | 79 | return min([(math.dist(kid.position, host.position), host.position[0], host.position[1], host) for host in hosts])[-1] | ||
73 | closest_host = hosts[0] | ||||
74 | for host in hosts: | ||||
75 | # check distance | ||||
76 | dist = (kid.position[0] - host.position[0])**2 + (kid.position[1] - host.position[1])**2 | ||||
77 | if closest_host_dist > dist: | ||||
78 | closest_host_dist = dist | ||||
79 | closest_host = host | ||||
80 | elif closest_host_dist == dist: | ||||
81 | # check x coordinate | ||||
82 | if closest_host.position[0] > host.position[0]: | ||||
83 | closest_host_dist = dist | ||||
84 | closest_host = host | ||||
85 | elif closest_host.position[0] == host.position[0]: | ||||
86 | # check y coordinate | ||||
87 | if closest_host.position[1] > host.position[1]: | ||||
88 | closest_host_dist = dist | ||||
89 | closest_host = host | ||||
90 | return closest_host | ||||
91 | |||||
92 | |||||
93 | def sort_by_initiative(elem): | ||||
94 | return elem[0].initiative | ||||
95 | 80 | ||||
96 | 81 | ||||
97 | class FluxCapacitor: | 82 | class FluxCapacitor: | ||
n | 98 | all_kids = [] | n | ||
99 | all_hosts = [] | ||||
100 | 83 | ||||
101 | def __init__(self, participants): | 84 | def __init__(self, participants): | ||
n | n | 85 | self.all_kids = [] | ||
86 | self.all_hosts = [] | ||||
102 | for person in participants: | 87 | for person in participants: | ||
103 | if type(person) is Kid: | 88 | if type(person) is Kid: | ||
104 | self.all_kids.append(person) | 89 | self.all_kids.append(person) | ||
105 | else: | 90 | else: | ||
106 | self.all_hosts.append(person) | 91 | self.all_hosts.append(person) | ||
107 | 92 | ||||
108 | def __check_for_victims(self): | 93 | def __check_for_victims(self): | ||
109 | dead_kids = set() | 94 | dead_kids = set() | ||
110 | for kid in self.all_kids: | 95 | for kid in self.all_kids: | ||
111 | if kid.is_critical(): | 96 | if kid.is_critical(): | ||
112 | dead_kids.add(kid) | 97 | dead_kids.add(kid) | ||
113 | return dead_kids | 98 | return dead_kids | ||
114 | 99 | ||||
115 | def get_victims(self): | 100 | def get_victims(self): | ||
n | 116 | n | |||
117 | hosts_to_visit = [] | 101 | hosts_to_visit = [] | ||
n | 118 | curr_idx = 0 | n | ||
119 | for kid in self.all_kids: | 102 | for kid in self.all_kids: | ||
120 | hosts_to_visit.append([kid, []]) | 103 | hosts_to_visit.append([kid, []]) | ||
121 | for host in self.all_hosts: | 104 | for host in self.all_hosts: | ||
n | 122 | hosts_to_visit[curr_idx][1].append(host) | n | 105 | hosts_to_visit[-1][1].append(host) |
123 | curr_idx += 1 | ||||
124 | hosts_to_visit.sort(reverse=True, key=sort_by_initiative) | 106 | hosts_to_visit.sort(reverse=True, key=(lambda x: x[0].initiative)) | ||
125 | 107 | ||||
126 | while not (dead_kids := self.__check_for_victims()): | 108 | while not (dead_kids := self.__check_for_victims()): | ||
127 | for kid_and_hosts in hosts_to_visit: | 109 | for kid_and_hosts in hosts_to_visit: | ||
128 | kid = kid_and_hosts[0] | 110 | kid = kid_and_hosts[0] | ||
129 | hosts = kid_and_hosts[1] | 111 | hosts = kid_and_hosts[1] | ||
130 | if not hosts: | 112 | if not hosts: | ||
131 | return None | 113 | return None | ||
n | 132 | closest_host = get_closest_host(kid, hosts) | n | 114 | closest_host = fancy_get_closest_host(kid, hosts) |
133 | hosts.remove(closest_host) | 115 | hosts.remove(closest_host) | ||
134 | kid.position = closest_host.position | 116 | kid.position = closest_host.position | ||
n | 135 | n | |||
136 | if (candy := closest_host.remove_candy(choose)): | 117 | if (candy := closest_host.remove_candy(CandyChooser.choose_heaviest_candy)): | ||
137 | kid.add_candy(candy) | 118 | kid.add_candy(candy) | ||
138 | 119 | ||||
139 | if not dead_kids: | 120 | if not dead_kids: | ||
140 | return None | 121 | return None | ||
141 | return dead_kids | 122 | return dead_kids | ||
t | t | 123 | |||
124 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|