Домашни > Работилница за отвари! > Решения > Решението на Виктор Бечев

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

10 точки общо

20 успешни теста
0 неуспешни теста
Код (Quick fixes due to subtle brain farts)

  1from copy import deepcopy
  2from math import ceil
  3
  4class Effect:
  5    def __init__(self, func, intensity=1):
  6        self._func = func
  7        self.intensity = intensity
  8        self._depleted = False
  9
 10    def duplicate(self):
 11        return Effect(self._func, self.intensity)
 12    
 13    def __call__(self, *args,**kwargs):
 14        if self._depleted:
 15            raise TypeError("Effect is depleted.")
 16        else:
 17            self._depleted = True
 18            for _ in range(self.intensity):
 19                self._func(*args, **kwargs)
 20
 21    def __add__(self, other):
 22        return Effect(self._func, self.intensity + other.intensity) if all((self, other)) else self
 23
 24    def __sub__(self, other):
 25        return Effect(self._func, self.intensity - other.intensity) if all((self, other)) else self
 26    
 27    def __mul__(self, other):
 28        return Effect(self._func, ceil(self.intensity * other - 0.5)) if all((self, other)) else self
 29    
 30    def __truediv__(self, other):
 31        return Effect(self._func, ceil(self.intensity / other - 0.5)) if all((self, other)) else self
 32
 33    __radd__ = __add__
 34    __rsub__ = __sub__
 35
 36    def __eq__(self, other):
 37        return self.intensity == other.intensity
 38
 39    def __gt__(self, other):
 40        return self.intensity > other.intensity
 41
 42
 43class Potion:
 44
 45    def __init__(self, effects, duration):
 46        self.effects = {name: func if isinstance(func, Effect) else Effect(func)
 47                        for name, func in effects.items()}
 48        self.duration = duration
 49        self.potent = True
 50        self.depleted = False
 51
 52    def duplicate(self):
 53        return Potion({name: effect.duplicate() for name, effect in self.effects.items()},
 54                      self.duration)
 55
 56    def check_if_potent_or_depleted(self):
 57        if self.depleted:
 58            raise TypeError("Potion is depleted.")
 59        if not self.potent:
 60            raise TypeError("Potion is now part of something bigger than itself.")
 61    
 62    def use(self, target):
 63        self.check_if_potent_or_depleted()
 64        for name in sorted(self.effects.keys(), reverse=True,
 65                           key=lambda name: sum(ord(char) for char in name)):
 66            try: # This method exists becase it's not Dimitrichka's job to try/except this
 67                self.effects[name](target)
 68            except TypeError:
 69                pass # Effect is depleted
 70        self.depleted = True
 71
 72    def __getattr__(self, name):
 73        super().__getattribute__('check_if_potent_or_depleted')()
 74        try:
 75            return super().__getattribute__('effects')[name]
 76        except KeyError:
 77            raise AttributeError
 78
 79    def __add__(self, other):
 80        self.check_if_potent_or_depleted()
 81        effects = {name: self.effects.get(name) + other.effects.get(name)
 82                   for name in list(self.effects.keys()) + list(other.effects.keys())}
 83        self.potent = False
 84        other.potent = False
 85        return Potion(effects, max((self.duration, other.duration)))
 86
 87    def __sub__(self, other):
 88        self.check_if_potent_or_depleted()
 89        if not all(effect in self.effects for effect in other.effects):
 90            raise TypeError
 91        effects = {name: effect
 92                   for name in list(self.effects.keys()) + list(other.effects.keys())
 93                   if (effect:=self.effects.get(name) - other.effects.get(name)).intensity > 0}
 94        self.potent = False
 95        other.potent = False
 96        return Potion(effects, self.duration)
 97
 98    def __mul__(self, multiplier):
 99        self.check_if_potent_or_depleted()
100        effects = {name: self.effects[name] * multiplier for name in self.effects}
101        self.potent = False
102        return Potion(effects, self.duration)
103
104    def __truediv__(self, divisor):
105        self.check_if_potent_or_depleted()
106        potions = [Potion({name: self.effects[name] / divisor for name in self.effects},
107                          self.duration)
108                   for _ in range(divisor)]
109        self.potent = False
110        return potions
111
112    def __eq__(self, other):
113        return self.effects.items() == other.effects.items()
114
115    def __gt__(self, other):
116        return sum(self.effects.values()) > sum(other.effects.values())
117
118
119class ГоспожатаПоХимия:
120
121    def __init__(self):
122        self.target_states = {}
123
124    def apply(self, target, potion):
125        if target not in self.target_states:
126            self.target_states[target] = {'state': deepcopy(target.__dict__),
127                                          'potions_applied': []}
128        self.target_states[target]['potions_applied'].append({'potion': potion,
129                                                              'ticks_left': potion.duration})
130        potion.use(target)
131
132    def tick(self):
133        for target, target_meta in self.target_states.items():
134            # Nasty approach to solve proper state management
135            # But honestly... I'm tired of this homework
136            target.__dict__ = deepcopy(target_meta['state'])
137            for potion_meta in target_meta['potions_applied']:
138                potion_meta['ticks_left'] -= 1
139                if potion_meta['ticks_left'] > 0:
140                    potion_meta['potion'].duplicate().use(target)

