f | class Candy: | f | class Candy: |
n | | n | |
| def __init__(self, mass: int, uranium: float): | | def __init__(self, mass: int, uranium: float): |
| self._mass = mass | | self._mass = mass |
| self._uranium = uranium | | self._uranium = uranium |
| | | |
| def get_uranium_quantity(self): | | def get_uranium_quantity(self): |
| return self._mass * self._uranium | | return self._mass * self._uranium |
| | | |
| def get_mass(self): | | def get_mass(self): |
| return self._mass | | return self._mass |
| | | |
| | | |
| class Person: | | class Person: |
n | | n | |
| def __init__(self, position: tuple): | | def __init__(self, position: tuple): |
| self._position = position | | self._position = position |
| | | |
| def get_position(self): | | def get_position(self): |
| return self._position | | return self._position |
| | | |
| def set_position(self, position: tuple): | | def set_position(self, position: tuple): |
| self._position = position | | self._position = position |
| | | |
| | | |
| class Kid(Person): | | class Kid(Person): |
n | | n | |
| _critical_mass = 20 | | _critical_mass = 20 |
| | | |
| def __init__(self, position: tuple, initiative): | | def __init__(self, position: tuple, initiative): |
| super().__init__(position) | | super().__init__(position) |
| self._initiative = initiative | | self._initiative = initiative |
| self._bag = [] | | self._bag = [] |
| | | |
| def get_initiative(self): | | def get_initiative(self): |
| return self._initiative | | return self._initiative |
| | | |
| def add_candy(self, candy: Candy): | | def add_candy(self, candy: Candy): |
| self._bag.append(candy) | | self._bag.append(candy) |
| | | |
| def is_critical(self): | | def is_critical(self): |
| radianion = 0 | | radianion = 0 |
| for candy in self._bag: | | for candy in self._bag: |
| radianion += candy.get_uranium_quantity() | | radianion += candy.get_uranium_quantity() |
| return radianion > self._critical_mass | | return radianion > self._critical_mass |
| | | |
| | | |
| class Host(Person): | | class Host(Person): |
n | | n | |
| def __init__(self, position: tuple, candies: list): | | def __init__(self, position: tuple, candies: list): |
| super().__init__(position) | | super().__init__(position) |
| self._candies = [] | | self._candies = [] |
| for candy in candies: | | for candy in candies: |
n | self._candies.append(Candy(candy[0], candy[1])) | n | self._candies.append(Candy(*candy)) |
| | | |
| def remove_candy(self, candy_criteria): | | def remove_candy(self, candy_criteria): |
| if self._candies: | | if self._candies: |
| selected_candy = candy_criteria(self._candies) | | selected_candy = candy_criteria(self._candies) |
| self._candies.remove(selected_candy) | | self._candies.remove(selected_candy) |
| return selected_candy | | return selected_candy |
| return None | | return None |
| | | |
| | | |
| class FluxCapacitor: | | class FluxCapacitor: |
n | | n | |
| def __init__(self, participants: set): | | def __init__(self, participants: set): |
| self._kids = set() | | self._kids = set() |
| self._hosts = set() | | self._hosts = set() |
| for person in participants: | | for person in participants: |
| if isinstance(person, Kid): | | if isinstance(person, Kid): |
| self._kids.add(person) | | self._kids.add(person) |
| else: | | else: |
| self._hosts.add(person) | | self._hosts.add(person) |
| self._kids = sorted(self._kids, key=lambda kid: kid.get_initiative(), reverse=True) | | self._kids = sorted(self._kids, key=lambda kid: kid.get_initiative(), reverse=True) |
| | | |
| def get_victim(self): | | def get_victim(self): |
| if len(self._hosts) == 0: | | if len(self._hosts) == 0: |
| return None | | return None |
| | | |
| unvisited = {} | | unvisited = {} |
| for kid in self._kids: | | for kid in self._kids: |
| unvisited[kid.get_initiative()] = set() | | unvisited[kid.get_initiative()] = set() |
| for host in self._hosts: | | for host in self._hosts: |
| unvisited[kid.get_initiative()].add(host.get_position()) | | unvisited[kid.get_initiative()].add(host.get_position()) |
| | | |
| while unvisited: | | while unvisited: |
| for kid in self._kids: | | for kid in self._kids: |
n | curr_position = kid.get_position() | n | curr_pos = kid.get_position() |
| next_position = self._closest_host(curr_position, unvisited[kid.get_initiative()]) | | next_pos =FluxCapacitor.closest_host(curr_pos, unvisited[kid.get_initiative()]) |
| kid.set_position(next_position) | | kid.set_position(next_pos) |
| candy: Candy | | |
| for host in self._hosts: | | for host in self._hosts: |
n | if next_position == host.get_position(): | n | if next_pos == host.get_position(): |
| candy = host.remove_candy(candy_criteria) | | candy = host.remove_candy(FluxCapacitor.candy_criteria) |
| break | | break |
| if candy is not None: | | if candy is not None: |
| kid.add_candy(candy) | | kid.add_candy(candy) |
n | unvisited[kid.get_initiative()].remove(next_position) | n | unvisited[kid.get_initiative()].remove(next_pos) |
| if len(unvisited[kid.get_initiative()]) == 0: | | if len(unvisited[kid.get_initiative()]) == 0: |
| unvisited.pop(kid.get_initiative()) | | unvisited.pop(kid.get_initiative()) |
| | | |
| kids_with_critical_mass = self._critical_mass_check() | | kids_with_critical_mass = self._critical_mass_check() |
| if kids_with_critical_mass: | | if kids_with_critical_mass: |
| return kids_with_critical_mass | | return kids_with_critical_mass |
| | | |
| return None | | return None |
| | | |
n | def _closest_host(self, pos: tuple, remaining_hosts: set): | n | |
| closest_dist = 10000000 | | |
| next_pos = (100000, 100000) | | |
| | | |
| for host in remaining_hosts: | | |
| dist = ((pos[0] - host[0]) * (pos[0] - host[0]) | | |
| + (pos[1] - host[1]) * (pos[1] - host[1])) | | |
| if (dist < closest_dist | | |
| or (dist == closest_dist and next_pos[0] < pos[0]) | | |
| or (dist == closest_dist and next_pos[0] == pos[0] and next_pos[1] < pos[1])): | | |
| closest_dist = dist | | |
| next_pos = host | | |
| return next_pos | | |
| | | |
| def _critical_mass_check(self): | | def _critical_mass_check(self): |
| kids_with_critical_mass = set() | | kids_with_critical_mass = set() |
| for kid in self._kids: | | for kid in self._kids: |
| if kid.is_critical(): | | if kid.is_critical(): |
| kids_with_critical_mass.add(kid) | | kids_with_critical_mass.add(kid) |
| return kids_with_critical_mass | | return kids_with_critical_mass |
| | | |
t | | t | @staticmethod |
| | | def closest_host(pos: tuple, remaining_hosts: set): |
| | | closest_dist = None |
| | | |
| | | for host in remaining_hosts: |
| | | dist = ((pos[0] - host[0]) * (pos[0] - host[0]) |
| | | + (pos[1] - host[1]) * (pos[1] - host[1])) |
| | | if (closest_dist is None or dist < closest_dist |
| | | or (dist == closest_dist and next_pos[0] < pos[0]) |
| | | or (dist == closest_dist and next_pos[0] == pos[0] and next_pos[1] < pos[1])): |
| | | closest_dist = dist |
| | | next_pos = host |
| | | return next_pos |
| | | |
| | | @staticmethod |
| def candy_criteria(candies: list[Candy]): | | def candy_criteria(candies: list[Candy]): |
| chosen_candy = Candy(0, 0) | | chosen_candy = Candy(0, 0) |
| for candy in candies: | | for candy in candies: |
| if candy.get_mass() > chosen_candy.get_mass(): | | if candy.get_mass() > chosen_candy.get_mass(): |
| chosen_candy = candy | | chosen_candy = candy |
| return chosen_candy | | return chosen_candy |