Projet Fil Rouge V5 — Solutions

Projet Fil Rouge V5 — Solutions #

Interface IObject (nouveau en V5) #

1242.2_Project_V5_FilRouge_IObject

IObject.h

namespace He_Arc::RPG
{
  class IObject
  {
  public:
    virtual ~IObject() = default;
    virtual std::string getName() const = 0;
    virtual int getFeature() const = 0;
  };
}

Classe Sword (adaptée pour IObject) #

1242.2_Project_V5_FilRouge_Sword

Sword.h

namespace He_Arc::RPG
{
  class Sword : public IObject
  {
  public:
    Sword() = default;
    explicit Sword(int damage) : m_damage(damage) {}
    virtual ~Sword() override = default;

    std::string getName() const override;
    int getFeature() const override;

  private:
    int m_damage{10};
  };
}

Sword.cpp

#include "Sword.h"

namespace He_Arc::RPG
{
  std::string Sword::getName() const
  {
    return "Sword";
  }

  int Sword::getFeature() const
  {
    return m_damage;
  }
}

Classe Shield (nouveau en V5) #

1242.2_Project_V5_FilRouge_Shield

Shield.h

namespace He_Arc::RPG
{
  class Shield : public IObject
  {
  public:
    Shield() = default;
    explicit Shield(int solidity) : m_solidity(solidity) {}
    virtual ~Shield() override = default;

    std::string getName() const override;
    int getFeature() const override;

  private:
    int m_solidity{5};
  };
}

Shield.cpp

#include "Shield.h"

namespace He_Arc::RPG
{
  std::string Shield::getName() const
  {
    return "Shield";
  }

  int Shield::getFeature() const
  {
    return m_solidity;
  }
}

Classe Potion (nouveau en V5) #

1242.2_Project_V5_FilRouge_Potion

Potion.h

namespace He_Arc::RPG
{
  class Potion : public IObject
  {
  public:
    Potion() = default;
    explicit Potion(int power) : m_power(power) {}
    virtual ~Potion() override = default;

    std::string getName() const override;
    int getFeature() const override;

  private:
    int m_power{10};
  };
}

Potion.cpp

#include "Potion.h"

namespace He_Arc::RPG
{
  std::string Potion::getName() const
  {
    return "Potion";
  }

  int Potion::getFeature() const
  {
    return m_power;
  }
}

Classe Backpack (nouveau en V5) #

1242.2_Project_V5_FilRouge_Backpack

Backpack.h

namespace He_Arc::RPG
{
  class Backpack
  {
  public:
    Backpack() = default;
    virtual ~Backpack() = default;

    void pack(IObject* pObject);
    IObject* unPack();
    bool isNotEmpty() const;

  private:
    std::stack<IObject*> m_stack;
  };
}

Backpack.cpp

namespace He_Arc::RPG
{
  void Backpack::pack(IObject* pObject)
  {
    m_stack.push(pObject);
  }

  IObject* Backpack::unPack()
  {
    auto pObject = m_stack.top();
    m_stack.pop();
    return pObject;
  }

  bool Backpack::isNotEmpty() const
  {
    return !m_stack.empty();
  }
}

Classe Hero (modifiée en V5 — IObject + Backpack) #

1242.2_Project_V5_FilRouge_Hero

Hero.h

namespace He_Arc::RPG
{
  class Hero
  {
  public:
    Hero() = default;
    Hero(const Hero&) = delete;
    Hero& operator=(const Hero&) = delete;

    Hero(int strength, int agility, int intelligence, double hp, std::string name, IObject* pObject);
    virtual ~Hero();

    virtual void show() const;
    virtual void interact(const Hero& other) = 0;

    std::string getName() const { return m_name; }
    int getStrength() const { return m_strength; }
    int getAgility() const { return m_agility; }
    int getIntelligence() const { return m_intelligence; }
    double getHp() const { return m_hp; }

    Backpack& getBackpack() { return m_backpack; }

    friend std::ostream& operator<<(std::ostream& s, const Hero& p);

  protected:
    int m_strength{0};
    int m_agility{0};
    int m_intelligence{0};
    double m_hp{0};
    std::string m_name{"no name"};
    IObject* m_pObject{nullptr};

  private:
    Backpack m_backpack;
  };

  std::ostream& operator<<(std::ostream& s, const Hero& p);
}

Hero.cpp

namespace He_Arc::RPG
{
  Hero::Hero(int strength, int agility, int intelligence, double hp, std::string name, IObject* pObject)
      : m_strength(strength), m_agility(agility), m_intelligence(intelligence),
        m_hp(hp), m_name(std::move(name)), m_pObject(pObject) {}

  Hero::~Hero()
  {
    delete m_pObject;
    m_pObject = nullptr;
  }

  void Hero::show() const
  {
    std::println("=================");
    std::println("HERO: {}", m_name);
    std::println("=================");
    std::println("strength: {}", m_strength);
    std::println("agility: {}", m_agility);
    std::println("intelligence: {}", m_intelligence);
    std::println("HP: {}", m_hp);
    std::println("{}: {}", m_pObject->getName(), m_pObject->getFeature());
  }

  void Hero::interact(const Hero& other)
  {
    std::println("Hello valiant {}! I'm {}", other.getName(), m_name);
  }

  std::ostream& operator<<(std::ostream& s, const Hero& p)
  {
    s << "=================\n"
      << "HERO: " << p.getName() << '\n'
      << "=================\n"
      << "strength: " << p.getStrength() << '\n'
      << "agility: " << p.getAgility() << '\n'
      << "intelligence: " << p.getIntelligence() << '\n'
      << "HP: " << p.getHp() << '\n';
    return s;
  }
}

