f | import re | f | import re |
| | | |
| class Santa: | | class Santa: |
| _instance = None | | _instance = None |
n | _wish_pattern = r"(\"|\')[A-Za-z0-9\s]+\1" | n | _WISH_PATTERN = r"(\"|\')[A-Za-z0-9\s]+\1" |
| _id_pattern = r"^\s*\d+\s*$" | | _ID_PATTERN = r"^\s*\d+\s*$" |
| | | _MAX_XMAS_COUNT = 5 |
| _kid_presents = {} | | _kid_presents = {} |
| _all_presents = {} | | _all_presents = {} |
| _all_kids = [] | | _all_kids = [] |
| _presents = [] | | _presents = [] |
| | | |
| def __new__(cls, *args, **kwargs): | | def __new__(cls, *args, **kwargs): |
| if cls._instance is None: | | if cls._instance is None: |
| cls._instance = super().__new__(cls) | | cls._instance = super().__new__(cls) |
| return cls._instance | | return cls._instance |
| | | |
| def _present_checker(self, present): | | def _present_checker(self, present): |
n | wish_match = re.search(self._wish_pattern, present) | n | wish_match = re.search(self._WISH_PATTERN, present) |
| if not wish_match: | | if not wish_match: |
| raise TypeError('not a valid wish') | | raise TypeError('not a valid wish') |
| | | |
| return re.sub(r'(\'|\")', '', wish_match.group()) | | return re.sub(r'(\'|\")', '', wish_match.group()) |
| | | |
| def _add_present(self, kid, present): | | def _add_present(self, kid, present): |
| current_present = self._kid_presents.get(kid, None) | | current_present = self._kid_presents.get(kid, None) |
| | | |
| if current_present: | | if current_present: |
| idx = self._presents.index(current_present) | | idx = self._presents.index(current_present) |
| self._presents[idx] = present | | self._presents[idx] = present |
| else: | | else: |
| self._presents.append(present) | | self._presents.append(present) |
| | | |
| self._kid_presents[kid] = present | | self._kid_presents[kid] = present |
n | if present not in self._all_presents.keys(): | n | self._all_presents[present] = self._all_presents.get(present, 0) + 1 |
| self._all_presents[present] = 0 | | |
| self._all_presents[present] += 1 | | |
| | | |
| def __call__(self, kid, message): | | def __call__(self, kid, message): |
| present = self._present_checker(message) | | present = self._present_checker(message) |
| self._add_present(kid, present) | | self._add_present(kid, present) |
| | | |
| def __matmul__(self, letter): | | def __matmul__(self, letter): |
| present = self._present_checker(letter) | | present = self._present_checker(letter) |
n | id_match = re.search(self._id_pattern, letter, re.MULTILINE) | n | id_match = re.search(self._ID_PATTERN, letter, re.MULTILINE) |
| | | |
| kid_id = int(re.sub(r'\s', '', id_match.group())) | | kid_id = int(re.sub(r'\s', '', id_match.group())) |
| kid = Kid.get_instance(kid_id) | | kid = Kid.get_instance(kid_id) |
| | | |
| if kid is None: | | if kid is None: |
| raise TypeError('not a valid kid') | | raise TypeError('not a valid kid') |
| | | |
| self._add_present(kid, present) | | self._add_present(kid, present) |
| | | |
| def __iter__(self): | | def __iter__(self): |
n | for _ in self._presents: | n | for present in self._presents: |
| yield _ | | yield present |
| | | |
| def _clear_list(self): | | def _clear_list(self): |
| self._kid_presents.clear() | | self._kid_presents.clear() |
| self._all_presents.clear() | | self._all_presents.clear() |
| self._presents.clear() | | self._presents.clear() |
| | | |
| def _xmas_checker(self): | | def _xmas_checker(self): |
| for kid in self._all_kids: | | for kid in self._all_kids: |
n | if kid.xmas_count == 5: | n | if kid.xmas_count == self._MAX_XMAS_COUNT: |
| Kid.remove_from_xmas(kid) | | Kid.remove_from_xmas(kid) |
| continue | | continue |
| kid.xmas_count += 1 | | kid.xmas_count += 1 |
| | | |
| def xmas(self): | | def xmas(self): |
| self._xmas_checker() | | self._xmas_checker() |
| | | |
| if not self._kid_presents: | | if not self._kid_presents: |
| return None | | return None |
| | | |
n | best_present = self._most_wished_present() | n | best_present = max(self._all_presents, key=self._all_presents.get) |
| | | |
| for kid in self._all_kids: | | for kid in self._all_kids: |
| if not kid._has_present: | | if not kid._has_present: |
| continue | | continue |
| if kid._has_exception: | | if kid._has_exception: |
| kid('coal') | | kid('coal') |
| Kid.reset_exception_status(kid) | | Kid.reset_exception_status(kid) |
| else: | | else: |
| if kid not in self._kid_presents.keys(): | | if kid not in self._kid_presents.keys(): |
| kid(best_present) | | kid(best_present) |
| else: | | else: |
| kid(self._kid_presents[kid]) | | kid(self._kid_presents[kid]) |
| | | |
| self._clear_list() | | self._clear_list() |
t | | t | |
| | | |
| def _most_wished_present(self): | | |
| counter = 0 | | |
| present = '' | | |
| | | |
| for curr_present, curr_count in self._all_presents.items(): | | |
| if curr_count >= counter: | | |
| present = curr_present | | |
| counter = curr_count | | |
| | | |
| return present | | |
| | | |
| | | |
| @classmethod | | @classmethod |
| def add_kid(cls, kid): | | def add_kid(cls, kid): |
| cls._all_kids.append(kid) | | cls._all_kids.append(kid) |
| | | |
| | | |
| class Kid(type): | | class Kid(type): |
| _instances = {} | | _instances = {} |
| | | |
| def __new__(cls, name, bases, attr_dict): | | def __new__(cls, name, bases, attr_dict): |
| if '__call__' not in attr_dict.keys(): | | if '__call__' not in attr_dict.keys(): |
| raise NotImplementedError | | raise NotImplementedError |
| attr_dict['xmas_count'] = 0 | | attr_dict['xmas_count'] = 0 |
| attr_dict['_has_exception'] = False | | attr_dict['_has_exception'] = False |
| attr_dict['_has_present'] = True | | attr_dict['_has_present'] = True |
| | | |
| for name, value in attr_dict.items(): | | for name, value in attr_dict.items(): |
| if callable(value) and not name.startswith('_'): | | if callable(value) and not name.startswith('_'): |
| attr_dict[name] = cls.check_exceptions(value) | | attr_dict[name] = cls.check_exceptions(value) |
| return super().__new__(cls, name, bases, attr_dict) | | return super().__new__(cls, name, bases, attr_dict) |
| | | |
| @staticmethod | | @staticmethod |
| def check_exceptions(func): | | def check_exceptions(func): |
| def decorator(self, *args, **kwargs): | | def decorator(self, *args, **kwargs): |
| try: | | try: |
| return func(self, *args, **kwargs) | | return func(self, *args, **kwargs) |
| except Exception as e: | | except Exception as e: |
| self._has_exception = True | | self._has_exception = True |
| raise | | raise |
| return decorator | | return decorator |
| | | |
| @classmethod | | @classmethod |
| def reset_exception_status(cls, instance): | | def reset_exception_status(cls, instance): |
| instance._has_exception = False | | instance._has_exception = False |
| | | |
| @classmethod | | @classmethod |
| def remove_from_xmas(cls, instance): | | def remove_from_xmas(cls, instance): |
| instance._has_present = False | | instance._has_present = False |
| | | |
| def __call__(cls, *args, **kwargs): | | def __call__(cls, *args, **kwargs): |
| instance = super().__call__(*args, **kwargs) | | instance = super().__call__(*args, **kwargs) |
| Santa.add_kid(instance) | | Santa.add_kid(instance) |
| | | |
| if id(instance) not in Kid._instances.keys(): | | if id(instance) not in Kid._instances.keys(): |
| Kid._instances[id(instance)] = instance | | Kid._instances[id(instance)] = instance |
| | | |
| return instance | | return instance |
| | | |
| @classmethod | | @classmethod |
| def get_instance(cls, instance_id): | | def get_instance(cls, instance_id): |
| return cls._instances.get(instance_id, None) | | return cls._instances.get(instance_id, None) |