Домашни > Подаръци ще има за всички от сърце > Решения > Решението на Асен Красимиров

Резултати
8 точки от тестове
0 точки от учител

8 точки общо

16 успешни теста
4 неуспешни теста
Код
Скрий всички коментари

  1import random
  2import re
  3from collections import defaultdict
  4
  5class Singleton(type):
  6    _instances = {}
  7
  8    def __call__(mcs, *args, **kwargs):
  9        if mcs not in mcs._instances:
 10            mcs._instances[mcs] = super(Singleton, mcs).__call__(*args, **kwargs)
 11        return mcs._instances[mcs]
 12
 13
 14class Kid(type):
 15    instances = {}  # id -> {child: self, xmas_count: 0, bad: False}
 16
 17    def __new__(mcs, name, bases, class_dict):
 18        if "__call__" not in class_dict:
 19            raise NotImplementedError(f"The class {name} must define a __call__ method.")
 20
 21        cls = super().__new__(mcs, name, bases, class_dict)
 22        
 23        original_init = cls.__init__
 24        
 25        def init_wrapper(self, *args, **kwargs):
 26            original_init(self, *args, **kwargs)
 27            Kid.instances[id(self)] = {'child': self, 'xmas_count': 0, 'bad': False}
 28        
 29        cls.__init__ = init_wrapper
 30
 31        for attr_name, attr_value in class_dict.items():
 32            if callable(attr_value) and not attr_name.startswith("__") and attr_name != "__call__":
 33                def method_wrapper(self, *args, **kwargs):
 34                    try:
 35                        return attr_value(self, *args, **kwargs)
 36                    except Exception:
 37                        Kid.instances[id(self)]['bad'] = True
 38                        return None
 39                
 40                setattr(cls, attr_name, method_wrapper)
 41        
 42        return cls
 43
 44
 45class Santa(metaclass=Singleton):
 46    def __init__(self):
 47        self.wishes = {}
 48        self.wishes_ranking = defaultdict(int)
 49        self.were_there_wished = False
 50
 51    def __call__(self, child, wish):
 52        if not isinstance(type(child), Kid):
 53            raise TypeError("Only instances of classes with Kid as metaclass are allowed.")
 54        if not isinstance(wish, str):
 55            raise ValueError("The wish must be a string.")
 56
 57        extracted_wish_text = self._extract_wish(wish)
 58
 59        if not extracted_wish_text:
 60            raise ValueError("The message must contain a valid wish enclosed in quotes.")
 61        
 62        self.wishes[id(child)] = extracted_wish_text
 63        self.wishes_ranking[extracted_wish_text] += 1
 64        self.were_there_wished = True
 65
 66    def __matmul__(self, letter):
 67        if not isinstance(letter, str):
 68            raise ValueError("The letter must be a string.")
 69
 70        extracted_wish_text = self._extract_wish(letter)
 71
 72        if not extracted_wish_text:
 73            raise ValueError("The letter must contain a valid wish enclosed in quotes.")
 74
 75        signature_regex = r'\n\s*(\d+)\s*$'
 76        signature_match = re.search(signature_regex, letter)
 77
 78        if not signature_match:
 79            raise ValueError("The letter must contain a valid numeric signature.")
 80
 81        signature = int(signature_match.group(1))
 82        self.wishes[signature] = extracted_wish_text
 83        self.wishes_ranking[extracted_wish_text] += 1
 84        self.were_there_wished = True
 85
 86    def _extract_wish(self, text):
 87        wish_regex = r'(["\'])([a-zA-Z0-9 ]+)\1'
 88        extracted_wish = re.search(wish_regex, text)
 89
 90        if not extracted_wish:
 91            return None
 92        
 93        return extracted_wish.group(2) or extracted_wish.group(3)
 94
 95    def __iter__(self):
 96        for wish in self.wishes.values():
 97            yield wish
 98
 99    def _get_most_wished_wish(self):
100        max_value = max(self.wishes_ranking.values())
101        max_wished = [key for key, value in self.wishes_ranking.items() if value == max_value]
102        return random.choice(max_wished)
103        
104    def xmas(self):
105        if not self.were_there_wished:
106            for kid_info in Kid.instances.values():
107                kid_info['xmas_count'] += 1
108            return
109        
110        # wish for the rest of the children
111        random_wish = self._get_most_wished_wish()
112
113        # all children that wished
114        for kid_id, wish in (self.wishes | {kid_id : random_wish for kid_id in (Kid.instances.keys() - self.wishes.keys())}).items():
115            kid_info = Kid.instances[kid_id]
116
117            if kid_info['xmas_count'] >= 5:
118                continue
119
120            if kid_info['bad']:
121                kid_info['child']('coal')
122                print(f"{kid_info['child']} -> coal")
123            else:
124                kid_info['child'](wish)
125                print(f"{kid_info['child']} -> {wish}")
126
127            kid_info['xmas_count'] += 1
128            kid_info['bad'] = False
129
130        self.wishes.clear()
131        self.wishes_ranking = defaultdict(int)
132        self.were_there_wished = False

......E......F..F
Stdout:
<solution.KidClass1 object at 0x74792e6e2060> -> coal
F..
======================================================================
ERROR: test_present_matching (test.TestSanta.test_present_matching)
Test matching signature in the letter.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 87, in test_present_matching
self.santa @ f"""
File "/tmp/solution.py", line 79, in __matmul__
raise ValueError("The letter must contain a valid numeric signature.")
ValueError: The letter must contain a valid numeric signature.

======================================================================
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 222, in test_xmass_naughty
with self.assertRaises(ZeroDivisionError):
AssertionError: ZeroDivisionError not raised

======================================================================
FAIL: test_xmass_private_with_error (test.TestSanta.test_xmass_private_with_error)
Test a Christmas with not-so-naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 240, in test_xmass_private_with_error
self.assertEqual(kid1.SECRET_PRESENT, 'sirenie')
AssertionError: 'coal' != 'sirenie'
- coal
+ sirenie

Stdout:
<solution.KidClass1 object at 0x74792e6e2060> -> coal

======================================================================
FAIL: test_xmass_public_with_no_error (test.TestSanta.test_xmass_public_with_no_error)
Test a Christmas with not-so-naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 246, in test_xmass_public_with_no_error
self.assertEqual(kid1.public_without_error(), 42)
AssertionError: None != 42

----------------------------------------------------------------------
Ran 20 tests in 0.027s

FAILED (failures=3, errors=1)

Дискусия
История
Това решение има само една версия.