Classe Warrior (modifiée en V5 — arme par défaut) #

1242.2_Project_V5_FilRouge_Warrior

Warrior.h

namespace He_Arc::RPG
{
  class Warrior : public Hero
  {
  public:
    Warrior(int strength = 10, int agility = 5, int intelligence = 1,
            double hp = 20, std::string name = "no_name_warrior")
        : Hero(strength, agility, intelligence, hp, std::move(name), new Sword()) {}

    virtual ~Warrior() override = default;

    void interact(const Hero& other) override;
  };
}

Warrior.cpp

#include "Warrior.h"

#include <print>

namespace He_Arc::RPG
{
  void Warrior::interact(const Hero& other)
  {
    std::println("I will fight you! @{}", other.getName());
  }
}

Classe Wizard (modifiée en V5 — objet par défaut) #

1242.2_Project_V5_FilRouge_Wizard

Wizard.h

namespace He_Arc::RPG
{
  class Wizard : public Hero
  {
  public:
    Wizard(int strength = 10, int agility = 5, int intelligence = 1,
           double hp = 20, std::string name = "no_name_wizard", int mana = 10)
        : Hero(strength, agility, intelligence, hp, std::move(name), new Potion()),
          m_mana(mana) {}

    virtual ~Wizard() override = default;

    void show() const override;
    void interact(const Hero& other) override;
    void castSpell(Hero& other);

  protected:
    int m_mana{0};
  };
}

Wizard.cpp

namespace He_Arc::RPG
{
  void Wizard::show() const
  {
    Hero::show();
    std::println("Mana: {}", m_mana);
  }

  void Wizard::interact([[maybe_unused]] const Hero& other)
  {
    std::println("Hello fellow traveler! I'm a bit lost, do you know where the Shire is?");
  }

  void Wizard::castSpell([[maybe_unused]] Hero& other)
  {
    if (m_mana > 2)
    {
      std::println("FIREBALL!! hahaha!");
      m_mana -= 2;
    }
    else
    {
      std::println("Not enough mana!! Run?");
    }
  }
}

Classe Necromancer (inchangée depuis V3) #

1242.2_Project_V5_FilRouge_Necromancer

Necromancer.h

namespace He_Arc::RPG
{
  class Necromancer : public Wizard
  {
  public:
    Necromancer(int strength = 10, int agility = 5, int intelligence = 1,
                double hp = 20, std::string name = "no_name_necromancer", int mana = 10)
        : Wizard(strength, agility, intelligence, hp, std::move(name), mana) {}

    virtual ~Necromancer() override = default;

    void riseUndeads();
  };
}

Necromancer.cpp

#include "Necromancer.h"

#include <print>

namespace He_Arc::RPG
{
  void Necromancer::riseUndeads()
  {
    if (m_mana > 2)
    {
      std::println("Creating undead... work in progress");
      m_mana -= 2;
    }
    else
    {
      std::println("Not enough mana!!");
    }
  }
}

Utilitaire #

1242.2_Project_V5_FilRouge_Utility

Utility.h

#pragma once

namespace He_Arc::RPG::Utility
{
  template <typename T>
  inline void deletePtr(T*& rPtr)
  {
    delete rPtr;
    rPtr = nullptr;
  }
}

Programme principal (étape 12 — Backpack) #

1242.2_Project_V5_FilRouge_main

main.cpp

int main()
{
    Warrior gimli = {10, 5, 1, 20, "Gimli"};
    Wizard gandalf = {2, 2, 10, 10, "Gandalf", 10};
    Necromancer sauron = {20, 20, 10, 999.9, "Sauron", 50};

    gimli.show();
    std::println("");
    gandalf.show();
    std::println("");
    sauron.show();
    std::println("");

    gimli.interact(gandalf);
    gandalf.interact(sauron);
    sauron.interact(gimli);

    sauron.castSpell(gandalf);
    sauron.riseUndeads();

    sauron.show();
    std::println("");

    // V4: Polymorphism with std::list
    auto pHero1 = new Warrior(2, 2, 1, 10, "Twoflower");
    auto pHero2 = new Warrior(4, 12, 10, 10, "Weasel");
    auto pHero3 = new Wizard(2, 2, 10, 10, "Rincewind", 3);
    auto pHero4 = new Necromancer(1, 1, 1, 10, "G.A. Romero", 50);
    auto pHero5 = new Warrior(10, 7, 3, 20, "Bravd");

    std::list<Hero*> myParty = {pHero1, pHero2, pHero3, pHero4, pHero5};

    for (const auto& hero : myParty)
    {
        hero->show();
    }

    for (auto& hero : myParty)
    {
        delete hero;
        hero = nullptr;
    }

    // V5: Backpack (LIFO inventory)
    std::println("BackPack test");

    gimli.getBackpack().pack(new Sword());
    gimli.getBackpack().pack(new Sword());
    gimli.getBackpack().pack(new Sword());
    gimli.getBackpack().pack(new Shield());
    gimli.getBackpack().pack(new Shield());
    gimli.getBackpack().pack(new Potion());

    std::println("\nThe backpack of {} contains:", gimli.getName());

    while (gimli.getBackpack().isNotEmpty())
    {
        auto pObject = gimli.getBackpack().unPack();
        std::println(" - {} ({})", pObject->getName(), pObject->getFeature());
        delete pObject;
        pObject = nullptr;
    }

    return 0;
}