1import re
2
3class SingletonType(type):
4 def __new__(mcs, name, bases, attrs):
5 def singleton_new(cls):
6 if not hasattr(cls, 'instance'):
7 cls.instance = object.__new__(cls)
8 return cls.instance
9 attrs['__new__'] = singleton_new
10 return type.__new__(mcs, name, bases, attrs)
11
12
13class Santa(metaclass = SingletonType):
14 """A class for greedy kids."""
15 all_kids = set()
16 kids_objects = {}
17 kids_ages = {}
18 gifts = {}
19 naughty_kids = set()
20
21 def extract_gift(self, letter: str):
22 """Extracts a gift from a letter or call."""
23 pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')'
24 pattern = re.compile(pattern_gift, re.MULTILINE)
25 gifts = pattern.findall(letter)
26
27 for gift_tuple in reversed(gifts):
28 for gift in gift_tuple:
29 if gift:
30 return gift
31 return None
32
33 def extract_signature_from_letter(self, letter: str):
34 """Extracts a signiture from a letter."""
35 pattern_signature = r'\s*(\d+)\s*'
36 pattern = re.compile(pattern_signature, re.MULTILINE)
37 signature = pattern.findall(letter)
38 if signature:
39 return signature[-1]
40 return None
41
42 def __matmul__(self, letter: str):
43 """Predefined operator @ when a kid writes a letter to Santa."""
44 gift = self.extract_gift(letter)
45 signature = self.extract_signature_from_letter(letter)
46
47 index = int(signature)
48 self.gifts[index] = gift
49 self.all_kids.add(index)
50 self.kids_ages[index] = 0
51 if id(signature) in self.kids_objects:
52 self.kids_objects[signature] = signature
53
54 def __call__(self, child, wish: str):
55 """Predefined operator () when a kid calls Santa."""
56 index = id(child)
57 self.gifts[index] = self.extract_gift(wish)
58
59 def __iter__(self):
60 return iter(self.gifts.values())
61
62 def get_most_wanted_gift_this_year(self):
63 """Calculates what is the most wanted gift this year."""
64 this_years_gifts = [gift for gift in self.gifts.values() if gift is not None]
65
66 if set(this_years_gifts):
67 most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count)
68 else:
69 most_wanted_gift_this_year = None
70 return most_wanted_gift_this_year
71
72 def remove_kid(self, keys_to_delete):
73 """Deletes kid because it is too old for presents."""
74 for key in keys_to_delete:
75 del self.gifts[key]
76 del self.kids_ages[key]
77 del self.kids_objects[key]
78 self.all_kids.remove(key)
79
80 def mark_as_naughty(self, kid):
81 """Marks a kid as naughty."""
82 if id(kid) in self.all_kids:
83 self.naughty_kids.add(id(kid))
84
85 def xmas(self):
86 """Time for presents."""
87 for key in self.kids_ages:
88 self.kids_ages[key] += 1
89
90 most_wanted_gift = self.get_most_wanted_gift_this_year()
91 keys_to_delete = []
92
93 for kid, age in self.kids_ages.items():
94 cur_gift = self.gifts[kid]
95 if age > 5:
96 keys_to_delete.append(kid)
97 continue
98 elif age <= 5:
99 kid_obj = self.kids_objects.get(kid)
100 if all(value == None for value in self.gifts.values()):
101 break
102 elif kid in self.naughty_kids:
103 kid_obj("coal")
104 elif cur_gift is None:
105 kid_obj(most_wanted_gift)
106 else:
107 kid_obj(cur_gift)
108
109 for cur_gift in self.gifts:
110 self.gifts[cur_gift] = None
111
112 self.remove_kid(keys_to_delete)
113 self.naughty_kids.clear()
114
115
116def detect_naughty_kid(func):
117 """Checks if the kid is naughty."""
118 def wrapper(self, *args, **kwargs):
119 try:
120 return func(self, *args, **kwargs)
121 except Exception:
122 Santa().mark_as_naughty(self)
123 raise
124 return wrapper
125
126
127class Kid(type):
128 """A class that defines a kid."""
129 def __new__(mcs, name, bases, attrs):
130 if '__call__' not in attrs:
131 raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).")
132 for key, value in attrs.items():
133 if callable(value) and not key.startswith("_"):
134 attrs[key] = detect_naughty_kid(value)
135 return super().__new__(mcs, name, bases, attrs)
136
137 def __call__(cls, *args, **kwargs):
138 instance = super().__call__(*args, **kwargs)
139 if id(instance) not in Santa().all_kids:
140 Santa().all_kids.add(id(instance))
141 Santa().gifts[id(instance)] = None
142 Santa().kids_ages[id(instance)] = 0
143 Santa().kids_objects[id(instance)] = instance
144 return instance
......FF............
======================================================================
FAIL: test_present_matching (test.TestSanta.test_present_matching)
Test matching signature in the letter.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 92, in test_present_matching
self.assertEqual(list(self.santa), ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '])
AssertionError: Lists differ: ['toy4', None, 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '] != ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
First differing element 1:
None
'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '
First list contains 1 additional elements.
First extra element 2:
'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '
- ['toy4', None, 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
? ------
+ ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
======================================================================
FAIL: test_santa_gift_order (test.TestSanta.test_santa_gift_order)
Test ordering of the Santa iterator.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 260, in test_santa_gift_order
self.assertEqual(list(self.santa), ["toy2v2", "toy3", "toy1"])
AssertionError: Lists differ: ['toy1', 'toy2v2', 'toy3'] != ['toy2v2', 'toy3', 'toy1']
First differing element 0:
'toy1'
'toy2v2'
- ['toy1', 'toy2v2', 'toy3']
+ ['toy2v2', 'toy3', 'toy1']
----------------------------------------------------------------------
Ran 20 tests in 0.038s
FAILED (failures=2)
Виктор Бечев
19.12.2024 13:30Аз говорех за това, че имаш два почти идентични регулярни израза, с единствената разлика в кавичките. Това може да бъде обединено в клас - `[\'"]`.
|
Росица Илиева
19.12.2024 13:16Няма проблем, иначе относно регекса в extract_gift го направих така, предвид това че подаръкът не може да е празен стринг или само whitespace-ове. Реално никъде в условието не е казано, че не може да е празен стринг, но аз от тази гледна точка го направих така.
|
Виктор Бечев
19.12.2024 13:12Вътрешната репрезентация, за която говориш, е в `Santa`. Там нямаме претенции какво ще правиш, не би следвало да ни създаде проблем как и какво ще пазиш.
Тестовете се базират на input и очакван output. Ако тези две неща са окей - тестовете минават.
П.П. Късно, бях започнал да пиша. :grin:
|
Росица Илиева
19.12.2024 13:10Отговорих си на въпроса
|
Росица Илиева
19.12.2024 12:14Ии последен въпрос, когато никой няма желание за Коледа, в моя код задавам стойност None за подаръка на съответното дете. Това ли трябва да връщаме в такъв случай, или това ще си зависи от имплементацията на наследниците на Kid?
|
Виктор Бечев
19.12.2024 11:55Хубав въпрос. Според буквалното четене на условието:
```
Ако през изминалата година (т.е. след последното извикване на xmas) Дядо Коледа не е получил нито едно желание (с писмо или с обаждане), той не раздава нищо на никого. Явно магията на Коледа е отминала и всички са забравили за него.
```
Следва дори и лошите деца да не получават нищо, защото на Дядо Коледа му е тъжно.
|
Росица Илиева
19.12.2024 11:01Ако никое дете няма желания за подаръци за Коледа, обаче някое от тях тази година е било непослушно, изпращаме ли му въглен, или не получава нищо?
|
Виктор Бечев
18.12.2024 22:37С изключение на едно минало предизвикателство - никъде в домашните (и като цяло рядко в production код) не очакваме да има принтове.
|
Росица Илиева
18.12.2024 21:33Имам въпрос дали е необходимо да добавяме принтове за всеки подарък, който дете получава, или това не е задължително?
|
| f | 1 | import re | f | 1 | import re |
| 2 | 2 | ||||
| 3 | class SingletonType(type): | 3 | class SingletonType(type): | ||
| 4 | def __new__(mcs, name, bases, attrs): | 4 | def __new__(mcs, name, bases, attrs): | ||
| 5 | def singleton_new(cls): | 5 | def singleton_new(cls): | ||
| 6 | if not hasattr(cls, 'instance'): | 6 | if not hasattr(cls, 'instance'): | ||
| 7 | cls.instance = object.__new__(cls) | 7 | cls.instance = object.__new__(cls) | ||
| 8 | return cls.instance | 8 | return cls.instance | ||
| 9 | attrs['__new__'] = singleton_new | 9 | attrs['__new__'] = singleton_new | ||
| 10 | return type.__new__(mcs, name, bases, attrs) | 10 | return type.__new__(mcs, name, bases, attrs) | ||
| 11 | 11 | ||||
| 12 | 12 | ||||
| 13 | class Santa(metaclass = SingletonType): | 13 | class Santa(metaclass = SingletonType): | ||
| 14 | """A class for greedy kids.""" | 14 | """A class for greedy kids.""" | ||
| 15 | all_kids = set() | 15 | all_kids = set() | ||
| 16 | kids_objects = {} | 16 | kids_objects = {} | ||
| 17 | kids_ages = {} | 17 | kids_ages = {} | ||
| 18 | gifts = {} | 18 | gifts = {} | ||
| 19 | naughty_kids = set() | 19 | naughty_kids = set() | ||
| 20 | 20 | ||||
| 21 | def extract_gift(self, letter: str): | 21 | def extract_gift(self, letter: str): | ||
| 22 | """Extracts a gift from a letter or call.""" | 22 | """Extracts a gift from a letter or call.""" | ||
| 23 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | 23 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | ||
| 24 | pattern = re.compile(pattern_gift, re.MULTILINE) | 24 | pattern = re.compile(pattern_gift, re.MULTILINE) | ||
| 25 | gifts = pattern.findall(letter) | 25 | gifts = pattern.findall(letter) | ||
| 26 | 26 | ||||
| 27 | for gift_tuple in reversed(gifts): | 27 | for gift_tuple in reversed(gifts): | ||
| 28 | for gift in gift_tuple: | 28 | for gift in gift_tuple: | ||
| 29 | if gift: | 29 | if gift: | ||
| 30 | return gift | 30 | return gift | ||
| 31 | return None | 31 | return None | ||
| 32 | 32 | ||||
| 33 | def extract_signature_from_letter(self, letter: str): | 33 | def extract_signature_from_letter(self, letter: str): | ||
| 34 | """Extracts a signiture from a letter.""" | 34 | """Extracts a signiture from a letter.""" | ||
| 35 | pattern_signature = r'\s*(\d+)\s*' | 35 | pattern_signature = r'\s*(\d+)\s*' | ||
| 36 | pattern = re.compile(pattern_signature, re.MULTILINE) | 36 | pattern = re.compile(pattern_signature, re.MULTILINE) | ||
| 37 | signature = pattern.findall(letter) | 37 | signature = pattern.findall(letter) | ||
| 38 | if signature: | 38 | if signature: | ||
| 39 | return signature[-1] | 39 | return signature[-1] | ||
| 40 | return None | 40 | return None | ||
| 41 | 41 | ||||
| 42 | def __matmul__(self, letter: str): | 42 | def __matmul__(self, letter: str): | ||
| 43 | """Predefined operator @ when a kid writes a letter to Santa.""" | 43 | """Predefined operator @ when a kid writes a letter to Santa.""" | ||
| 44 | gift = self.extract_gift(letter) | 44 | gift = self.extract_gift(letter) | ||
| 45 | signature = self.extract_signature_from_letter(letter) | 45 | signature = self.extract_signature_from_letter(letter) | ||
| 46 | 46 | ||||
| 47 | index = int(signature) | 47 | index = int(signature) | ||
| 48 | self.gifts[index] = gift | 48 | self.gifts[index] = gift | ||
| 49 | self.all_kids.add(index) | 49 | self.all_kids.add(index) | ||
| 50 | self.kids_ages[index] = 0 | 50 | self.kids_ages[index] = 0 | ||
| 51 | if id(signature) in self.kids_objects: | 51 | if id(signature) in self.kids_objects: | ||
| 52 | self.kids_objects[signature] = signature | 52 | self.kids_objects[signature] = signature | ||
| 53 | 53 | ||||
| 54 | def __call__(self, child, wish: str): | 54 | def __call__(self, child, wish: str): | ||
| 55 | """Predefined operator () when a kid calls Santa.""" | 55 | """Predefined operator () when a kid calls Santa.""" | ||
| 56 | index = id(child) | 56 | index = id(child) | ||
| 57 | self.gifts[index] = self.extract_gift(wish) | 57 | self.gifts[index] = self.extract_gift(wish) | ||
| 58 | 58 | ||||
| 59 | def __iter__(self): | 59 | def __iter__(self): | ||
| 60 | return iter(self.gifts.values()) | 60 | return iter(self.gifts.values()) | ||
| 61 | 61 | ||||
| 62 | def get_most_wanted_gift_this_year(self): | 62 | def get_most_wanted_gift_this_year(self): | ||
| 63 | """Calculates what is the most wanted gift this year.""" | 63 | """Calculates what is the most wanted gift this year.""" | ||
| 64 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | 64 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | ||
| 65 | 65 | ||||
| 66 | if set(this_years_gifts): | 66 | if set(this_years_gifts): | ||
| 67 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | 67 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | ||
| 68 | else: | 68 | else: | ||
| 69 | most_wanted_gift_this_year = None | 69 | most_wanted_gift_this_year = None | ||
| 70 | return most_wanted_gift_this_year | 70 | return most_wanted_gift_this_year | ||
| 71 | 71 | ||||
| 72 | def remove_kid(self, keys_to_delete): | 72 | def remove_kid(self, keys_to_delete): | ||
| 73 | """Deletes kid because it is too old for presents.""" | 73 | """Deletes kid because it is too old for presents.""" | ||
| 74 | for key in keys_to_delete: | 74 | for key in keys_to_delete: | ||
| 75 | del self.gifts[key] | 75 | del self.gifts[key] | ||
| 76 | del self.kids_ages[key] | 76 | del self.kids_ages[key] | ||
| 77 | del self.kids_objects[key] | 77 | del self.kids_objects[key] | ||
| 78 | self.all_kids.remove(key) | 78 | self.all_kids.remove(key) | ||
| 79 | 79 | ||||
| 80 | def mark_as_naughty(self, kid): | 80 | def mark_as_naughty(self, kid): | ||
| 81 | """Marks a kid as naughty.""" | 81 | """Marks a kid as naughty.""" | ||
| 82 | if id(kid) in self.all_kids: | 82 | if id(kid) in self.all_kids: | ||
| 83 | self.naughty_kids.add(id(kid)) | 83 | self.naughty_kids.add(id(kid)) | ||
| 84 | 84 | ||||
| 85 | def xmas(self): | 85 | def xmas(self): | ||
| 86 | """Time for presents.""" | 86 | """Time for presents.""" | ||
| 87 | for key in self.kids_ages: | 87 | for key in self.kids_ages: | ||
| 88 | self.kids_ages[key] += 1 | 88 | self.kids_ages[key] += 1 | ||
| 89 | 89 | ||||
| 90 | most_wanted_gift = self.get_most_wanted_gift_this_year() | 90 | most_wanted_gift = self.get_most_wanted_gift_this_year() | ||
| 91 | keys_to_delete = [] | 91 | keys_to_delete = [] | ||
| 92 | 92 | ||||
| 93 | for kid, age in self.kids_ages.items(): | 93 | for kid, age in self.kids_ages.items(): | ||
| 94 | cur_gift = self.gifts[kid] | 94 | cur_gift = self.gifts[kid] | ||
| 95 | if age > 5: | 95 | if age > 5: | ||
| 96 | keys_to_delete.append(kid) | 96 | keys_to_delete.append(kid) | ||
| 97 | continue | 97 | continue | ||
| 98 | elif age <= 5: | 98 | elif age <= 5: | ||
| 99 | kid_obj = self.kids_objects.get(kid) | 99 | kid_obj = self.kids_objects.get(kid) | ||
| t | 100 | if kid in self.naughty_kids and not all(value == None for value in self.gifts.values()): | t | 100 | if all(value == None for value in self.gifts.values()): |
| 101 | break | ||||
| 102 | elif kid in self.naughty_kids: | ||||
| 101 | kid_obj("coal") | 103 | kid_obj("coal") | ||
| 102 | elif cur_gift is None: | 104 | elif cur_gift is None: | ||
| 103 | kid_obj(most_wanted_gift) | 105 | kid_obj(most_wanted_gift) | ||
| 104 | else: | 106 | else: | ||
| 105 | kid_obj(cur_gift) | 107 | kid_obj(cur_gift) | ||
| 106 | 108 | ||||
| 107 | for cur_gift in self.gifts: | 109 | for cur_gift in self.gifts: | ||
| 108 | self.gifts[cur_gift] = None | 110 | self.gifts[cur_gift] = None | ||
| 109 | 111 | ||||
| 110 | self.remove_kid(keys_to_delete) | 112 | self.remove_kid(keys_to_delete) | ||
| 111 | self.naughty_kids.clear() | 113 | self.naughty_kids.clear() | ||
| 112 | 114 | ||||
| 113 | 115 | ||||
| 114 | def detect_naughty_kid(func): | 116 | def detect_naughty_kid(func): | ||
| 115 | """Checks if the kid is naughty.""" | 117 | """Checks if the kid is naughty.""" | ||
| 116 | def wrapper(self, *args, **kwargs): | 118 | def wrapper(self, *args, **kwargs): | ||
| 117 | try: | 119 | try: | ||
| 118 | return func(self, *args, **kwargs) | 120 | return func(self, *args, **kwargs) | ||
| 119 | except Exception: | 121 | except Exception: | ||
| 120 | Santa().mark_as_naughty(self) | 122 | Santa().mark_as_naughty(self) | ||
| 121 | raise | 123 | raise | ||
| 122 | return wrapper | 124 | return wrapper | ||
| 123 | 125 | ||||
| 124 | 126 | ||||
| 125 | class Kid(type): | 127 | class Kid(type): | ||
| 126 | """A class that defines a kid.""" | 128 | """A class that defines a kid.""" | ||
| 127 | def __new__(mcs, name, bases, attrs): | 129 | def __new__(mcs, name, bases, attrs): | ||
| 128 | if '__call__' not in attrs: | 130 | if '__call__' not in attrs: | ||
| 129 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | 131 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | ||
| 130 | for key, value in attrs.items(): | 132 | for key, value in attrs.items(): | ||
| 131 | if callable(value) and not key.startswith("_"): | 133 | if callable(value) and not key.startswith("_"): | ||
| 132 | attrs[key] = detect_naughty_kid(value) | 134 | attrs[key] = detect_naughty_kid(value) | ||
| 133 | return super().__new__(mcs, name, bases, attrs) | 135 | return super().__new__(mcs, name, bases, attrs) | ||
| 134 | 136 | ||||
| 135 | def __call__(cls, *args, **kwargs): | 137 | def __call__(cls, *args, **kwargs): | ||
| 136 | instance = super().__call__(*args, **kwargs) | 138 | instance = super().__call__(*args, **kwargs) | ||
| 137 | if id(instance) not in Santa().all_kids: | 139 | if id(instance) not in Santa().all_kids: | ||
| 138 | Santa().all_kids.add(id(instance)) | 140 | Santa().all_kids.add(id(instance)) | ||
| 139 | Santa().gifts[id(instance)] = None | 141 | Santa().gifts[id(instance)] = None | ||
| 140 | Santa().kids_ages[id(instance)] = 0 | 142 | Santa().kids_ages[id(instance)] = 0 | ||
| 141 | Santa().kids_objects[id(instance)] = instance | 143 | Santa().kids_objects[id(instance)] = instance | ||
| 142 | return instance | 144 | return instance |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import re | f | 1 | import re |
| 2 | 2 | ||||
| 3 | class SingletonType(type): | 3 | class SingletonType(type): | ||
| 4 | def __new__(mcs, name, bases, attrs): | 4 | def __new__(mcs, name, bases, attrs): | ||
| 5 | def singleton_new(cls): | 5 | def singleton_new(cls): | ||
| 6 | if not hasattr(cls, 'instance'): | 6 | if not hasattr(cls, 'instance'): | ||
| 7 | cls.instance = object.__new__(cls) | 7 | cls.instance = object.__new__(cls) | ||
| 8 | return cls.instance | 8 | return cls.instance | ||
| 9 | attrs['__new__'] = singleton_new | 9 | attrs['__new__'] = singleton_new | ||
| 10 | return type.__new__(mcs, name, bases, attrs) | 10 | return type.__new__(mcs, name, bases, attrs) | ||
| 11 | 11 | ||||
| 12 | 12 | ||||
| 13 | class Santa(metaclass = SingletonType): | 13 | class Santa(metaclass = SingletonType): | ||
| 14 | """A class for greedy kids.""" | 14 | """A class for greedy kids.""" | ||
| 15 | all_kids = set() | 15 | all_kids = set() | ||
| 16 | kids_objects = {} | 16 | kids_objects = {} | ||
| 17 | kids_ages = {} | 17 | kids_ages = {} | ||
| 18 | gifts = {} | 18 | gifts = {} | ||
| 19 | naughty_kids = set() | 19 | naughty_kids = set() | ||
| 20 | 20 | ||||
| 21 | def extract_gift(self, letter: str): | 21 | def extract_gift(self, letter: str): | ||
| 22 | """Extracts a gift from a letter or call.""" | 22 | """Extracts a gift from a letter or call.""" | ||
| 23 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | 23 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | ||
| 24 | pattern = re.compile(pattern_gift, re.MULTILINE) | 24 | pattern = re.compile(pattern_gift, re.MULTILINE) | ||
| 25 | gifts = pattern.findall(letter) | 25 | gifts = pattern.findall(letter) | ||
| 26 | 26 | ||||
| 27 | for gift_tuple in reversed(gifts): | 27 | for gift_tuple in reversed(gifts): | ||
| 28 | for gift in gift_tuple: | 28 | for gift in gift_tuple: | ||
| 29 | if gift: | 29 | if gift: | ||
| 30 | return gift | 30 | return gift | ||
| 31 | return None | 31 | return None | ||
| 32 | 32 | ||||
| 33 | def extract_signature_from_letter(self, letter: str): | 33 | def extract_signature_from_letter(self, letter: str): | ||
| 34 | """Extracts a signiture from a letter.""" | 34 | """Extracts a signiture from a letter.""" | ||
| 35 | pattern_signature = r'\s*(\d+)\s*' | 35 | pattern_signature = r'\s*(\d+)\s*' | ||
| 36 | pattern = re.compile(pattern_signature, re.MULTILINE) | 36 | pattern = re.compile(pattern_signature, re.MULTILINE) | ||
| 37 | signature = pattern.findall(letter) | 37 | signature = pattern.findall(letter) | ||
| 38 | if signature: | 38 | if signature: | ||
| 39 | return signature[-1] | 39 | return signature[-1] | ||
| 40 | return None | 40 | return None | ||
| 41 | 41 | ||||
| 42 | def __matmul__(self, letter: str): | 42 | def __matmul__(self, letter: str): | ||
| 43 | """Predefined operator @ when a kid writes a letter to Santa.""" | 43 | """Predefined operator @ when a kid writes a letter to Santa.""" | ||
| 44 | gift = self.extract_gift(letter) | 44 | gift = self.extract_gift(letter) | ||
| 45 | signature = self.extract_signature_from_letter(letter) | 45 | signature = self.extract_signature_from_letter(letter) | ||
| 46 | 46 | ||||
| 47 | index = int(signature) | 47 | index = int(signature) | ||
| 48 | self.gifts[index] = gift | 48 | self.gifts[index] = gift | ||
| 49 | self.all_kids.add(index) | 49 | self.all_kids.add(index) | ||
| 50 | self.kids_ages[index] = 0 | 50 | self.kids_ages[index] = 0 | ||
| 51 | if id(signature) in self.kids_objects: | 51 | if id(signature) in self.kids_objects: | ||
| 52 | self.kids_objects[signature] = signature | 52 | self.kids_objects[signature] = signature | ||
| 53 | 53 | ||||
| 54 | def __call__(self, child, wish: str): | 54 | def __call__(self, child, wish: str): | ||
| 55 | """Predefined operator () when a kid calls Santa.""" | 55 | """Predefined operator () when a kid calls Santa.""" | ||
| 56 | index = id(child) | 56 | index = id(child) | ||
| 57 | self.gifts[index] = self.extract_gift(wish) | 57 | self.gifts[index] = self.extract_gift(wish) | ||
| 58 | 58 | ||||
| 59 | def __iter__(self): | 59 | def __iter__(self): | ||
| 60 | return iter(self.gifts.values()) | 60 | return iter(self.gifts.values()) | ||
| 61 | 61 | ||||
| 62 | def get_most_wanted_gift_this_year(self): | 62 | def get_most_wanted_gift_this_year(self): | ||
| 63 | """Calculates what is the most wanted gift this year.""" | 63 | """Calculates what is the most wanted gift this year.""" | ||
| 64 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | 64 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | ||
| 65 | 65 | ||||
| 66 | if set(this_years_gifts): | 66 | if set(this_years_gifts): | ||
| 67 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | 67 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | ||
| 68 | else: | 68 | else: | ||
| 69 | most_wanted_gift_this_year = None | 69 | most_wanted_gift_this_year = None | ||
| 70 | return most_wanted_gift_this_year | 70 | return most_wanted_gift_this_year | ||
| 71 | 71 | ||||
| 72 | def remove_kid(self, keys_to_delete): | 72 | def remove_kid(self, keys_to_delete): | ||
| 73 | """Deletes kid because it is too old for presents.""" | 73 | """Deletes kid because it is too old for presents.""" | ||
| 74 | for key in keys_to_delete: | 74 | for key in keys_to_delete: | ||
| 75 | del self.gifts[key] | 75 | del self.gifts[key] | ||
| 76 | del self.kids_ages[key] | 76 | del self.kids_ages[key] | ||
| 77 | del self.kids_objects[key] | 77 | del self.kids_objects[key] | ||
| 78 | self.all_kids.remove(key) | 78 | self.all_kids.remove(key) | ||
| 79 | 79 | ||||
| 80 | def mark_as_naughty(self, kid): | 80 | def mark_as_naughty(self, kid): | ||
| 81 | """Marks a kid as naughty.""" | 81 | """Marks a kid as naughty.""" | ||
| 82 | if id(kid) in self.all_kids: | 82 | if id(kid) in self.all_kids: | ||
| 83 | self.naughty_kids.add(id(kid)) | 83 | self.naughty_kids.add(id(kid)) | ||
| 84 | 84 | ||||
| 85 | def xmas(self): | 85 | def xmas(self): | ||
| 86 | """Time for presents.""" | 86 | """Time for presents.""" | ||
| 87 | for key in self.kids_ages: | 87 | for key in self.kids_ages: | ||
| 88 | self.kids_ages[key] += 1 | 88 | self.kids_ages[key] += 1 | ||
| 89 | 89 | ||||
| 90 | most_wanted_gift = self.get_most_wanted_gift_this_year() | 90 | most_wanted_gift = self.get_most_wanted_gift_this_year() | ||
| 91 | keys_to_delete = [] | 91 | keys_to_delete = [] | ||
| 92 | 92 | ||||
| 93 | for kid, age in self.kids_ages.items(): | 93 | for kid, age in self.kids_ages.items(): | ||
| 94 | cur_gift = self.gifts[kid] | 94 | cur_gift = self.gifts[kid] | ||
| 95 | if age > 5: | 95 | if age > 5: | ||
| 96 | keys_to_delete.append(kid) | 96 | keys_to_delete.append(kid) | ||
| 97 | continue | 97 | continue | ||
| 98 | elif age <= 5: | 98 | elif age <= 5: | ||
| 99 | kid_obj = self.kids_objects.get(kid) | 99 | kid_obj = self.kids_objects.get(kid) | ||
| t | 100 | if kid in self.naughty_kids: | t | 100 | if kid in self.naughty_kids and not all(value == None for value in self.gifts.values()): |
| 101 | kid_obj("coal") | 101 | kid_obj("coal") | ||
| 102 | elif cur_gift is None: | 102 | elif cur_gift is None: | ||
| 103 | kid_obj(most_wanted_gift) | 103 | kid_obj(most_wanted_gift) | ||
| 104 | else: | 104 | else: | ||
| 105 | kid_obj(cur_gift) | 105 | kid_obj(cur_gift) | ||
| 106 | 106 | ||||
| 107 | for cur_gift in self.gifts: | 107 | for cur_gift in self.gifts: | ||
| 108 | self.gifts[cur_gift] = None | 108 | self.gifts[cur_gift] = None | ||
| 109 | 109 | ||||
| 110 | self.remove_kid(keys_to_delete) | 110 | self.remove_kid(keys_to_delete) | ||
| 111 | self.naughty_kids.clear() | 111 | self.naughty_kids.clear() | ||
| 112 | 112 | ||||
| 113 | 113 | ||||
| 114 | def detect_naughty_kid(func): | 114 | def detect_naughty_kid(func): | ||
| 115 | """Checks if the kid is naughty.""" | 115 | """Checks if the kid is naughty.""" | ||
| 116 | def wrapper(self, *args, **kwargs): | 116 | def wrapper(self, *args, **kwargs): | ||
| 117 | try: | 117 | try: | ||
| 118 | return func(self, *args, **kwargs) | 118 | return func(self, *args, **kwargs) | ||
| 119 | except Exception: | 119 | except Exception: | ||
| 120 | Santa().mark_as_naughty(self) | 120 | Santa().mark_as_naughty(self) | ||
| 121 | raise | 121 | raise | ||
| 122 | return wrapper | 122 | return wrapper | ||
| 123 | 123 | ||||
| 124 | 124 | ||||
| 125 | class Kid(type): | 125 | class Kid(type): | ||
| 126 | """A class that defines a kid.""" | 126 | """A class that defines a kid.""" | ||
| 127 | def __new__(mcs, name, bases, attrs): | 127 | def __new__(mcs, name, bases, attrs): | ||
| 128 | if '__call__' not in attrs: | 128 | if '__call__' not in attrs: | ||
| 129 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | 129 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | ||
| 130 | for key, value in attrs.items(): | 130 | for key, value in attrs.items(): | ||
| 131 | if callable(value) and not key.startswith("_"): | 131 | if callable(value) and not key.startswith("_"): | ||
| 132 | attrs[key] = detect_naughty_kid(value) | 132 | attrs[key] = detect_naughty_kid(value) | ||
| 133 | return super().__new__(mcs, name, bases, attrs) | 133 | return super().__new__(mcs, name, bases, attrs) | ||
| 134 | 134 | ||||
| 135 | def __call__(cls, *args, **kwargs): | 135 | def __call__(cls, *args, **kwargs): | ||
| 136 | instance = super().__call__(*args, **kwargs) | 136 | instance = super().__call__(*args, **kwargs) | ||
| 137 | if id(instance) not in Santa().all_kids: | 137 | if id(instance) not in Santa().all_kids: | ||
| 138 | Santa().all_kids.add(id(instance)) | 138 | Santa().all_kids.add(id(instance)) | ||
| 139 | Santa().gifts[id(instance)] = None | 139 | Santa().gifts[id(instance)] = None | ||
| 140 | Santa().kids_ages[id(instance)] = 0 | 140 | Santa().kids_ages[id(instance)] = 0 | ||
| 141 | Santa().kids_objects[id(instance)] = instance | 141 | Santa().kids_objects[id(instance)] = instance | ||
| 142 | return instance | 142 | return instance |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import re | f | 1 | import re |
| 2 | 2 | ||||
| 3 | class SingletonType(type): | 3 | class SingletonType(type): | ||
| 4 | def __new__(mcs, name, bases, attrs): | 4 | def __new__(mcs, name, bases, attrs): | ||
| 5 | def singleton_new(cls): | 5 | def singleton_new(cls): | ||
| 6 | if not hasattr(cls, 'instance'): | 6 | if not hasattr(cls, 'instance'): | ||
| 7 | cls.instance = object.__new__(cls) | 7 | cls.instance = object.__new__(cls) | ||
| 8 | return cls.instance | 8 | return cls.instance | ||
| 9 | attrs['__new__'] = singleton_new | 9 | attrs['__new__'] = singleton_new | ||
| 10 | return type.__new__(mcs, name, bases, attrs) | 10 | return type.__new__(mcs, name, bases, attrs) | ||
| 11 | 11 | ||||
| 12 | 12 | ||||
| 13 | class Santa(metaclass = SingletonType): | 13 | class Santa(metaclass = SingletonType): | ||
| 14 | """A class for greedy kids.""" | 14 | """A class for greedy kids.""" | ||
| 15 | all_kids = set() | 15 | all_kids = set() | ||
| 16 | kids_objects = {} | 16 | kids_objects = {} | ||
| 17 | kids_ages = {} | 17 | kids_ages = {} | ||
| 18 | gifts = {} | 18 | gifts = {} | ||
| 19 | naughty_kids = set() | 19 | naughty_kids = set() | ||
| 20 | 20 | ||||
| 21 | def extract_gift(self, letter: str): | 21 | def extract_gift(self, letter: str): | ||
| 22 | """Extracts a gift from a letter or call.""" | 22 | """Extracts a gift from a letter or call.""" | ||
| 23 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | 23 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | ||
| 24 | pattern = re.compile(pattern_gift, re.MULTILINE) | 24 | pattern = re.compile(pattern_gift, re.MULTILINE) | ||
| 25 | gifts = pattern.findall(letter) | 25 | gifts = pattern.findall(letter) | ||
| 26 | 26 | ||||
| 27 | for gift_tuple in reversed(gifts): | 27 | for gift_tuple in reversed(gifts): | ||
| 28 | for gift in gift_tuple: | 28 | for gift in gift_tuple: | ||
| 29 | if gift: | 29 | if gift: | ||
| 30 | return gift | 30 | return gift | ||
| 31 | return None | 31 | return None | ||
| 32 | 32 | ||||
| 33 | def extract_signature_from_letter(self, letter: str): | 33 | def extract_signature_from_letter(self, letter: str): | ||
| 34 | """Extracts a signiture from a letter.""" | 34 | """Extracts a signiture from a letter.""" | ||
| 35 | pattern_signature = r'\s*(\d+)\s*' | 35 | pattern_signature = r'\s*(\d+)\s*' | ||
| 36 | pattern = re.compile(pattern_signature, re.MULTILINE) | 36 | pattern = re.compile(pattern_signature, re.MULTILINE) | ||
| 37 | signature = pattern.findall(letter) | 37 | signature = pattern.findall(letter) | ||
| 38 | if signature: | 38 | if signature: | ||
| 39 | return signature[-1] | 39 | return signature[-1] | ||
| 40 | return None | 40 | return None | ||
| 41 | 41 | ||||
| 42 | def __matmul__(self, letter: str): | 42 | def __matmul__(self, letter: str): | ||
| 43 | """Predefined operator @ when a kid writes a letter to Santa.""" | 43 | """Predefined operator @ when a kid writes a letter to Santa.""" | ||
| 44 | gift = self.extract_gift(letter) | 44 | gift = self.extract_gift(letter) | ||
| 45 | signature = self.extract_signature_from_letter(letter) | 45 | signature = self.extract_signature_from_letter(letter) | ||
| t | 46 | t | 46 | ||
| 47 | index = int(signature) | 47 | index = int(signature) | ||
| 48 | self.gifts[index] = gift | 48 | self.gifts[index] = gift | ||
| 49 | self.all_kids.add(index) | 49 | self.all_kids.add(index) | ||
| 50 | self.kids_ages[index] = 0 | 50 | self.kids_ages[index] = 0 | ||
| 51 | if id(signature) in self.kids_objects: | 51 | if id(signature) in self.kids_objects: | ||
| 52 | self.kids_objects[signature] = signature | 52 | self.kids_objects[signature] = signature | ||
| 53 | 53 | ||||
| 54 | def __call__(self, child, wish: str): | 54 | def __call__(self, child, wish: str): | ||
| 55 | """Predefined operator () when a kid calls Santa.""" | 55 | """Predefined operator () when a kid calls Santa.""" | ||
| 56 | index = id(child) | 56 | index = id(child) | ||
| 57 | self.gifts[index] = self.extract_gift(wish) | 57 | self.gifts[index] = self.extract_gift(wish) | ||
| 58 | 58 | ||||
| 59 | def __iter__(self): | 59 | def __iter__(self): | ||
| 60 | return iter(self.gifts.values()) | 60 | return iter(self.gifts.values()) | ||
| 61 | 61 | ||||
| 62 | def get_most_wanted_gift_this_year(self): | 62 | def get_most_wanted_gift_this_year(self): | ||
| 63 | """Calculates what is the most wanted gift this year.""" | 63 | """Calculates what is the most wanted gift this year.""" | ||
| 64 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | 64 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | ||
| 65 | 65 | ||||
| 66 | if set(this_years_gifts): | 66 | if set(this_years_gifts): | ||
| 67 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | 67 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | ||
| 68 | else: | 68 | else: | ||
| 69 | most_wanted_gift_this_year = None | 69 | most_wanted_gift_this_year = None | ||
| 70 | return most_wanted_gift_this_year | 70 | return most_wanted_gift_this_year | ||
| 71 | 71 | ||||
| 72 | def remove_kid(self, keys_to_delete): | 72 | def remove_kid(self, keys_to_delete): | ||
| 73 | """Deletes kid because it is too old for presents.""" | 73 | """Deletes kid because it is too old for presents.""" | ||
| 74 | for key in keys_to_delete: | 74 | for key in keys_to_delete: | ||
| 75 | del self.gifts[key] | 75 | del self.gifts[key] | ||
| 76 | del self.kids_ages[key] | 76 | del self.kids_ages[key] | ||
| 77 | del self.kids_objects[key] | 77 | del self.kids_objects[key] | ||
| 78 | self.all_kids.remove(key) | 78 | self.all_kids.remove(key) | ||
| 79 | 79 | ||||
| 80 | def mark_as_naughty(self, kid): | 80 | def mark_as_naughty(self, kid): | ||
| 81 | """Marks a kid as naughty.""" | 81 | """Marks a kid as naughty.""" | ||
| 82 | if id(kid) in self.all_kids: | 82 | if id(kid) in self.all_kids: | ||
| 83 | self.naughty_kids.add(id(kid)) | 83 | self.naughty_kids.add(id(kid)) | ||
| 84 | 84 | ||||
| 85 | def xmas(self): | 85 | def xmas(self): | ||
| 86 | """Time for presents.""" | 86 | """Time for presents.""" | ||
| 87 | for key in self.kids_ages: | 87 | for key in self.kids_ages: | ||
| 88 | self.kids_ages[key] += 1 | 88 | self.kids_ages[key] += 1 | ||
| 89 | 89 | ||||
| 90 | most_wanted_gift = self.get_most_wanted_gift_this_year() | 90 | most_wanted_gift = self.get_most_wanted_gift_this_year() | ||
| 91 | keys_to_delete = [] | 91 | keys_to_delete = [] | ||
| 92 | 92 | ||||
| 93 | for kid, age in self.kids_ages.items(): | 93 | for kid, age in self.kids_ages.items(): | ||
| 94 | cur_gift = self.gifts[kid] | 94 | cur_gift = self.gifts[kid] | ||
| 95 | if age > 5: | 95 | if age > 5: | ||
| 96 | keys_to_delete.append(kid) | 96 | keys_to_delete.append(kid) | ||
| 97 | continue | 97 | continue | ||
| 98 | elif age <= 5: | 98 | elif age <= 5: | ||
| 99 | kid_obj = self.kids_objects.get(kid) | 99 | kid_obj = self.kids_objects.get(kid) | ||
| 100 | if kid in self.naughty_kids: | 100 | if kid in self.naughty_kids: | ||
| 101 | kid_obj("coal") | 101 | kid_obj("coal") | ||
| 102 | elif cur_gift is None: | 102 | elif cur_gift is None: | ||
| 103 | kid_obj(most_wanted_gift) | 103 | kid_obj(most_wanted_gift) | ||
| 104 | else: | 104 | else: | ||
| 105 | kid_obj(cur_gift) | 105 | kid_obj(cur_gift) | ||
| 106 | 106 | ||||
| 107 | for cur_gift in self.gifts: | 107 | for cur_gift in self.gifts: | ||
| 108 | self.gifts[cur_gift] = None | 108 | self.gifts[cur_gift] = None | ||
| 109 | 109 | ||||
| 110 | self.remove_kid(keys_to_delete) | 110 | self.remove_kid(keys_to_delete) | ||
| 111 | self.naughty_kids.clear() | 111 | self.naughty_kids.clear() | ||
| 112 | 112 | ||||
| 113 | 113 | ||||
| 114 | def detect_naughty_kid(func): | 114 | def detect_naughty_kid(func): | ||
| 115 | """Checks if the kid is naughty.""" | 115 | """Checks if the kid is naughty.""" | ||
| 116 | def wrapper(self, *args, **kwargs): | 116 | def wrapper(self, *args, **kwargs): | ||
| 117 | try: | 117 | try: | ||
| 118 | return func(self, *args, **kwargs) | 118 | return func(self, *args, **kwargs) | ||
| 119 | except Exception: | 119 | except Exception: | ||
| 120 | Santa().mark_as_naughty(self) | 120 | Santa().mark_as_naughty(self) | ||
| 121 | raise | 121 | raise | ||
| 122 | return wrapper | 122 | return wrapper | ||
| 123 | 123 | ||||
| 124 | 124 | ||||
| 125 | class Kid(type): | 125 | class Kid(type): | ||
| 126 | """A class that defines a kid.""" | 126 | """A class that defines a kid.""" | ||
| 127 | def __new__(mcs, name, bases, attrs): | 127 | def __new__(mcs, name, bases, attrs): | ||
| 128 | if '__call__' not in attrs: | 128 | if '__call__' not in attrs: | ||
| 129 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | 129 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | ||
| 130 | for key, value in attrs.items(): | 130 | for key, value in attrs.items(): | ||
| 131 | if callable(value) and not key.startswith("_"): | 131 | if callable(value) and not key.startswith("_"): | ||
| 132 | attrs[key] = detect_naughty_kid(value) | 132 | attrs[key] = detect_naughty_kid(value) | ||
| 133 | return super().__new__(mcs, name, bases, attrs) | 133 | return super().__new__(mcs, name, bases, attrs) | ||
| 134 | 134 | ||||
| 135 | def __call__(cls, *args, **kwargs): | 135 | def __call__(cls, *args, **kwargs): | ||
| 136 | instance = super().__call__(*args, **kwargs) | 136 | instance = super().__call__(*args, **kwargs) | ||
| 137 | if id(instance) not in Santa().all_kids: | 137 | if id(instance) not in Santa().all_kids: | ||
| 138 | Santa().all_kids.add(id(instance)) | 138 | Santa().all_kids.add(id(instance)) | ||
| 139 | Santa().gifts[id(instance)] = None | 139 | Santa().gifts[id(instance)] = None | ||
| 140 | Santa().kids_ages[id(instance)] = 0 | 140 | Santa().kids_ages[id(instance)] = 0 | ||
| 141 | Santa().kids_objects[id(instance)] = instance | 141 | Santa().kids_objects[id(instance)] = instance | ||
| 142 | return instance | 142 | return instance |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
| f | 1 | import re | f | 1 | import re |
| 2 | 2 | ||||
| 3 | class SingletonType(type): | 3 | class SingletonType(type): | ||
| 4 | def __new__(mcs, name, bases, attrs): | 4 | def __new__(mcs, name, bases, attrs): | ||
| 5 | def singleton_new(cls): | 5 | def singleton_new(cls): | ||
| 6 | if not hasattr(cls, 'instance'): | 6 | if not hasattr(cls, 'instance'): | ||
| 7 | cls.instance = object.__new__(cls) | 7 | cls.instance = object.__new__(cls) | ||
| 8 | return cls.instance | 8 | return cls.instance | ||
| 9 | attrs['__new__'] = singleton_new | 9 | attrs['__new__'] = singleton_new | ||
| 10 | return type.__new__(mcs, name, bases, attrs) | 10 | return type.__new__(mcs, name, bases, attrs) | ||
| 11 | 11 | ||||
| 12 | 12 | ||||
| 13 | class Santa(metaclass = SingletonType): | 13 | class Santa(metaclass = SingletonType): | ||
| 14 | """A class for greedy kids.""" | 14 | """A class for greedy kids.""" | ||
| 15 | all_kids = set() | 15 | all_kids = set() | ||
| n | n | 16 | kids_objects = {} | ||
| 16 | kids_ages = {} | 17 | kids_ages = {} | ||
| 17 | gifts = {} | 18 | gifts = {} | ||
| 18 | naughty_kids = set() | 19 | naughty_kids = set() | ||
| 19 | 20 | ||||
| 20 | def extract_gift(self, letter: str): | 21 | def extract_gift(self, letter: str): | ||
| 21 | """Extracts a gift from a letter or call.""" | 22 | """Extracts a gift from a letter or call.""" | ||
| 22 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | 23 | pattern_gift = r'(?:\")([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\")|(?:\')([A-Za-z0-9]+[A-Za-z0-9 ]*)(?:\')' | ||
| 23 | pattern = re.compile(pattern_gift, re.MULTILINE) | 24 | pattern = re.compile(pattern_gift, re.MULTILINE) | ||
| 24 | gifts = pattern.findall(letter) | 25 | gifts = pattern.findall(letter) | ||
| 25 | 26 | ||||
| 26 | for gift_tuple in reversed(gifts): | 27 | for gift_tuple in reversed(gifts): | ||
| 27 | for gift in gift_tuple: | 28 | for gift in gift_tuple: | ||
| 28 | if gift: | 29 | if gift: | ||
| 29 | return gift | 30 | return gift | ||
| 30 | return None | 31 | return None | ||
| 31 | 32 | ||||
| 32 | def extract_signature_from_letter(self, letter: str): | 33 | def extract_signature_from_letter(self, letter: str): | ||
| 33 | """Extracts a signiture from a letter.""" | 34 | """Extracts a signiture from a letter.""" | ||
| 34 | pattern_signature = r'\s*(\d+)\s*' | 35 | pattern_signature = r'\s*(\d+)\s*' | ||
| 35 | pattern = re.compile(pattern_signature, re.MULTILINE) | 36 | pattern = re.compile(pattern_signature, re.MULTILINE) | ||
| 36 | signature = pattern.findall(letter) | 37 | signature = pattern.findall(letter) | ||
| 37 | if signature: | 38 | if signature: | ||
| 38 | return signature[-1] | 39 | return signature[-1] | ||
| 39 | return None | 40 | return None | ||
| 40 | 41 | ||||
| 41 | def __matmul__(self, letter: str): | 42 | def __matmul__(self, letter: str): | ||
| 42 | """Predefined operator @ when a kid writes a letter to Santa.""" | 43 | """Predefined operator @ when a kid writes a letter to Santa.""" | ||
| 43 | gift = self.extract_gift(letter) | 44 | gift = self.extract_gift(letter) | ||
| 44 | signature = self.extract_signature_from_letter(letter) | 45 | signature = self.extract_signature_from_letter(letter) | ||
| n | 45 | n | 46 | ||
| 46 | index = int(signature) | 47 | index = int(signature) | ||
| 47 | self.gifts[index] = gift | 48 | self.gifts[index] = gift | ||
| 48 | self.all_kids.add(index) | 49 | self.all_kids.add(index) | ||
| 49 | self.kids_ages[index] = 0 | 50 | self.kids_ages[index] = 0 | ||
| n | n | 51 | if id(signature) in self.kids_objects: | ||
| 52 | self.kids_objects[signature] = signature | ||||
| 50 | 53 | ||||
| 51 | def __call__(self, child, wish: str): | 54 | def __call__(self, child, wish: str): | ||
| 52 | """Predefined operator () when a kid calls Santa.""" | 55 | """Predefined operator () when a kid calls Santa.""" | ||
| 53 | index = id(child) | 56 | index = id(child) | ||
| 54 | self.gifts[index] = self.extract_gift(wish) | 57 | self.gifts[index] = self.extract_gift(wish) | ||
| 55 | 58 | ||||
| 56 | def __iter__(self): | 59 | def __iter__(self): | ||
| 57 | return iter(self.gifts.values()) | 60 | return iter(self.gifts.values()) | ||
| 58 | 61 | ||||
| 59 | def get_most_wanted_gift_this_year(self): | 62 | def get_most_wanted_gift_this_year(self): | ||
| 60 | """Calculates what is the most wanted gift this year.""" | 63 | """Calculates what is the most wanted gift this year.""" | ||
| 61 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | 64 | this_years_gifts = [gift for gift in self.gifts.values() if gift is not None] | ||
| 62 | 65 | ||||
| 63 | if set(this_years_gifts): | 66 | if set(this_years_gifts): | ||
| 64 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | 67 | most_wanted_gift_this_year = max(set(this_years_gifts) , key = this_years_gifts.count) | ||
| 65 | else: | 68 | else: | ||
| 66 | most_wanted_gift_this_year = None | 69 | most_wanted_gift_this_year = None | ||
| 67 | return most_wanted_gift_this_year | 70 | return most_wanted_gift_this_year | ||
| 68 | 71 | ||||
| 69 | def remove_kid(self, keys_to_delete): | 72 | def remove_kid(self, keys_to_delete): | ||
| 70 | """Deletes kid because it is too old for presents.""" | 73 | """Deletes kid because it is too old for presents.""" | ||
| 71 | for key in keys_to_delete: | 74 | for key in keys_to_delete: | ||
| 72 | del self.gifts[key] | 75 | del self.gifts[key] | ||
| 73 | del self.kids_ages[key] | 76 | del self.kids_ages[key] | ||
| n | n | 77 | del self.kids_objects[key] | ||
| 74 | self.all_kids.remove(key) | 78 | self.all_kids.remove(key) | ||
| 75 | 79 | ||||
| 76 | def mark_as_naughty(self, kid): | 80 | def mark_as_naughty(self, kid): | ||
| 77 | """Marks a kid as naughty.""" | 81 | """Marks a kid as naughty.""" | ||
| 78 | if id(kid) in self.all_kids: | 82 | if id(kid) in self.all_kids: | ||
| 79 | self.naughty_kids.add(id(kid)) | 83 | self.naughty_kids.add(id(kid)) | ||
| 80 | 84 | ||||
| 81 | def xmas(self): | 85 | def xmas(self): | ||
| 82 | """Time for presents.""" | 86 | """Time for presents.""" | ||
| 83 | for key in self.kids_ages: | 87 | for key in self.kids_ages: | ||
| 84 | self.kids_ages[key] += 1 | 88 | self.kids_ages[key] += 1 | ||
| 85 | 89 | ||||
| 86 | most_wanted_gift = self.get_most_wanted_gift_this_year() | 90 | most_wanted_gift = self.get_most_wanted_gift_this_year() | ||
| 87 | keys_to_delete = [] | 91 | keys_to_delete = [] | ||
| 88 | 92 | ||||
| 89 | for kid, age in self.kids_ages.items(): | 93 | for kid, age in self.kids_ages.items(): | ||
| 90 | cur_gift = self.gifts[kid] | 94 | cur_gift = self.gifts[kid] | ||
| 91 | if age > 5: | 95 | if age > 5: | ||
| 92 | keys_to_delete.append(kid) | 96 | keys_to_delete.append(kid) | ||
| 93 | continue | 97 | continue | ||
| 94 | elif age <= 5: | 98 | elif age <= 5: | ||
| n | n | 99 | kid_obj = self.kids_objects.get(kid) | ||
| 95 | if kid in self.naughty_kids: | 100 | if kid in self.naughty_kids: | ||
| n | 96 | cur_gift = "coal" | n | 101 | kid_obj("coal") |
| 97 | elif cur_gift is None: | 102 | elif cur_gift is None: | ||
| n | 98 | cur_gift = most_wanted_gift | n | 103 | kid_obj(most_wanted_gift) |
| 99 | # print(f"{kid} получава {cur_gift}.") | 104 | else: | ||
| 100 | cur_gift = None | 105 | kid_obj(cur_gift) | ||
| 101 | 106 | ||||
| 102 | for cur_gift in self.gifts: | 107 | for cur_gift in self.gifts: | ||
| 103 | self.gifts[cur_gift] = None | 108 | self.gifts[cur_gift] = None | ||
| 104 | 109 | ||||
| 105 | self.remove_kid(keys_to_delete) | 110 | self.remove_kid(keys_to_delete) | ||
| 106 | self.naughty_kids.clear() | 111 | self.naughty_kids.clear() | ||
| 107 | 112 | ||||
| 108 | 113 | ||||
| 109 | def detect_naughty_kid(func): | 114 | def detect_naughty_kid(func): | ||
| 110 | """Checks if the kid is naughty.""" | 115 | """Checks if the kid is naughty.""" | ||
| 111 | def wrapper(self, *args, **kwargs): | 116 | def wrapper(self, *args, **kwargs): | ||
| 112 | try: | 117 | try: | ||
| 113 | return func(self, *args, **kwargs) | 118 | return func(self, *args, **kwargs) | ||
| 114 | except Exception: | 119 | except Exception: | ||
| 115 | Santa().mark_as_naughty(self) | 120 | Santa().mark_as_naughty(self) | ||
| 116 | raise | 121 | raise | ||
| 117 | return wrapper | 122 | return wrapper | ||
| 118 | 123 | ||||
| 119 | 124 | ||||
| 120 | class Kid(type): | 125 | class Kid(type): | ||
| 121 | """A class that defines a kid.""" | 126 | """A class that defines a kid.""" | ||
| 122 | def __new__(mcs, name, bases, attrs): | 127 | def __new__(mcs, name, bases, attrs): | ||
| 123 | if '__call__' not in attrs: | 128 | if '__call__' not in attrs: | ||
| 124 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | 129 | raise NotImplementedError("Sorry, you should implement the __call__ method of the kid :).") | ||
| 125 | for key, value in attrs.items(): | 130 | for key, value in attrs.items(): | ||
| 126 | if callable(value) and not key.startswith("_"): | 131 | if callable(value) and not key.startswith("_"): | ||
| 127 | attrs[key] = detect_naughty_kid(value) | 132 | attrs[key] = detect_naughty_kid(value) | ||
| 128 | return super().__new__(mcs, name, bases, attrs) | 133 | return super().__new__(mcs, name, bases, attrs) | ||
| 129 | 134 | ||||
| 130 | def __call__(cls, *args, **kwargs): | 135 | def __call__(cls, *args, **kwargs): | ||
| 131 | instance = super().__call__(*args, **kwargs) | 136 | instance = super().__call__(*args, **kwargs) | ||
| 132 | if id(instance) not in Santa().all_kids: | 137 | if id(instance) not in Santa().all_kids: | ||
| 133 | Santa().all_kids.add(id(instance)) | 138 | Santa().all_kids.add(id(instance)) | ||
| 134 | Santa().gifts[id(instance)] = None | 139 | Santa().gifts[id(instance)] = None | ||
| 135 | Santa().kids_ages[id(instance)] = 0 | 140 | Santa().kids_ages[id(instance)] = 0 | ||
| t | t | 141 | Santa().kids_objects[id(instance)] = instance | ||
| 136 | return instance | 142 | return instance |
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||