11"""
2+ ***********
23Game models
4+ ***********
5+
6+ Enemy
7+ =====
8+
9+ .. autoclass:: Enemy
10+ :members: decrease_health, select_attack, select_defence
11+ :special_members: __init__
12+
13+ Player
14+ ======
15+
16+ .. autoclass:: Player
17+ :members: decrease_health, select_attack, select_defence, attack, defence
18+ :special_members: __init__
319
420"""
521
622import logging
723import random
824from abc import ABC , abstractmethod
25+ from functools import wraps
926
1027from wtk import settings
1128from wtk .enums import FightChoice , FightResult , get_fight_result
1229from wtk .exceptions import EnemyDown , GameOver
1330from wtk .loggers import stream_handler
1431
32+ __all__ = ["Enemy" , "Player" ]
33+
1534
1635class _AbstractModel (ABC ):
1736 """Abstract game model"""
@@ -30,17 +49,26 @@ def decrease_health(self) -> None:
3049
3150
3251class Enemy (_AbstractModel ):
33- """Enemy model
52+ """
53+ Enemy model
3454
35- :ivar level: enemy's level
55+ Represents the playing enemy-bot.
56+
57+ :ivar level: enemy's level value
3658 :type level: int
3759 :ivar health: enemy's instance health points
3860 :type health: int
3961
4062 """
4163
4264 def __init__ (self , level : int = settings .INITIAL_ENEMY_LEVEL ) -> None :
43- """Initialize instance"""
65+ """
66+ Initialize instance
67+
68+ :param level: an enemy's level indicator
69+ :type level: int
70+
71+ """
4472
4573 self .health = level
4674 self .level = level
@@ -56,7 +84,11 @@ def __str__(self) -> str:
5684 return f"Enemy level { self .level } "
5785
5886 def decrease_health (self ) -> None :
59- """Decrease health points
87+ """
88+ Decrease health points
89+
90+ This method decreases the health meter value. When it comes to be
91+ less than 1 (one) an ``EnemyDown`` exception is raised.
6092
6193 :raise: EnemyDown
6294
@@ -68,28 +100,38 @@ def decrease_health(self) -> None:
68100
69101 @staticmethod
70102 def _select_fight_choice () -> FightChoice : # pragma: no cover
71- """Return a random fight choice"""
103+ """
104+ Return a random fight choice
105+
106+ Choices made by an enemy are random.
107+
108+ :return: a fight choice
109+
110+ """
72111
73112 return random .choice (tuple (FightChoice ))
74113
114+ @wraps (_select_fight_choice , ("__annotations__" , "__doc__" ))
75115 def select_attack (self ) -> FightChoice : # pragma: no cover
76116 return self ._select_fight_choice ()
77117
118+ @wraps (_select_fight_choice , ("__annotations__" , "__doc__" ))
78119 def select_defence (self ) -> FightChoice : # pragma: no cover
79120 return self ._select_fight_choice ()
80121
81122
82123class Player (_AbstractModel ):
83- """Player model
124+ """
125+ Player model
126+
127+ This model is controlled by the player.
84128
85129 :ivar name: player's name
86130 :type name: str
87131 :ivar health: player's instance health points
88132 :type health: int
89133 :ivar score: player's instance gained score points
90134 :type score: int
91- :cvar logger: class based message logger
92- :type logger: :class: `logging.Logger`
93135
94136 """
95137
@@ -98,7 +140,16 @@ class Player(_AbstractModel):
98140 logger .addHandler (stream_handler )
99141
100142 def __init__ (self , name : str ) -> None :
101- """Initialize instance"""
143+ """
144+ Initialize instance
145+
146+ This method performs player instance initialization. It set instance
147+ name, initial score points value and health.
148+
149+ :param name: a player's name
150+ :type name: str
151+
152+ """
102153
103154 self .name = name
104155 self .health = settings .INITIAL_PLAYER_HEALTH
@@ -115,7 +166,11 @@ def __str__(self) -> str:
115166 return self .name
116167
117168 def decrease_health (self ) -> None :
118- """Decrease instance health points
169+ """
170+ Decrease health points
171+
172+ This method decreases the health meter value. When it comes to be
173+ less than 1 (one) an ``GameOver`` exception is raised.
119174
120175 :raise: GameOver
121176
@@ -127,7 +182,16 @@ def decrease_health(self) -> None:
127182
128183 @staticmethod
129184 def _select_fight_choice () -> FightChoice :
130- """Return fight choice from the user's prompt"""
185+ """
186+ Return fight choice from the user's prompt
187+
188+ The player is asked to make their decision for the upcoming fight.
189+ The chosen value is validated and if it is invalid the question is
190+ repeated.
191+
192+ :return: a fight choice
193+
194+ """
131195
132196 choices = ", " .join (
133197 f"{ choice .name } - { choice .value } " for choice in FightChoice
@@ -140,25 +204,50 @@ def _select_fight_choice() -> FightChoice:
140204 except ValueError :
141205 pass
142206
207+ @wraps (_select_fight_choice , ("__annotations__" , "__doc__" ))
143208 def select_attack (self ) -> FightChoice : # pragma: no cover
144209 return self ._select_fight_choice ()
145210
211+ @wraps (_select_fight_choice , ("__annotations__" , "__doc__" ))
146212 def select_defence (self ) -> FightChoice : # pragma: no cover
147213 return self ._select_fight_choice ()
148214
149215 @staticmethod
150216 def fight (attack : FightChoice , defence : FightChoice ) -> FightResult :
151- """Implements a fight result calculation interface"""
217+ """
218+ Fight result calculation interface
219+
220+ The method calculates the fight result based on the game rules:
221+
222+ - **knight** beats **thief**
223+ - **thief** beats **wizard**
224+ - **wizard** beats **knight**
225+
226+ """
152227
153228 return get_fight_result (attack , defence )
154229
155230 def add_score_points (self , score_points : int ) -> None :
156- """Add score points"""
231+ """Add score points to the player instance """
157232
158233 self .score += score_points
159234
160235 def attack (self , enemy : Enemy ) -> None :
161- """Attack an enemy"""
236+ """
237+ Attack an enemy
238+
239+ Perform attack on an enemy instance. This method takes an enemy
240+ instance as an argument. After that, it takes attack choice from
241+ the player model and the defence choice from an enemy model.
242+ After fight result calculation required operation are to be
243+ performed (decrease enemy health, assign score points etc.).
244+ Based on fight result should print out a message:
245+
246+ - "YOUR ATTACK IS SUCCESSFUL!"
247+ - "YOUR ATTACK IS FAILED!"
248+ - "IT'S A DRAW!"
249+
250+ """
162251
163252 attack = self .select_attack ()
164253 defence = enemy .select_defence ()
@@ -180,7 +269,21 @@ def attack(self, enemy: Enemy) -> None:
180269 self .logger .info (settings .MSG_DRAW )
181270
182271 def defence (self , enemy : Enemy ) -> None :
183- """Defend from an enemy's attack"""
272+ """
273+ Defend from an enemy's attack
274+
275+ Perform defence from an enemy attack. This method takes an enemy
276+ instance as an argument. After that, it takes defence choice from
277+ the player model and the attack choice from an enemy model.
278+ After fight result calculation required operation are to be
279+ performed (decrease player health).
280+ Based on fight result should print out a message:
281+
282+ - "YOUR DEFENCE IS SUCCESSFUL!"
283+ - "YOUR DEFENCE IS FAILED!"
284+ - "IT'S A DRAW!"
285+
286+ """
184287
185288 attack = enemy .select_attack ()
186289 defence = self .select_defence ()
@@ -194,6 +297,3 @@ def defence(self, enemy: Enemy) -> None:
194297 self .logger .info (settings .MSG_SUCCESS_DEFENCE )
195298 elif fight_result == FightResult .DRAW :
196299 self .logger .info (settings .MSG_DRAW )
197-
198-
199- __all__ = ["Enemy" , "Player" ]
0 commit comments