Wizards, Thieves and Knights
“Wizards, Thieves and Knights” (WTK) game is a “Paper, Rock and Scissors” clone but in a fantasy setting. It comes with a simple command line interface where the use must type in his or her choice. The enemy is controlled by the script. The player’s goal is to gain as many score points, as it possible.
Code organization
Use separate modules to maintain your code base. For example:
/
|-- engine.py
|-- exceptions.py
|-- models.py
|-- settings.py
General playground description
The game process is divided into rounds. Each round consists of attack and defence stages. Rounds are repeated, until player is defeated.
Fight rules
It’s simple…
Wizard beats Knight
Thief beats Wizard
Knight beats Thief
Attack stage
Player selects the choice to attack from wizard, thief or knight, enemy selects the choice for defence from the same options by random. If the attack is successful:
enemy health is decreased
player gains score points
In case enemy is defeated:
a new enemy instance is initialized using higher level
player gains some extra score points
next defence stage is skipped, and player attacks again
Defence stage
Player selects the choice to defend from wizard, thief or knight, enemy selects the choice to attack from the same options by random. If the attack is successful:
player health is decreased
If player is defeated:
report the message about gained score points to the terminal
write down player’s name and score points to “scores.txt” file
Exceptions
Enemy down
This is an exceptional scenario when enemy is defeated. A custom exception
EnemyDown
should be used to track these cases. Exception should provide
the details on the enemy’s instance, especially its level.
- class wtk.exceptions.EnemyDown(model: _AbstractModel)
Raised when an enemy is defeated
Game over
This is an exceptional scenario when player is defeated. A custom exception
GameOver
should be used to track these cases. Exception should provide
the details on the player’s instance, especially its score points.
- class wtk.exceptions.GameOver(model: _AbstractModel)
Raised when a player is defeated
Models
Enemy
- class wtk.models.Enemy(level: int = 1)
Enemy model
- Variables:
level – enemy’s level value
health – enemy’s instance health points
Represents the playing enemy-bot.
- __init__(level: int = 1) None
Initialize instance
- Parameters:
level (int) – an enemy’s level indicator
Health value is equal to the level value.
- decrease_health() None
Decrease health points
- Raise:
EnemyDown
This method decreases the health meter value. When it comes to be less than 1 (one) an
EnemyDown
exception is raised.
- select_attack() FightChoice
Return a random fight choice
- Returns:
a fight choice
Choices made by an enemy are random.
- select_defence() FightChoice
Return a random fight choice
- Returns:
a fight choice
Choices made by an enemy are random.
You are free to implement other methods you like, if needed.
Player
- class wtk.models.Player(name: str)
Player model
- Variables:
name – player’s name
health – player’s instance health points
score – player’s instance gained score points
This model is controlled by the player.
- __init__(name: str) None
Initialize instance
- Parameters:
name (str) – a player’s name
This method performs player instance initialization. It set instance name, initial score points value and health.
- attack(enemy: Enemy) None
Attack an enemy
Perform attack on an enemy instance. This method takes an enemy instance as an argument. After that, it takes attack choice from the player model and the defence choice from an enemy model. After fight result calculation required operation are to be performed (decrease enemy health, assign score points etc.). Based on fight result should print out a message:
“YOUR ATTACK IS SUCCESSFUL!”
“YOUR ATTACK IS FAILED!”
“IT’S A DRAW!”
- decrease_health() None
Decrease health points
- Raise:
GameOver
This method decreases the health meter value. When it comes to be less than 1 (one) an
GameOver
exception is raised.
- defence(enemy: Enemy) None
Defend from an enemy’s attack
Perform defence from an enemy attack. This method takes an enemy instance as an argument. After that, it takes defence choice from the player model and the attack choice from an enemy model. After fight result calculation required operation are to be performed (decrease player health). Based on fight result should print out a message:
“YOUR DEFENCE IS SUCCESSFUL!”
“YOUR DEFENCE IS FAILED!”
“IT’S A DRAW!”
- static fight(attack: FightChoice, defence: FightChoice) FightResult
Fight result calculation interface
The method calculates the fight result based on the game rules:
wizard beats knight
thief beats wizard
knight beats thief
- select_attack() FightChoice
Return fight choice from the user’s prompt
- Returns:
a fight choice
The player is asked to make their decision for the upcoming fight. The chosen value is validated and if it is invalid the question is repeated.
- select_defence() FightChoice
Return fight choice from the user’s prompt
- Returns:
a fight choice
The player is asked to make their decision for the upcoming fight. The chosen value is validated and if it is invalid the question is repeated.
Settings
Settings module contains constants values for the game.
For example,
- wtk.settings.INITIAL_PLAYER_HEALTH: int
Initial player health value
- wtk.settings.INITIAL_ENEMY_LEVEL: int
Initial enemy level value
- wtk.settings.SCORE_SUCCESS_ATTACK: int
Score points value to assign when player’s attack is successful
- wtk.settings.SCORE_ENEMY_DOWN: int
Score points value to assign when enemy is defeated
You may also define messages with this module, for example:
- wtk.settings.MSG_SUCCESS_ATTACK: str = 'YOUR ATTACK IS SUCCESSFUL!'
Successful attack message
- wtk.settings.MSG_SUCCESS_DEFENCE: str = 'YOUR DEFENCE IS SUCCESSFUL!'
Successful defence message
- wtk.settings.MSG_FAILURE_ATTACK: str = 'YOUR ATTACK IS FAILED!'
Failed attack message
- wtk.settings.MSG_FAILURE_DEFENCE: str = 'YOUR DEFENCE HAS BEEN BREACHED!'
Failed defence message
- wtk.settings.MSG_DRAW: str = "IT'S A DRAW!"
Draw fight message
Engine
Engine module should provide two functions:
get_player_name
play
Player name getter
Asks the user to type in his or her name and return it back. Leading and trailing whitespaces are to be trimmed. Name should contain at least one character.
- wtk.engine.get_player_name() str
Return a player’s name from the user prompt
- Returns:
a player defined name
A validation process is performed as well. The player name cannot be an empty string.
Play
This function initializes player and enemy instance.
It processes game rounds inside of an endless loop stage by stage.
If an enemy is defeated - a new one should be initialized with level increased
by 1 (one). This case should be reported to the terminal.
If a player is defeated - the “Game Over” message should be reported to the
terminal.
KeyboardInterrupt
should be handled as well - it’s behavior is similar
to “Game Over” event, but “game over” message should be omitted.
- wtk.engine.play() None
Run the game
The function initializes player and enemy instances. After that it runs the game process in an endless loop. Once the player is defeated - it stops the execution.
Optional Enhancements
Add scores processor to show top-10 scores from a record table.
Create game menu, for example:
AVAILABLE MENU CHOICES: PLAY, SCORES, EXIT TYPE YOUR CHOICE HERE:
Store score table to the database instead of using text file.