....................
----------------------------------------------------------------------
Ran 20 tests in 0.002s

OK

Дискусия
История

n1from collections import defaultdictn
2from copy import deepcopy1from copy import deepcopy
3from math import ceil2from math import ceil
43
5class Effect:4class Effect:
6    def __init__(self, func, intensity=1):5    def __init__(self, func, intensity=1):
n7        # Avoid creating nested Effectsn
8        self._func = func6        self._func = func
9        self.intensity = intensity7        self.intensity = intensity
10        self._depleted = False8        self._depleted = False
119
12    def duplicate(self):10    def duplicate(self):
13        return Effect(self._func, self.intensity)11        return Effect(self._func, self.intensity)
14    12    
15    def __call__(self, *args,**kwargs):13    def __call__(self, *args,**kwargs):
16        if self._depleted:14        if self._depleted:
17            raise TypeError("Effect is depleted.")15            raise TypeError("Effect is depleted.")
18        else:16        else:
19            self._depleted = True17            self._depleted = True
20            for _ in range(self.intensity):18            for _ in range(self.intensity):
21                self._func(*args, **kwargs)19                self._func(*args, **kwargs)
2220
23    def __add__(self, other):21    def __add__(self, other):
24        return Effect(self._func, self.intensity + other.intensity) if all((self, other)) else self22        return Effect(self._func, self.intensity + other.intensity) if all((self, other)) else self
2523
26    def __sub__(self, other):24    def __sub__(self, other):
27        return Effect(self._func, self.intensity - other.intensity) if all((self, other)) else self25        return Effect(self._func, self.intensity - other.intensity) if all((self, other)) else self
28    26    
29    def __mul__(self, other):27    def __mul__(self, other):
30        return Effect(self._func, ceil(self.intensity * other - 0.5)) if all((self, other)) else self28        return Effect(self._func, ceil(self.intensity * other - 0.5)) if all((self, other)) else self
31    29    
32    def __truediv__(self, other):30    def __truediv__(self, other):
33        return Effect(self._func, ceil(self.intensity / other - 0.5)) if all((self, other)) else self31        return Effect(self._func, ceil(self.intensity / other - 0.5)) if all((self, other)) else self
3432
35    __radd__ = __add__33    __radd__ = __add__
36    __rsub__ = __sub__34    __rsub__ = __sub__
3735
38    def __eq__(self, other):36    def __eq__(self, other):
39        return self.intensity == other.intensity37        return self.intensity == other.intensity
4038
41    def __gt__(self, other):39    def __gt__(self, other):
42        return self.intensity > other.intensity40        return self.intensity > other.intensity
4341
4442
45class Potion:43class Potion:
n46    __pseudo_slots = ['duration', 'effects', 'potent', 'depleted',n
47                      'check_if_potent_or_depleted', 'duplicate', 'use']
4844
49    def __init__(self, effects, duration):45    def __init__(self, effects, duration):
50        self.effects = {name: func if isinstance(func, Effect) else Effect(func)46        self.effects = {name: func if isinstance(func, Effect) else Effect(func)
51                        for name, func in effects.items()}47                        for name, func in effects.items()}
52        self.duration = duration48        self.duration = duration
53        self.potent = True49        self.potent = True
54        self.depleted = False50        self.depleted = False
5551
56    def duplicate(self):52    def duplicate(self):
57        return Potion({name: effect.duplicate() for name, effect in self.effects.items()},53        return Potion({name: effect.duplicate() for name, effect in self.effects.items()},
58                      self.duration)54                      self.duration)
5955
60    def check_if_potent_or_depleted(self):56    def check_if_potent_or_depleted(self):
61        if self.depleted:57        if self.depleted:
62            raise TypeError("Potion is depleted.")58            raise TypeError("Potion is depleted.")
63        if not self.potent:59        if not self.potent:
64            raise TypeError("Potion is now part of something bigger than itself.")60            raise TypeError("Potion is now part of something bigger than itself.")
65    61    
66    def use(self, target):62    def use(self, target):
67        self.check_if_potent_or_depleted()63        self.check_if_potent_or_depleted()
68        for name in sorted(self.effects.keys(), reverse=True,64        for name in sorted(self.effects.keys(), reverse=True,
69                           key=lambda name: sum(ord(char) for char in name)):65                           key=lambda name: sum(ord(char) for char in name)):
70            try: # This method exists becase it's not Dimitrichka's job to try/except this66            try: # This method exists becase it's not Dimitrichka's job to try/except this
71                self.effects[name](target)67                self.effects[name](target)
72            except TypeError:68            except TypeError:
73                pass # Effect is depleted69                pass # Effect is depleted
74        self.depleted = True70        self.depleted = True
7571
t76    def __getattribute__(self, name):t72    def __getattr__(self, name):
77            if name in Potion.__pseudo_slots:
78                return super().__getattribute__(name)
79            super().__getattribute__('check_if_potent_or_depleted')()73        super().__getattribute__('check_if_potent_or_depleted')()
80            try:74        try:
81                return super().__getattribute__('effects')[name]75            return super().__getattribute__('effects')[name]
82            except KeyError:76        except KeyError:
83                raise AttributeError77            raise AttributeError
8478
85    def __add__(self, other):79    def __add__(self, other):
86        self.check_if_potent_or_depleted()80        self.check_if_potent_or_depleted()
87        effects = {name: self.effects.get(name) + other.effects.get(name)81        effects = {name: self.effects.get(name) + other.effects.get(name)
88                   for name in list(self.effects.keys()) + list(other.effects.keys())}82                   for name in list(self.effects.keys()) + list(other.effects.keys())}
89        self.potent = False83        self.potent = False
90        other.potent = False84        other.potent = False
91        return Potion(effects, max((self.duration, other.duration)))85        return Potion(effects, max((self.duration, other.duration)))
9286
93    def __sub__(self, other):87    def __sub__(self, other):
94        self.check_if_potent_or_depleted()88        self.check_if_potent_or_depleted()
95        if not all(effect in self.effects for effect in other.effects):89        if not all(effect in self.effects for effect in other.effects):
96            raise TypeError90            raise TypeError
97        effects = {name: effect91        effects = {name: effect
98                   for name in list(self.effects.keys()) + list(other.effects.keys())92                   for name in list(self.effects.keys()) + list(other.effects.keys())
99                   if (effect:=self.effects.get(name) - other.effects.get(name)).intensity > 0}93                   if (effect:=self.effects.get(name) - other.effects.get(name)).intensity > 0}
100        self.potent = False94        self.potent = False
101        other.potent = False95        other.potent = False
102        return Potion(effects, self.duration)96        return Potion(effects, self.duration)
10397
104    def __mul__(self, multiplier):98    def __mul__(self, multiplier):
105        self.check_if_potent_or_depleted()99        self.check_if_potent_or_depleted()
106        effects = {name: self.effects[name] * multiplier for name in self.effects}100        effects = {name: self.effects[name] * multiplier for name in self.effects}
107        self.potent = False101        self.potent = False
108        return Potion(effects, self.duration)102        return Potion(effects, self.duration)
109103
110    def __truediv__(self, divisor):104    def __truediv__(self, divisor):
111        self.check_if_potent_or_depleted()105        self.check_if_potent_or_depleted()
112        potions = [Potion({name: self.effects[name] / divisor for name in self.effects},106        potions = [Potion({name: self.effects[name] / divisor for name in self.effects},
113                          self.duration)107                          self.duration)
114                   for _ in range(divisor)]108                   for _ in range(divisor)]
115        self.potent = False109        self.potent = False
116        return potions110        return potions
117111
118    def __eq__(self, other):112    def __eq__(self, other):
119        return self.effects.items() == other.effects.items()113        return self.effects.items() == other.effects.items()
120114
121    def __gt__(self, other):115    def __gt__(self, other):
122        return sum(self.effects.values()) > sum(other.effects.values())116        return sum(self.effects.values()) > sum(other.effects.values())
123117
124118
125class ГоспожатаПоХимия:119class ГоспожатаПоХимия:
126120
127    def __init__(self):121    def __init__(self):
128        self.target_states = {}122        self.target_states = {}
129123
130    def apply(self, target, potion):124    def apply(self, target, potion):
131        if target not in self.target_states:125        if target not in self.target_states:
132            self.target_states[target] = {'state': deepcopy(target.__dict__),126            self.target_states[target] = {'state': deepcopy(target.__dict__),
133                                          'potions_applied': []}127                                          'potions_applied': []}
134        self.target_states[target]['potions_applied'].append({'potion': potion,128        self.target_states[target]['potions_applied'].append({'potion': potion,
135                                                              'ticks_left': potion.duration})129                                                              'ticks_left': potion.duration})
136        potion.use(target)130        potion.use(target)
137131
138    def tick(self):132    def tick(self):
139        for target, target_meta in self.target_states.items():133        for target, target_meta in self.target_states.items():
140            # Nasty approach to solve proper state management134            # Nasty approach to solve proper state management
141            # But honestly... I'm tired of this homework135            # But honestly... I'm tired of this homework
142            target.__dict__ = deepcopy(target_meta['state'])136            target.__dict__ = deepcopy(target_meta['state'])
143            for potion_meta in target_meta['potions_applied']:137            for potion_meta in target_meta['potions_applied']:
144                potion_meta['ticks_left'] -= 1138                potion_meta['ticks_left'] -= 1
145                if potion_meta['ticks_left'] > 0:139                if potion_meta['ticks_left'] > 0:
146                    potion_meta['potion'].duplicate().use(target)140                    potion_meta['potion'].duplicate().use(target)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op