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 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|