Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Combat encounter

We will refactor the following code in order to apply the principles of single responsibility and the Stepdown Rule.

  1. Create a Lab12/ directory as well as the following directories and files.

Lab12/
├── include/
│    ├── character.h
│    └── combat-encounter.h
├── source/
│    ├── character.cpp
│    ├── combat-encounter.cpp
│    └── main.cpp
├── compile_flags.txt
└── makefile
character.h
combat-encounter.h
character.cpp
combat-encounter.cpp
main.cpp
compile_flags.txt
makefile
#ifndef CHARACTER_H
#define CHARACTER_H

#include <string>

class Character {
public:
    Character(const std::string& name, int health, int attack, int defense, int healAmount);

    std::string getName() const;
    int getHealth() const;
    int getAttack() const;
    int getDefense() const;
    int getHealAmount() const;

    bool isAlive() const;
    void takeDamage(int damage);
    void heal();

private:
    std::string mName;
    int mHealth;
    int mAttack;
    int mDefense;
    int mHealAmount;
};

#endif

You can add this lab to the task inputs in tasks.json and create a configuration in launch.json in order to compile, run, and debug it through the VSCodium interface, if you wish to do so.

  1. Run the code and try to understand the program’s behavior.

Our goal is to refactor CombatEncounter::run(), which will likely lead us to modify Character, CombatEncounter, and introduce new classes.

  1. First, we will extract the output operations into static methods in a CombatPrinter class.

In the implementation of the output methods in CombatPrinter, some outputs are related to a single character, such as displaying its attributes or its health. In this case, the responsibility naturally belongs to the Character class.

  1. You can extract the display of character attributes into Character::displayInformation and the display of health into Character::displayHealth.

Once the functions related to output (std::cout) are properly refactored, we will move on to handling user input (std::cin). For now, this responsibility is directly handled by CombatEncounter using enum Action.

  1. We will extract enum Action and move it into a class InputAction, with a method readAction that retrieves user input.

Now, we want the combat loop to be easy to read. A pseudo-code of CombatEncounter::run() should look like this:

  1. We will extract the hero’s and the enemy’s turns into CombatEncounter::playHeroTurn() and CombatEncounter::playEnemyTurn() so that CombatEncounter::run() properly follows The Stepdown Rule.

Finally, the damage calculation in both the hero’s and the enemy’s turns is the same. Extracting this calculation into a function makes the code less redundant and easier to modify if the damage formula changes in the future.

  1. We will therefore extract the calculation of int damage into a method CombatEncounter::calculateDamage.