1import re
2from collections import defaultdict
3from random import choice
4
5
6class Singleton(type):
7 class_instances = {}
8
9 def __call__(cls, *args, **kwargs):
10 if cls not in cls.class_instances:
11 cls.class_instances[cls] = super().__call__(*args, **kwargs)
12 return cls.class_instances[cls]
13
14
15class Santa(metaclass=Singleton):
16 def __init__(self):
17 self.gifts = {}
18 self.count_of_xmases = defaultdict(int)
19 self.gifts_count = defaultdict(int)
20 self.naughty_kids = set()
21
22 def __call__(self, kid_instance, message):
23 wish = self.__extract_wish(message)
24 self.gifts[kid_instance] = wish
25 self.gifts_count[wish] += 1
26
27 def __matmul__(self, letter):
28 wish = self.__extract_wish(letter)
29 kid_id = int(self.__extract_signature(letter))
30 kid = Kid.created_kids.get(kid_id)
31 self.gifts[kid] = wish
32 self.gifts_count[wish] += 1
33
34 def __iter__(self):
35 for gift in self.gifts.values():
36 yield gift
37
38 def choose_random_default_gift(self):
39 curr_gift_count = 0
40 most_wished_gifts = []
41 for gift, count in self.gifts_count.items():
42 if count > curr_gift_count:
43 curr_gift_count = count
44 most_wished_gifts = [gift]
45 elif count == curr_gift_count:
46 most_wished_gifts.append(gift)
47 return most_wished_gifts
48
49 def reset_christmas(self):
50 # Reset gifts values for the new Christmas + incrementing the xmas count by 1
51 for kid in self.gifts.keys():
52 self.gifts[kid] = ""
53 self.count_of_xmases[kid] += 1
54
55 def xmas(self):
56 if all(count == 0 for count in self.gifts_count.values()):
57 self.reset_christmas()
58 return
59
60 most_wished_gifts = self.choose_random_default_gift()
61 default_gift = choice(most_wished_gifts) if most_wished_gifts else None
62
63 for kid, gift in self.gifts.items():
64 if self.count_of_xmases[kid] >= 5:
65 continue
66
67 if kid in self.naughty_kids:
68 kid("coal")
69 else:
70 if gift == "":
71 final_gift = default_gift
72 else:
73 final_gift = gift
74
75 if final_gift:
76 kid(final_gift)
77
78 self.reset_christmas()
79 self.naughty_kids.clear()
80 self.gifts_count = defaultdict(int)
81
82 @staticmethod
83 def __extract_wish(message):
84 match = re.search(r'["\']([a-zA-Z0-9 ]+)["\']', message)
85 return match.group(1)
86
87 @staticmethod
88 def __extract_signature(message):
89 match = re.search(r'^\s*(\d+)\s*$', message, re.MULTILINE)
90 return match.group(1)
91
92
93class Kid(type):
94 created_kids = {}
95
96 @classmethod
97 def is_naughty(cls, method):
98 def wrapper(self, *args, **kwargs):
99 try:
100 return method(self, *args, **kwargs)
101 except Exception:
102 Santa().naughty_kids.add(self)
103 raise
104 return wrapper
105
106 def __new__(cls, name, bases, dct):
107 if '__call__' not in dct:
108 raise NotImplementedError(
109 f"Tova meta dete/klas {name} neshto ne moje da se vika!")
110
111 for attr_name, attr_value in dct.items():
112 if callable(attr_value) and not attr_name.startswith("_"):
113 dct[attr_name] = cls.is_naughty(attr_value)
114 return super().__new__(cls, name, bases, dct)
115
116 def __call__(cls, *args, **kwargs):
117 instance = super().__call__(*args, **kwargs)
118 # Saving the (id -> kid) pair of each created kid for an easier access later in __matmul__
119 Kid.created_kids[id(instance)] = instance
120
121 # Set default value to each created kid
122 santa = Santa()
123 if instance not in santa.gifts:
124 santa.gifts[instance] = ""
125 return instance
.......F............
======================================================================
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.030s
FAILED (failures=1)
Виктор Бечев
16.12.2024 00:24Да, Дядо Коледа дава нов шанс на всички всяка Коледа.
|
Василена Станойска
15.12.2024 21:33Може ли да попитам само, когато едно дете е било непослушно например първата година, то следващата вече си е послушно и може да получава подарък различен от "coal", нали?
|
f | 1 | import re | f | 1 | import re |
n | n | 2 | from collections import defaultdict | ||
2 | from random import choice | 3 | from random import choice | ||
n | 3 | from collections import defaultdict | n | ||
4 | 4 | ||||
5 | 5 | ||||
6 | class Singleton(type): | 6 | class Singleton(type): | ||
7 | class_instances = {} | 7 | class_instances = {} | ||
8 | 8 | ||||
9 | def __call__(cls, *args, **kwargs): | 9 | def __call__(cls, *args, **kwargs): | ||
10 | if cls not in cls.class_instances: | 10 | if cls not in cls.class_instances: | ||
11 | cls.class_instances[cls] = super().__call__(*args, **kwargs) | 11 | cls.class_instances[cls] = super().__call__(*args, **kwargs) | ||
12 | return cls.class_instances[cls] | 12 | return cls.class_instances[cls] | ||
13 | 13 | ||||
14 | 14 | ||||
15 | class Santa(metaclass=Singleton): | 15 | class Santa(metaclass=Singleton): | ||
16 | def __init__(self): | 16 | def __init__(self): | ||
17 | self.gifts = {} | 17 | self.gifts = {} | ||
18 | self.count_of_xmases = defaultdict(int) | 18 | self.count_of_xmases = defaultdict(int) | ||
19 | self.gifts_count = defaultdict(int) | 19 | self.gifts_count = defaultdict(int) | ||
20 | self.naughty_kids = set() | 20 | self.naughty_kids = set() | ||
21 | 21 | ||||
22 | def __call__(self, kid_instance, message): | 22 | def __call__(self, kid_instance, message): | ||
n | 23 | wish = self.__extract_wish__(message) | n | 23 | wish = self.__extract_wish(message) |
24 | self.gifts[kid_instance] = wish | 24 | self.gifts[kid_instance] = wish | ||
25 | self.gifts_count[wish] += 1 | 25 | self.gifts_count[wish] += 1 | ||
26 | 26 | ||||
27 | def __matmul__(self, letter): | 27 | def __matmul__(self, letter): | ||
n | 28 | wish = self.__extract_wish__(letter) | n | 28 | wish = self.__extract_wish(letter) |
29 | kid_id = int(self.__extract_signature__(letter)) | 29 | kid_id = int(self.__extract_signature(letter)) | ||
30 | kid = Kid.created_kids.get(kid_id) | 30 | kid = Kid.created_kids.get(kid_id) | ||
31 | self.gifts[kid] = wish | 31 | self.gifts[kid] = wish | ||
32 | self.gifts_count[wish] += 1 | 32 | self.gifts_count[wish] += 1 | ||
33 | 33 | ||||
34 | def __iter__(self): | 34 | def __iter__(self): | ||
35 | for gift in self.gifts.values(): | 35 | for gift in self.gifts.values(): | ||
36 | yield gift | 36 | yield gift | ||
37 | 37 | ||||
n | 38 | def xmas(self): | n | 38 | def choose_random_default_gift(self): |
39 | if all(count == 0 for count in self.gifts_count.values()): | ||||
40 | # Reset gifts values for the new Christmas + incrementing the xmas count by 1 | ||||
41 | for kid in self.gifts.keys(): | ||||
42 | self.gifts[kid] = "" | ||||
43 | self.count_of_xmases[kid] += 1 | ||||
44 | return | ||||
45 | |||||
46 | curr_gift_count = 0 | 39 | curr_gift_count = 0 | ||
47 | most_wished_gifts = [] | 40 | most_wished_gifts = [] | ||
48 | for gift, count in self.gifts_count.items(): | 41 | for gift, count in self.gifts_count.items(): | ||
49 | if count > curr_gift_count: | 42 | if count > curr_gift_count: | ||
50 | curr_gift_count = count | 43 | curr_gift_count = count | ||
51 | most_wished_gifts = [gift] | 44 | most_wished_gifts = [gift] | ||
52 | elif count == curr_gift_count: | 45 | elif count == curr_gift_count: | ||
53 | most_wished_gifts.append(gift) | 46 | most_wished_gifts.append(gift) | ||
n | 54 | n | 47 | return most_wished_gifts | |
48 | |||||
49 | def reset_christmas(self): | ||||
50 | # Reset gifts values for the new Christmas + incrementing the xmas count by 1 | ||||
51 | for kid in self.gifts.keys(): | ||||
52 | self.gifts[kid] = "" | ||||
53 | self.count_of_xmases[kid] += 1 | ||||
54 | |||||
55 | def xmas(self): | ||||
56 | if all(count == 0 for count in self.gifts_count.values()): | ||||
57 | self.reset_christmas() | ||||
58 | return | ||||
59 | |||||
60 | most_wished_gifts = self.choose_random_default_gift() | ||||
55 | default_gift = choice(most_wished_gifts) if most_wished_gifts else None | 61 | default_gift = choice(most_wished_gifts) if most_wished_gifts else None | ||
n | n | 62 | |||
56 | for kid in list(self.gifts.keys()): | 63 | for kid, gift in self.gifts.items(): | ||
57 | if self.count_of_xmases[kid] >= 5: | 64 | if self.count_of_xmases[kid] >= 5: | ||
58 | continue | 65 | continue | ||
59 | 66 | ||||
60 | if kid in self.naughty_kids: | 67 | if kid in self.naughty_kids: | ||
61 | kid("coal") | 68 | kid("coal") | ||
62 | else: | 69 | else: | ||
n | 63 | if self.gifts[kid] == "": | n | 70 | if gift == "": |
64 | final_gift = default_gift | 71 | final_gift = default_gift | ||
65 | else: | 72 | else: | ||
n | 66 | final_gift = self.gifts[kid] | n | 73 | final_gift = gift |
67 | 74 | ||||
68 | if final_gift: | 75 | if final_gift: | ||
69 | kid(final_gift) | 76 | kid(final_gift) | ||
70 | 77 | ||||
n | 71 | # Reset gifts values for the new Christmas + incrementing the xmas count by 1 | n | 78 | self.reset_christmas() |
72 | for kid in self.gifts.keys(): | 79 | self.naughty_kids.clear() | ||
73 | self.gifts[kid] = "" | ||||
74 | self.count_of_xmases[kid] += 1 | ||||
75 | self.gifts_count = defaultdict(int) | 80 | self.gifts_count = defaultdict(int) | ||
76 | 81 | ||||
77 | @staticmethod | 82 | @staticmethod | ||
n | 78 | def __extract_wish__(message): | n | 83 | def __extract_wish(message): |
79 | match = re.search(r'["\']([a-zA-Z0-9 ]+)["\']', message) | 84 | match = re.search(r'["\']([a-zA-Z0-9 ]+)["\']', message) | ||
80 | return match.group(1) | 85 | return match.group(1) | ||
81 | 86 | ||||
82 | @staticmethod | 87 | @staticmethod | ||
n | 83 | def __extract_signature__(message): | n | 88 | def __extract_signature(message): |
84 | match = re.search(r'^\s*(\d+)\s*$', message, re.MULTILINE) | 89 | match = re.search(r'^\s*(\d+)\s*$', message, re.MULTILINE) | ||
85 | return match.group(1) | 90 | return match.group(1) | ||
86 | 91 | ||||
87 | 92 | ||||
88 | class Kid(type): | 93 | class Kid(type): | ||
89 | created_kids = {} | 94 | created_kids = {} | ||
90 | 95 | ||||
n | 91 | @staticmethod | n | 96 | @classmethod |
92 | def is_naughty(method): | 97 | def is_naughty(cls, method): | ||
93 | def wrapper(self, *args, **kwargs): | 98 | def wrapper(self, *args, **kwargs): | ||
94 | try: | 99 | try: | ||
95 | return method(self, *args, **kwargs) | 100 | return method(self, *args, **kwargs) | ||
96 | except Exception: | 101 | except Exception: | ||
97 | Santa().naughty_kids.add(self) | 102 | Santa().naughty_kids.add(self) | ||
98 | raise | 103 | raise | ||
99 | return wrapper | 104 | return wrapper | ||
100 | 105 | ||||
101 | def __new__(cls, name, bases, dct): | 106 | def __new__(cls, name, bases, dct): | ||
102 | if '__call__' not in dct: | 107 | if '__call__' not in dct: | ||
103 | raise NotImplementedError( | 108 | raise NotImplementedError( | ||
104 | f"Tova meta dete/klas {name} neshto ne moje da se vika!") | 109 | f"Tova meta dete/klas {name} neshto ne moje da se vika!") | ||
105 | 110 | ||||
106 | for attr_name, attr_value in dct.items(): | 111 | for attr_name, attr_value in dct.items(): | ||
107 | if callable(attr_value) and not attr_name.startswith("_"): | 112 | if callable(attr_value) and not attr_name.startswith("_"): | ||
t | 108 | dct[attr_name] = Kid.is_naughty(attr_value) | t | 113 | dct[attr_name] = cls.is_naughty(attr_value) |
109 | return super().__new__(cls, name, bases, dct) | 114 | return super().__new__(cls, name, bases, dct) | ||
110 | 115 | ||||
111 | def __call__(cls, *args, **kwargs): | 116 | def __call__(cls, *args, **kwargs): | ||
112 | instance = super().__call__(*args, **kwargs) | 117 | instance = super().__call__(*args, **kwargs) | ||
113 | # Saving the (id -> kid) pair of each created kid for an easier access later in __matmul__ | 118 | # Saving the (id -> kid) pair of each created kid for an easier access later in __matmul__ | ||
114 | Kid.created_kids[id(instance)] = instance | 119 | Kid.created_kids[id(instance)] = instance | ||
115 | 120 | ||||
116 | # Set default value to each created kid | 121 | # Set default value to each created kid | ||
117 | santa = Santa() | 122 | santa = Santa() | ||
118 | if instance not in santa.gifts: | 123 | if instance not in santa.gifts: | ||
119 | santa.gifts[instance] = "" | 124 | santa.gifts[instance] = "" | ||
120 | return instance | 125 | return instance |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|