1import re
2import random
3
4MAX_KID_YEARS = 5
5class MetaClass(type):
6 _instances = {}
7 def __call__(cls, *args, **kwargs):
8 if cls not in cls._instances:
9 cls._instances[cls] = super().__call__(*args, **kwargs)
10 return cls._instances[cls]
11
12
13class Santa(metaclass=MetaClass):
14 def __init__(self):
15 self.wish_list = {}
16 self._wishes_order = []
17 self.kid_years = {}
18 self.child_behavior = {}
19 self.global_wish_counter = {}
20 self.gifts_count = {}
21 self.child_instances = {}
22
23 def register_child(self, child):
24 self.child_instances[id(child)] = child
25 self.child_behavior[id(child)] = True
26 for attr_name in dir(child):
27 if not attr_name.startswith("_") and callable(getattr(child, attr_name)):
28 method = getattr(child, attr_name)
29 wrapped_method = self.behavior_wrapper(method, id(child))
30 setattr(child, attr_name, wrapped_method)
31
32 def behavior_wrapper(self, method, child_id):
33 def wrapper(*args, **kwargs):
34 try:
35 return method(*args, **kwargs)
36 except Exception:
37 self.child_behavior[child_id] = False
38 raise
39 return wrapper
40
41 def get_child_by_id(self, child_id):
42 return self.child_instances.get(child_id, None)
43
44 def find_text_in_quotes(self, message):
45 text_in_quotes = re.search(r'["\']([a-zA-Z0-9 ]+)["\']', message)
46 if not text_in_quotes:
47 raise ValueError("Text in quotes not found!")
48 return text_in_quotes.group(1)
49
50 def __call__(self, child, wish):
51 wish_for_present = self.find_text_in_quotes(wish)
52 child_id = id(child)
53 self.wish_list[child_id] = wish_for_present
54 if child_id not in self._wishes_order:
55 self._wishes_order.append(child_id)
56 if child_id not in self.kid_years:
57 self.kid_years[child_id] = 0
58 self.global_wish_counter[wish_for_present] = self.global_wish_counter.get(wish_for_present, 0) + 1
59
60 def get_signature(self, message):
61 only_nums = re.search(r'^\s*(\d+)\s*$', message, re.MULTILINE)
62 if not only_nums:
63 raise ValueError("Invalid ID!")
64 return int(only_nums.group(1))
65
66 def get_wish(self, message):
67 return self.find_text_in_quotes(message)
68
69 def __matmul__(self, message):
70 child_id = self.get_signature(message)
71 wish = self.get_wish(message)
72 self.wish_list[child_id] = wish
73 if child_id not in self._wishes_order:
74 self._wishes_order.append(child_id)
75 self.global_wish_counter[wish] = self.global_wish_counter.get(wish, 0) + 1
76
77 def __iter__(self):
78 for child_id in self._wishes_order:
79 yield self.wish_list[child_id]
80 self._wishes_order.clear()
81
82 def get_most_wished_gift(self):
83 if not self.global_wish_counter:
84 return ""
85 max_count = max(self.global_wish_counter.values())
86 most_wished_items = [item for item, count in self.global_wish_counter.items() if count == max_count]
87 return random.choice(most_wished_items)
88
89 def choose_random_default_gift(self):
90 return self.get_most_wished_gift()
91
92 def reset_christmas(self):
93 self.child_behavior = {id(child): True for child in self.child_instances.values()}
94 self.gifts_count = {}
95 self.wish_list = {}
96 self._wishes_order = []
97
98 def xmas(self):
99 if not self.wish_list:
100 return
101
102 most_wished_gift = self.choose_random_default_gift()
103
104 for child_id, gift in self.wish_list.items():
105 child = self.get_child_by_id(child_id)
106 if not child or self.kid_years.get(child_id, 0) >= MAX_KID_YEARS:
107 continue
108
109 if not self.child_behavior.get(child_id, True):
110 child("coal")
111 else:
112 child(self.wish_list[child_id] or most_wished_gift)
113
114 self.kid_years[child_id] = self.kid_years.get(child_id, 0) + 1
115 self.reset_christmas()
116
117
118class Kid(type):
119 def __new__(cls, name, bases, dct):
120 if "__call__" not in dct:
121 raise NotImplementedError("Not callable class!")
122 return super().__new__(cls, name, bases, dct)
123
124 def __call__(cls, *args, **kwargs):
125 instance = super().__call__(*args, **kwargs)
126 Santa().register_child(instance)
127 return instance
....F.......FF....F.
======================================================================
FAIL: test_iterable (test.TestSanta.test_iterable)
Ensure Santa can be iterated multiple times including overwriting presents.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 130, in test_iterable
self.assertEqual(list(self.santa), ['something', 'something else'])
AssertionError: Lists differ: [] != ['something', 'something else']
Second list contains 2 additional elements.
First extra element 0:
'something'
- []
+ ['something', 'something else']
======================================================================
FAIL: test_xmass_kid_without_a_wish (test.TestSanta.test_xmass_kid_without_a_wish)
Test a Christmas with a kids that hasn't sent a wish.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 178, in test_xmass_kid_without_a_wish
self.assertEqual(kid4.SECRET_PRESENT, 'toy1')
AssertionError: None != 'toy1'
======================================================================
FAIL: test_xmass_naughty (test.TestSanta.test_xmass_naughty)
Test a Christmas with naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 229, in test_xmass_naughty
self.assertEqual(kid3.SECRET_PRESENT, 'sirenie')
AssertionError: None != 'sirenie'
======================================================================
FAIL: test_xmass_years_5_and_over (test.TestSanta.test_xmass_years_5_and_over)
Test with passing years with kid aged 5 and over.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 213, in test_xmass_years_5_and_over
self.assertEqual(kid1.SECRET_PRESENT, None)
AssertionError: 'toy' != None
----------------------------------------------------------------------
Ran 20 tests in 0.026s
FAILED (failures=4)
20.12.2024 10:09
20.12.2024 10:10
20.12.2024 10:11
20.12.2024 10:12
20.12.2024 10:13