Skip to content

Commit ed593fa

Browse files
authored
Merge pull request #5398 from hozlucas28/Solution-32-Python
#32 - Python
2 parents ae3203d + c5b0e3d commit ed593fa

File tree

1 file changed

+313
-0
lines changed

1 file changed

+313
-0
lines changed
Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
2+
3+
4+
from abc import ABCMeta, abstractmethod
5+
from random import randint
6+
from typing import Self, TypedDict
7+
8+
import asyncio
9+
10+
# ---------------------------------------------------------------------------- #
11+
# SUPERHEROREGENERATINGERROR (ERROR) #
12+
# ---------------------------------------------------------------------------- #
13+
14+
15+
class SuperheroRegeneratingException(Exception):
16+
def __init__(self, *, superhero: "AbcSuperhero") -> None:
17+
super().__init__(f"{superhero.name} is regenerating")
18+
19+
20+
# ---------------------------------------------------------------------------- #
21+
# SUPERHERO (CLASS) #
22+
# ---------------------------------------------------------------------------- #
23+
24+
type AttackDamage = tuple[int, int]
25+
26+
27+
class AbcSuperhero(metaclass=ABCMeta):
28+
@property
29+
@abstractmethod
30+
def life_points(self) -> int:
31+
pass
32+
33+
@property
34+
@abstractmethod
35+
def regenerating(self) -> bool:
36+
pass
37+
38+
@property
39+
@abstractmethod
40+
def attack_damage(self) -> AttackDamage:
41+
pass
42+
43+
@property
44+
@abstractmethod
45+
def evade_percentage(self) -> int:
46+
pass
47+
48+
@property
49+
@abstractmethod
50+
def name(self) -> str:
51+
pass
52+
53+
@abstractmethod
54+
def set_regenerating(self, regenerating: bool) -> Self:
55+
pass
56+
57+
@abstractmethod
58+
def evade_attack(self) -> bool:
59+
pass
60+
61+
@abstractmethod
62+
def produce_damage(self) -> int:
63+
pass
64+
65+
@abstractmethod
66+
def receive_damage(self, damage: int) -> Self:
67+
pass
68+
69+
70+
class Superhero(AbcSuperhero):
71+
__life_points: int
72+
__regenerating: bool
73+
__attack_damage: AttackDamage
74+
__evade_percentage: int
75+
__name: str
76+
77+
def __init__(
78+
self,
79+
*,
80+
life_points: int,
81+
attack_damage: AttackDamage,
82+
evade_percentage: int,
83+
name: str,
84+
) -> None:
85+
self.__life_points = life_points
86+
self.__regenerating = False
87+
self.__attack_damage = attack_damage
88+
self.__evade_percentage = evade_percentage
89+
self.__name = name
90+
91+
@property
92+
def life_points(self) -> int:
93+
return self.__life_points
94+
95+
@property
96+
def regenerating(self) -> bool:
97+
return self.__regenerating
98+
99+
@property
100+
def attack_damage(self) -> AttackDamage:
101+
return self.__attack_damage
102+
103+
@property
104+
def evade_percentage(self) -> int:
105+
return self.__evade_percentage
106+
107+
@property
108+
def name(self) -> str:
109+
return self.__name
110+
111+
def set_regenerating(self, regenerating: bool) -> Self:
112+
self.__regenerating = regenerating
113+
return self
114+
115+
def evade_attack(self) -> bool:
116+
rnd_int: int = randint(a=0, b=100)
117+
return rnd_int <= self.__evade_percentage
118+
119+
def produce_damage(self) -> int:
120+
if self.__regenerating:
121+
raise SuperheroRegeneratingException(superhero=self)
122+
123+
[min_attack_damage, max_attack_damage] = self.attack_damage
124+
rnd_damage: int = randint(a=min_attack_damage, b=max_attack_damage)
125+
return rnd_damage
126+
127+
def receive_damage(self, damage: int) -> Self:
128+
self.__life_points -= damage
129+
return self
130+
131+
132+
# ---------------------------------------------------------------------------- #
133+
# WOLVERINE (CLASS) #
134+
# ---------------------------------------------------------------------------- #
135+
136+
137+
class Wolverine(Superhero):
138+
def __init__(self, *, life_points: int) -> None:
139+
super().__init__(
140+
life_points=life_points,
141+
attack_damage=(10, 120),
142+
evade_percentage=20,
143+
name="Wolverine",
144+
)
145+
146+
147+
# ---------------------------------------------------------------------------- #
148+
# DEADPOOL (CLASS) #
149+
# ---------------------------------------------------------------------------- #
150+
151+
152+
class Deadpool(Superhero):
153+
def __init__(self, *, life_points: int) -> None:
154+
super().__init__(
155+
life_points=life_points,
156+
attack_damage=(10, 100),
157+
evade_percentage=25,
158+
name="Deadpool",
159+
)
160+
161+
162+
# ---------------------------------------------------------------------------- #
163+
# SUPERHEROESFIGHT (CLASS) #
164+
# ---------------------------------------------------------------------------- #
165+
166+
167+
class Turn(TypedDict):
168+
attacker: AbcSuperhero
169+
number: int
170+
victim: AbcSuperhero
171+
172+
173+
class ExecutedTurn(Turn):
174+
damage_produced_by_attacker: int
175+
damage_received_by_victim: int
176+
victim_avoid_attack: bool
177+
178+
179+
class AbcSuperheroesFight(metaclass=ABCMeta):
180+
@property
181+
@abstractmethod
182+
def turn(self) -> Turn:
183+
pass
184+
185+
@property
186+
@abstractmethod
187+
def winner(self) -> None | AbcSuperhero:
188+
pass
189+
190+
@abstractmethod
191+
def execute_turn(self) -> ExecutedTurn:
192+
pass
193+
194+
195+
class SuperheroesFight(AbcSuperheroesFight):
196+
__turn: Turn
197+
__winner: None | AbcSuperhero
198+
199+
def __init__(
200+
self, *, superhero_one: AbcSuperhero, superhero_two: AbcSuperhero
201+
) -> None:
202+
self.__turn = {
203+
"attacker": superhero_one,
204+
"number": 1,
205+
"victim": superhero_two,
206+
}
207+
208+
self.__winner = None
209+
210+
@property
211+
def turn(self) -> Turn:
212+
return self.__turn
213+
214+
@property
215+
def winner(self) -> None | AbcSuperhero:
216+
return self.__winner
217+
218+
def execute_turn(self) -> ExecutedTurn:
219+
turn: Turn = self.turn
220+
attacker: AbcSuperhero = turn["attacker"]
221+
number: int = turn["number"]
222+
victim: AbcSuperhero = turn["victim"]
223+
224+
victim.set_regenerating(regenerating=False)
225+
226+
self.__turn = {
227+
"attacker": victim,
228+
"number": number + 1,
229+
"victim": attacker,
230+
}
231+
232+
try:
233+
damage_produced_by_attacker: int = attacker.produce_damage()
234+
attacker_attack_damage: AttackDamage = attacker.attack_damage
235+
236+
victim_avoid_attack: bool = victim.evade_attack()
237+
238+
if victim_avoid_attack:
239+
return {
240+
"attacker": attacker,
241+
"damage_produced_by_attacker": damage_produced_by_attacker,
242+
"damage_received_by_victim": 0,
243+
"number": number,
244+
"victim": victim,
245+
"victim_avoid_attack": victim_avoid_attack,
246+
}
247+
248+
victim.receive_damage(damage_produced_by_attacker)
249+
victim.set_regenerating(
250+
regenerating=damage_produced_by_attacker == attacker_attack_damage[1]
251+
)
252+
253+
if victim.life_points <= 0:
254+
self.__winner = attacker
255+
256+
return {
257+
"attacker": attacker,
258+
"damage_produced_by_attacker": damage_produced_by_attacker,
259+
"damage_received_by_victim": damage_produced_by_attacker,
260+
"number": number,
261+
"victim": victim,
262+
"victim_avoid_attack": victim_avoid_attack,
263+
}
264+
265+
except SuperheroRegeneratingException as error:
266+
raise error
267+
268+
269+
# ---------------------------------------------------------------------------- #
270+
# MAIN #
271+
# ---------------------------------------------------------------------------- #
272+
273+
274+
async def main() -> None:
275+
deadpool: Deadpool = Deadpool(life_points=500)
276+
wolverine: Wolverine = Wolverine(life_points=500)
277+
278+
superheroes_fight: SuperheroesFight = SuperheroesFight(
279+
superhero_one=deadpool, superhero_two=wolverine
280+
)
281+
282+
while superheroes_fight.winner is None:
283+
await asyncio.sleep(delay=1)
284+
current_turn: Turn = superheroes_fight.turn
285+
286+
try:
287+
executed_turn: ExecutedTurn = superheroes_fight.execute_turn()
288+
289+
if executed_turn["victim_avoid_attack"]:
290+
print(
291+
f"\n> Turn N°{executed_turn['number']}: {executed_turn['victim'].name}",
292+
f" avoided {executed_turn['attacker'].name} attack.",
293+
)
294+
continue
295+
296+
print(
297+
f"\n> Turn N°{executed_turn['number']}: {executed_turn['attacker'].name} attacked"
298+
+ f" {executed_turn['victim'].name} with"
299+
+ f" {executed_turn['damage_produced_by_attacker']} points of damage.",
300+
f"[ Life points of Deadpool: {deadpool.life_points} ]",
301+
f"[ Life points of Wolverine: {wolverine.life_points} ]",
302+
sep="\n",
303+
)
304+
except SuperheroRegeneratingException:
305+
print(
306+
f"\n> Turn N°{current_turn['number']}: {current_turn['attacker'].name} is"
307+
+ " regenerating"
308+
)
309+
310+
print(f"\nThe winner is {superheroes_fight.winner.name}!")
311+
312+
313+
asyncio.run(main=main())

0 commit comments

Comments
 (0)