1import re
2
3class Santa:
4 instance = None
5 MAX_KID_AGE = 5
6 COAL_PRESENT = 'coal'
7
8 def xmas(self):
9 for child in self.children.keys():
10 self.children[child] += 1
11
12 if not self.presents:
13 return
14
15 present_counts = dict()
16 given_presents = set()
17 for present in self.presents:
18 if self.children[present[0]] > Santa.MAX_KID_AGE:
19 continue
20 given_presents.add(present[0])
21 if present[0] in self.blacklist:
22 self.kids_by_id[present[0]](self.COAL_PRESENT)
23 continue
24 self.kids_by_id[present[0]](present[1])
25 present_counts[present[1]] = present_counts.get(present[1], 0) + 1
26
27 most_wanted_present = (None, 0)
28 for name, count in present_counts.items():
29 if most_wanted_present[1] < count:
30 most_wanted_present = (name, count)
31
32 must_be_good_present = most_wanted_present[0]
33
34 for kid, age in self.children.items():
35 if age > Santa.MAX_KID_AGE or kid in given_presents:
36 continue
37 if kid in self.blacklist:
38 self.kids_by_id[kid](self.COAL_PRESENT)
39 else:
40 self.kids_by_id[kid](must_be_good_present)
41
42 self.presents = []
43 self.blacklist = set()
44
45 def __new__(cls, *args, **kwargs):
46 if cls.instance is None:
47 cls.instance = super().__new__(cls, *args, **kwargs)
48 return cls.instance
49
50 def __init__(self):
51 self.presents = []
52 self.blacklist = set()
53 self.children = dict()
54 self.kids_by_id = dict()
55 self._iter_index = 0
56
57 def __call__(self, kid, wish):
58 kid_id = id(kid)
59 for i, present in enumerate(self.presents):
60 if present[0] == kid_id:
61 self.presents[i] = (kid_id, Santa.get_present_wish(wish))
62 break
63 else:
64 self.presents.append((kid_id, Santa.get_present_wish(wish)))
65
66 def __matmul__(self, letter):
67 kid_id = Santa.get_kid_id(letter)
68 kid_wish = Santa.get_present_wish(letter)
69 for i, present in enumerate(self.presents):
70 if present[0] == kid_id:
71 self.presents[i] = (kid_id, kid_wish)
72 break
73 else:
74 self.presents.append((kid_id, kid_wish))
75
76 def __iter__(self):
77 self._iter_index = 0
78 return self
79
80 def __next__(self):
81 if self._iter_index >= len(self.presents):
82 self._iter_index = 0
83 raise StopIteration
84 self._iter_index += 1
85 return self.presents[self._iter_index - 1][1]
86
87 @staticmethod
88 def get_present_wish(wish):
89 kid_present_r = r"(\"|\')([a-zA-Z0-9]+[a-zA-Z0-9\s]*)\1"
90 return re.search(kid_present_r, wish).group(2)
91
92 @staticmethod
93 def get_kid_id(letter):
94 kid_id_r = r"^\s*\d+\s*$"
95 kid_id = None
96 for line in letter.splitlines():
97 if re.match(kid_id_r, line):
98 kid_id = int(line.strip())
99 break
100 return kid_id
101
102class Kid(type):
103
104 def __new__(cls, name, bases, attr_dict):
105 if '__call__' not in attr_dict:
106 raise NotImplementedError('No __call__')
107
108 for attr, value in attr_dict.items():
109 if not attr.startswith('_') and hasattr(value, '__call__'):
110 attr_dict[attr] = Kid.bad_kid_checker(value)
111
112 new_class = super().__new__(cls, name, bases, attr_dict)
113 old_new = new_class.__new__
114
115 def new_new(cls, *args, **kwargs):
116 instance = old_new(cls, *args, **kwargs)
117 Santa.instance.children[id(instance)] = 0
118 Santa.instance.kids_by_id[id(instance)] = instance
119 return instance
120
121 new_class.__new__ = new_new
122
123 return new_class
124
125 @staticmethod
126 def bad_kid_checker(func):
127 def wrapper(self, *args, **kwargs):
128 try:
129 return func(self, *args, **kwargs)
130 except:
131 Santa.instance.blacklist.add(id(self))
132 raise
133 return wrapper
.............F......
======================================================================
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'
----------------------------------------------------------------------
Ran 20 tests in 0.024s
FAILED (failures=1)
20.12.2024 10:23
20.12.2024 10:19
20.12.2024 10:19
20.12.2024 10:21
20.12.2024 10:20