Домашни > Подаръци ще има за всички от сърце > Решения > Решението на Стефан Шиваров

Резултати
10 точки от тестове
0 точки от учител

10 точки общо

19 успешни теста
1 неуспешни теста
Код
Скрий всички коментари

  1import re
  2import random
  3
  4
  5class Santa:
  6    _instance = None
  7
  8    def __new__(cls, *args, **kwargs):
  9        if cls._instance is None:
 10            cls._instance = super(Santa, cls).__new__(cls)
 11            cls._instance._kids = {}
 12            cls._instance._presents = {}
 13            cls._instance._present_counts = {}
 14            cls._instance._year_counts = {}
 15            cls._instance._naughty_kids = []
 16        return cls._instance
 17
 18    def _add_kid(self, kid):
 19        kid_id = id(kid)
 20        self._kids[kid_id] = kid
 21        self._year_counts[kid_id] = 0
 22
 23    def _add_present_for_kid(self, kid, present):
 24        self._presents[id(kid)] = present
 25        if present not in self._present_counts:
 26            self._present_counts[present] = 0
 27        self._present_counts[present] += 1
 28
 29    def _extract_present_from_request(self, request):
 30        present_match = re.search(r'"([A-Za-z0-9\s]*)"|\'([A-Za-z0-9\s]*)\'', request)
 31        if present_match:
 32            return present_match.group(1) or present_match.group(2)
 33        return None
 34
 35    def __call__(self, kid, request):
 36        present = self._extract_present_from_request(request)
 37        self._add_present_for_kid(kid, present)
 38
 39    def __matmul__(self, letter):
 40        id_match = re.search(r'\b(\d+)\b', letter)
 41        if id_match:
 42            kid_id = int(id_match.group(1))
 43            if kid_id in self._kids:
 44                present = self._extract_present_from_request(letter)
 45                self._add_present_for_kid(self._kids[kid_id], present)
 46
 47    def __iter__(self):
 48        for present in self._presents.values():
 49            yield present
 50
 51    def _get_most_requested_present(self):
 52        if not self._present_counts:
 53            return None
 54        max_count = max(self._present_counts.values())
 55        most_requested = [pr for pr, count in self._present_counts.items() if count == max_count]
 56        return random.choice(most_requested)
 57
 58    def _is_kid_grown_up(self, kid_id):
 59        return self._year_counts.get(kid_id, 0) >= 5
 60
 61    def _is_kid_naughty(self, kid_id):
 62        return self._naughty_kids.count(kid_id)
 63
 64    def _remove_kid(self, kid_id):
 65        self._kids.pop(kid_id, None)
 66        self._presents.pop(kid_id, None)
 67        self._year_counts.pop(kid_id, None)
 68        if kid_id in self._naughty_kids:
 69            self._naughty_kids.remove(kid_id)
 70
 71    def _clear_requests(self):
 72        self._presents.clear()
 73        self._present_counts.clear()
 74
 75    def _increment_xmas_counts(self):
 76        for kid_id in self._year_counts:
 77            self._year_counts[kid_id] += 1
 78
 79    def xmas(self):
 80        most_requested_present = self._get_most_requested_present()
 81        kids_to_remove = []
 82        for kid_id, kid in self._kids.items():
 83            if self._presents and self._present_counts:
 84                if self._is_kid_grown_up(kid_id):
 85                    kids_to_remove.append(kid_id)
 86                    continue
 87                elif self._presents.get(kid_id, False) and self._is_kid_naughty(kid_id):
 88                    kid("coal")
 89                else:
 90                    present = self._presents.get(kid_id, most_requested_present)
 91                    kid(present)
 92            self._year_counts[kid_id] += 1
 93
 94        for kid_id in kids_to_remove:
 95            self._remove_kid(kid_id)
 96
 97        self._clear_requests()
 98
 99
100# опитах да използвам нещо подобно на декоратор (не баш) за логиката с непослушните деца
101# може би има и по - елегантен начин :D
102def naughty_checker(func, kid):
103    def wrapper(*args, **kwargs):
104        santa = Santa()
105        try:
106            return func(*args, **kwargs)
107        except Exception:
108            santa._naughty_kids.append(id(kid))
109            raise
110    return wrapper
111
112
113class Kid(type):
114
115    def __new__(cls, name, bases, attr_dict):
116        if "__call__" not in attr_dict:
117            raise NotImplementedError("__call__ is not implemented by the kid!")
118        return super().__new__(cls, name, bases, attr_dict)
119
120    def __call__(cls, *args, **kwargs):
121        instance = super(Kid, cls).__call__(*args, **kwargs)
122        santa = Santa()
123        santa._add_kid(instance)
124
125        for attr_name in dir(instance):
126            attribute = getattr(instance, attr_name)
127            if not attr_name.startswith('_') and callable(attribute):
128                setattr(instance, attr_name, naughty_checker(attribute, instance))
129
130        return instance

........F...........
======================================================================
FAIL: test_signature_matching (test.TestSanta.test_signature_matching)
Test matching present in the letter / call.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 119, in test_signature_matching
self.assertEqual(kid2.SECRET_PRESENT, 'toy2')
AssertionError: 'toy1' != 'toy2'
- toy1
? ^
+ toy2
? ^

----------------------------------------------------------------------
Ran 20 tests in 0.023s

FAILED (failures=1)

Дискусия
Стефан Шиваров
19.12.2024 18:07

Функцията ```increment_xmas_counts``` е излишна. Бях я написал първоначално, когато имах друга последователност на изпълнението в xmas(), но сега виждам, че съм забравил да я махна 😀
История
Това решение има само една версия.