# You must make sure to run all cells in sequence using shift + enter or you might encounter errors
from pykubegrader.initialize import initialize_assignment

responses = initialize_assignment("1_world_of_warcraft", "week_7", "lab", assignment_points = 186.0, assignment_tag = 'week7-lab')

# Initialize Otter
import otter
grader = otter.Notebook("1_world_of_warcraft.ipynb")

๐Ÿงช๐Ÿ  Welcome to Azeroth! ๐ŸŒโš”๏ธโœจ#

Note, this assignment counts for both a lab and a homework, assignment.

In the sprawling, war-torn lands of Azeroth, where mighty warriors, cunning rogues, and wise mages roam, World of Warcraft (WoW) brings players into an epic adventure filled with magic, battles, and legendary loot. Whether youโ€™re defending your faction in the battlegrounds, slaying dragons in deep dungeons, or trading in the bustling streets of Stormwind, WoW is a game of endless possibilities.

From the moment you create your character, choosing from noble Humans, fierce Orcs, or mystical Night Elves, youโ€™re thrust into a world where every decision matters. Will you wield mighty spells as a Mage, charge into battle as a Warrior, or vanish into the shadows as a Rogue? Your equipment, spells, and abilities define your journey, and mastering them is key to survival.

But Azeroth isnโ€™t just about brute strengthโ€”itโ€™s about strategy. Equipping the right gear, managing your resources, and casting spells at the perfect moment can be the difference between victory and defeat. Speaking of spellsโ€ฆ

Can you figure out how to implement a character class system that mirrors WoWโ€™s depth? ๐Ÿน๐Ÿง™โ€โ™‚๏ธโšก#

The following code lays the groundwork for a WoW-inspired RPG system, featuring items, spells, races, and classes. Study the mechanics, then dive into the arcane arts of programming to shape your own heroโ€™s destiny! ๐ŸŽฎ๐Ÿ”ฅ

Gear Up, Hero! ๐Ÿ›ก๏ธโš”๏ธ๐Ÿ’Ž#

In World of Warcraft, your character is only as strong as the gear and items they carry. Whether itโ€™s a health potion that saves you in the heat of battle, a mystic robe that enhances your spellcasting, or a legendary weapon that strikes fear into your enemies, items are the backbone of your power progression.

Every potion, weapon, and armor piece affects your stats in different waysโ€”some increase your strength, others restore your health, and the best ones? Well, they might just turn the tide of battle in your favor. Choosing the right items and knowing when to use them is the key to survival!

The following code defines an Item system, allowing different items to modify a characterโ€™s stats dynamically. Study it well, because in Azeroth, heroes are only as mighty as the gear they wield! ๐Ÿน๐Ÿ”ฎ๐Ÿ”ฅ

# import ABC and abstractmethod from the abc module
...

# Create an Item class 
...
    """Base class for all items."""

    # Create an init method with the following attributes:
    # name (str), effect (str), stat (str), value (int), slot (str) as an optional that defaults to None.
    # assign the attributes to self
    ...
    
    def apply(self, character):
        """
        Applies the item's effect to the given character.
        If the item is a Weapon or Armor, it will be equipped instead of consumed.
        """
            
        # For consumable items (potions etc), apply the effect
        if self.effect == "increase":
            if self.stat == "health":
                character.base_health += self.value
            elif self.stat == "mana":
                character.base_mana += self.value
            elif self.stat == "strength":
                character.strength += self.value
            elif self.stat == "agility":
                character.agility += self.value
            elif self.stat == "intellect":
                character.intellect += self.value
        elif self.effect == "restore":
            if self.stat == "health":
                character.base_health = min(
                    character.base_health + self.value, character.max_health
                )
            elif self.stat == "mana":
                character.base_mana = min(
                    character.base_mana + self.value, character.max_mana
                )
        
        return f"{character.name} used {self.name} โ†’ {self.stat} +{self.value}!"
grader.check("Item-class-builder")

Question 1 (Points: 16.0): Gear Up, Champion! ๐Ÿ›ก๏ธโš”๏ธ#

In the vast lands of Azeroth, where battles rage and monsters lurk, a hero is only as good as their gear. You wouldnโ€™t charge into battle wearing a flimsy tunic, would you? And fighting off a dragon with your bare fists? Thatโ€™s a one-way ticket to the graveyard!

Thatโ€™s why armor and weapons are essential. A sturdy chestplate can absorb crushing blows, while a razor-sharp sword can cleave through enemies with ease. Whether youโ€™re a mighty warrior, a stealthy rogue, or a powerful mage, the right equipment can mean the difference between victory and defeat.

Letโ€™s take a look at how armor and weapons work in our World of Warcraft-inspired RPG system!

# define the Armor class, which inherits from the Item class
...
    """
    Represents protective gear that enhances a characterโ€™s defensive stats.

    Armor items provide two key stat boosts:
    - `defense`: Reduces incoming damage.
    - `agility`: Improves evasion and movement speed.

    Parameters:
    -----------
    name : str
        The name of the armor (e.g., "Knightโ€™s Plate", "Shadow Cloak").
    stat : str
        The primary stat affected by the armor (e.g., "defense", "agility").
    value : int
        The amount of additional stat provided by the armor.
    slot : str
        The equipment slot where the armor is worn (e.g., "chest", "legs", "head").

    Effects:
    --------
    - **Equipping armor** increases the characterโ€™s overall survivability.
    - **Higher agility armor** may benefit classes like rogues or hunters.

    Example Usage:
    --------------
    >>> chestplate = Armor(name="Dragonbone Chestplate", stat="defense", value=50, slot="chest")
    >>> print(chestplate.name, chestplate.stat, chestplate.value, chestplate.slot)
    "Dragonbone Chestplate", "defense", 50, "chest"
    """
    # Define the __init__ method with the following attributes:
    # name (str), stat (str), value (int), slot (str)
    # call the super() method to initialize the attributes
    # assign the stat, value, and slot attributes to self -- this is done in the super() method
    # the default effect should be always "increase"
    ...
    
    # define the apply method, this should call the equip_item method on the character
    # this should replace the apply method in the Item class using abstraction
    # return the character object having called the equip_item method, on the armor object
    ...


# Create a weapon class that inherits from the Item class
...
    """
    Represents an offensive item that enhances a characterโ€™s damage output.

    Weapons provide two key benefits:
    - `damage`: The amount of raw attack power added to the characterโ€™s abilities.
    - `stat`: A bonus applied to a primary stat (e.g., strength or intellect).

    Parameters:
    -----------
    name : str
        The name of the weapon (e.g., "Flaming Sword", "Ice Staff").
    value : int
        The base damage value of the weapon.
    stat : str
        The primary stat affected by the weapon (e.g., "strength", "intellect").
    slot : str, optional
        The equipment slot, default is "weapon".

    Effects:
    --------
    - **Melee weapons** boost strength and increase physical attack power.
    - **Magic staves and wands** enhance intellect, increasing spell potency.
    - **Different classes benefit from different weapons** (e.g., warriors favor axes, mages favor staves).

    Example Usage:
    --------------
    >>> sword = Weapon(name="Doomblade", value=75, stat="strength")
    >>> print(sword.name, sword.value, sword.stat, sword.slot)
    "Doomblade", 75, "strength", "weapon"
    """
    # Define the __init__ method with the following attributes:
    # name (str), value (int), stat (str), slot (str)
    # call the super() method to initialize the attributes
    # the default should be to "increase" the stat
    ...
    
    # define the apply method, this should call the equip_item method on the character
    # this should replace the apply method in the Item class using abstraction
    # return the character object having called the equip_item method, on the weapon object
    ...
    
    
grader.check("Armor-class-builder")

Unleash the Arcane! ๐Ÿ”ฅโšก๐Ÿง™#

Magic is the lifeblood of Azerothโ€”from the fiery blasts of a mageโ€™s Fireball to the shadowy whispers of a warlockโ€™s curse. Whether youโ€™re hurling ice at your enemies or summoning divine light to heal allies, spells are a powerful force that can turn the tide of battle.

But beware, young sorcerer! ๐Ÿ”ฎโœจ Casting spells isnโ€™t freeโ€”each one drains your mana, and the most powerful incantations require a high level of mastery. Run out of mana in the middle of a fight? You might find yourself at the mercy of a rampaging orcโ€ฆ or worse!

The Spell class below allows spellcasters to cast abilities, but only if they have the required level and enough mana to fuel their arcane power. Study it wellโ€”your magic-wielding future depends on it! ๐Ÿ”ฅโš”๏ธ

# Create a class called Spell.
...
    """
    Represents a magical ability that consumes mana when cast.

    Spells are powerful abilities that characters can use in battle. Each spell has
    a name, damage value, mana cost, and a minimum level requirement. Characters
    must meet the level requirement and have sufficient mana to cast the spell.

    Attributes:
    -----------
    name : str
        The name of the spell (e.g., "Fireball", "Healing Light", "Shadow Bolt").
    damage : int
        The amount of damage the spell inflicts on an enemy (or healing power for healing spells).
    mana_cost : int
        The amount of mana required to cast the spell.
    level_required : int
        The minimum character level required to use the spell.

    Methods:
    --------
    cast(character):
        Attempts to cast the spell using the given character.
        - If the character's level is too low, it returns a message indicating that they cannot cast it.
        - If the character does not have enough mana, it returns a message about insufficient mana.
        - If the spell is successfully cast, the character's mana is reduced, and a message
        is returned confirming the spell and its damage.

    Example Usage:
    --------------
    >>> mage = Character(name="Merlin", race=Human(), class_type=Mage())
    >>> fireball = Spell(name="Fireball", damage=50, mana_cost=20, level_required=1)
    >>> print(fireball.cast(mage))
    "Merlin cast Fireball, dealing 50 damage!"

    Notes:
    ------
    - This class assumes the `character` parameter has attributes: `name`, `level`, and `base_mana`.
    - The method does not handle spell resistance or critical hits.
    """
    # Define the __init__ method with the following attributes:
    # name (str), damage (int), mana_cost (int), level_required (int)
    # assign the attributes to self
    ...

    # Define the cast method with the following parameters:
    # self, character
    # if the character's level is less than the level required for the spell
    # return a message saying "{character.name} is not high enough level to cast {self.name}!"
    # if the character does not have enough mana to cast the spell
    # return a message saying "Not enough mana to cast {self.name}!"
    # otherwise, subtract the mana cost from the character's base mana
    # return a message saying "{character.name} cast {self.name}, dealing {self.damage} damage!"
    ...
grader.check("Spell-casting-class")

Forging Your Path: The Legacy of Class Archetypes in Azeroth โš”๏ธ๐Ÿ”ฎ๐Ÿน#

In the grand saga of Azeroth, where heroes rise and legends are forged, your character class defines your role, abilities, and combat style. Choosing a class is more than just selecting a titleโ€”itโ€™s about embracing an identity.

Will you become a Warrior, clad in heavy armor, leading the charge into battle with raw strength and resilience? Or perhaps a Mage, wielding the destructive power of fire and ice, shaping reality itself with arcane mastery? Maybe you prefer the shadows, lurking unseen as a Rogue, striking with deadly precision before vanishing without a trace.

Each class type offers a unique set of advantages, spells, and abilities, shaping how you interact with the world and engage in combat. Some excel in close-quarters melee combat, others thrive in long-range spellcasting, while hybrid classes blend multiple disciplines, mastering a balance of offense and defense.

The ClassType class below serves as a blueprint for all character archetypes, setting the foundation for base stats, special abilities, and spellcasting potential. As an abstract class, it enforces a structure, ensuring that each specific classโ€”be it a Warrior, Mage, or Rogueโ€”must define its own special ability progression.

So, adventurer, the question remains:
What kind of hero will you become? โš”๏ธ๐Ÿ”ฅโœจ

# Create a class called ClassType.
# It should inherit from the ABC class
# It should have the following attributes:
# name (str), base_health (int), base_mana (int)
# It should have the following methods:
# special_ability()
...
    """
    The ClassType class serves as an abstract base class for all character classes in the game.
    
    Attributes:
        name (str): The name of the character class.
        base_health (int): The base health points for the character class. Defaults to 100.
        base_mana (int): The base mana points for the character class. Defaults to 50.
        abilities (dict): A dictionary mapping levels to abilities unlocked at those levels.
        spells (list): A list of spells available to the character class.
    
    Methods:
        __init__(name, **kwargs):
            Initializes the ClassType with a name, base health, base mana, abilities, and spells.
        
        special_ability(level):
            Abstract method that returns the ability unlocked at a given level.
            Must be implemented by subclasses.
    """
    # define the __init__ method with the following attributes:
    # use the **kwargs to initialize the attributes
    # set the base_health and base_mana attributes to the values in kwargs with default values of 100 and 50 respectively
    # set the abilities and spells attributes to empty dictionaries and lists respectively
    ...
    
    # define the special_ability method, this is an abstract method that must be implemented by subclasses
    # it should return the ability unlocked at a given level, this should call the abilities dictionary with the level as the key. 
    # if the level is not in the dictionary, return "No new abilities at this level."
    ...
grader.check("ClassType-class")

Gear Up, Champion: Mastering Equipment in Azeroth โš”๏ธ๐Ÿ›ก๏ธ#

In the battle-scarred world of Azeroth, the difference between victory and defeat often comes down to the gear you wield. A warrior without armor is just a fool charging into battle, and a mage without a staff is nothing more than a scholar in robes. Every hero needs the right equipment to survive, thrive, and dominate the battlefield.

From the legendary helmets of fallen kings to enchanted blades forged in dragonfire, equipment grants heroes increased power, defense, and agility. But managing this gear is no easy taskโ€”equipping the right items at the right time can be the key to unlocking your full potential.

The EquipmentManager class below ensures that characters can properly equip and unequip items, allowing them to maximize their strength, resilience, and magic power. Whether youโ€™re donning a new chestplate before a raid or swapping weapons for a duel, this system ensures that every piece of gear finds its rightful place.

So, hero, choose wiselyโ€”the right equipment can make you a legend. โšก๐Ÿ”ฅ๐Ÿน

# Create a class called EquipmentManager.
# It should have the following attributes:
# equipped_items (dict): A dictionary mapping slots to items
# It should have the following methods:
# equip_item(item)
# unequip_item(slot)
...
        self.equipped_items = {
            "head": None,
            "chest": None,
            "legs": None,
            "weapon": None,
        }

    # define the equip_item method with the following parameters:
    # self, item
    # if the item.slot is in the equipped_items dictionary
    # set the equipped_items dictionary to the item.slot key to the item
    # return a message saying "Equipped {item.name} in {item.slot} slot!"
    # otherwise, return a message saying "Cannot equip this item."
    ...
    
    # define the unequip_item method with the following parameters:
    # self, slot
    # if the slot is in the equipped_items dictionary and the slot is not None
    # set the equipped_items dictionary to the slot key to None
    # return a message saying "Unequipped {removed_item.name} from {slot} slot!"
    # otherwise, return a message saying "No item equipped in this slot."
    ...
grader.check("EquipmentManager-class")

The Unbreakable Vanguard: The Warriorโ€™s Path โš”๏ธ๐Ÿ›ก๏ธ๐Ÿ”ฅ#

In Azeroth, few embody raw power and unyielding resolve like the Warrior. Clad in heavy armor, wielding colossal weapons, and standing firm in the face of overwhelming odds, the Warrior is a living embodiment of strength and endurance.

Unlike fragile spellcasters who rely on mana or cunning rogues who lurk in the shadows, Warriors thrive in the thick of battle. They charge headfirst into combat, using their immense resilience and brute force to crush their enemies. Whether leading the charge in an epic siege or standing as the last line of defense, the Warrior never falters.

The Warrior class below builds upon the ClassType framework, defining a character with high health, minimal mana, and a set of abilities focused on physical combat. Warriors start with the powerful โ€œChargeโ€ ability, allowing them to rush into battle, and gain access to โ€œBattle Shoutโ€, a rallying cry that strengthens their allies.

Are you ready to take up your blade and shield, to stand firm against the darkness? Then the Warriorโ€™s path is yours to walk. โš”๏ธ๐Ÿ”ฅ๐Ÿ’€

# Create a class called Warrior.
# It should inherit from the ClassType class
# It should have the following attributes:
# name (str), base_health (int), base_mana (int)
# It should have the following methods:
# special_ability() which is a method inherited from the ClassType class
...
    # define the __init__ method with the following attributes:
    # name (str), base_health (int), base_mana (int)
    # use the **kwargs to initialize the attributes
    # set the base_health and base_mana attributes to the values in kwargs with default values of 150 and 30 respectively
    # set the abilities and spells attributes to empty dictionaries and lists respectively
    ...
        # call the super() method to initialize the attributes
        # make sure to pass the name to the super() method warrior - {name}
        # make sure to pass the base_health and base_mana to the super() method with default values of 150 and 30 respectively
        ...
        # Set the abilities to a dictionary with the key 1 and the value "Charge - Rush and deal damage!"
        # Set the spells to a list with the Spell object "Battle Shout", 0 damage, 10 mana cost, and level required of 2
        ...
    
    # Define the special_ability method with the following attributes:
    # self
    # return the abilities attribute 1
    ...
grader.check("Warrior-class")

Masters of the Arcane: The Path of the Mage ๐Ÿ”ฅ๐Ÿ“œโœจ#

In the mystical lands of Azeroth, knowledge is power, and no class wields it more destructively than the Mage. Masters of fire, frost, and arcane energy, Mages are glass cannonsโ€”fragile in body but capable of unleashing catastrophic destruction upon their foes.

With a flick of their wrist, a Mage can incinerate enemies with fire, freeze them solid with ice, or bend time and space to teleport across vast distances. Unlike warriors who charge into battle clad in heavy armor, Mages stand at a distance, strategically weaving spells that control, devastate, and bewilder their enemies.

The Mage class below is built upon the ClassType framework, defining a character with low health but immense mana reserves. Mages start with โ€œFireballโ€, a devastating spell that ignites foes, and later gain powerful spells like โ€œIce Barrierโ€ for protection and โ€œTeleportโ€ to traverse great distances.

If you seek to wield limitless magical potential, commanding fire, frost, and the arcane, then step forwardโ€”the path of the Mage awaits. ๐Ÿ”ฅ๐Ÿ“–โšก

# Create a class called Mage.
# It should inherit from the ClassType class
# It should have the following attributes:
# name (str), base_health (int), base_mana (int)
# It should have the following methods:
# special_ability() which is a method inherited from the ClassType class
...
    # define the __init__ method with the following attributes:
    # name (str), base_health (int), base_mana (int)
    # use the **kwargs to initialize the attributes
    # set the base_health and base_mana attributes to the values in kwargs with default values of 80 and 150 respectively
    ...
        # call the super() method to initialize the attributes
        # make sure to pass the name to the super() method mage
        # make sure to pass the base_health and base_mana to the super() method with default values of 80 and 150 respectively
        ...
        # Set the abilities to a dictionary with the key 1 and the value "Fireball - Cast a fire spell!"
        # Set the spells to a list with the Spell object "Fireball", 30 damage, 20 mana cost, and level required of 1
        # Set the spells to a list with the Spell object "Ice Barrier", 0 damage, 40 mana cost, and level required of 5
        # Set the spells to a list with the Spell object "Teleport", 0 damage, 50 mana cost, and level required of 10
        ...
        
    # Define the special_ability method with the following attributes:
    # self
    # return the abilities attribute 1
    ...
grader.check("Mage-class")

The Way of Balance: The Path of the Monk ๐ŸŒ€๐Ÿฅ‹โœจ#

In the vast and mystical lands of Azeroth, few warriors embody both discipline and harmony like the Monk. Trained in the art of hand-to-hand combat, spiritual energy, and inner balance, Monks channel their Chi to deliver swift, precise strikes while maintaining a deep connection to their surroundings.

Unlike warriors who rely on brute force or mages who manipulate arcane energies, Monks combine agility, wisdom, and spiritual resilience. They can strike with lightning-fast punches, redirect incoming attacks, and even heal wounds through meditation and energy flow. Whether as a fierce combatant, a tranquil healer, or a balanced master of both, the Monkโ€™s strength lies in their ability to adapt and flow like water.

The Monk class below builds upon the ClassType framework, defining a character with balanced health and mana, focusing on mobility, self-sustainability, and precise attacks. Monks begin with โ€œInner Focusโ€, allowing them to center their mind and body, and later gain access to โ€œChi Waveโ€, a technique that channels energy to strike enemies or heal allies.

Are you prepared to walk the path of balance, to master both body and spirit? If so, then the way of the Monk is yours to follow. ๐ŸŒ€๐Ÿฅ‹โœจ

# It should inherit from the ClassType class
# It should have the following attributes:
# name (str), base_health (int), base_mana (int)
# It should have the following methods:
# special_ability() which is a method inherited from the ClassType class
...
    # define the __init__ method with the following attributes:
    # name (str), base_health (int), base_mana (int)
    # use the **kwargs to initialize the attributes
    # set the base_health and base_mana attributes to the values in kwargs with default values of 120 and 90 respectively
    ...
        # call the super() method to initialize the attributes
        # make sure to pass the name to the super() method monk 
        # make sure to pass the base_health and base_mana to the super() method with default values of 120 and 90 respectively
        ...
        # Set the abilities to a dictionary with the key 1 and the value "Inner Focus - Center your mind and body for enhanced combat!"
        # Set the spells to a list with the Spell object "Chi Wave", 25 damage, 20 mana cost, and level required of 3
        # Set the spells to a list with the Spell object "Zen Meditation", 0 damage, 30 mana cost, and level required of 5
        # Set the spells to a list with the Spell object "Flying Serpent Kick", 40 damage, 25 mana cost, and level required of 7
        ...
        
    # Define the special_ability method with the following attributes:
    # self
    # return the abilities attribute 1
    ...
grader.check("Monk-class")

The Shield of Light: The Path of the Paladin ๐Ÿ›ก๏ธโœจโš”๏ธ#

In the realm of Azeroth, few warriors stand as resolute and unwavering as the Paladin. Champions of divine justice, Paladins wield the power of the Light to smite their enemies, shield their allies, and heal the wounded. Clad in shining armor and driven by an unbreakable sense of duty, they serve as the ultimate protectors against darkness.

Unlike reckless warriors who rely on brute strength or mages who manipulate the arcane, Paladins are a perfect blend of might and magic. They can strike down foes with holy-infused weapons, cleanse ailments with purifying energy, and stand unyielding in the face of overwhelming odds. Whether defending the weak, leading a charge, or calling upon divine power for miracles, the Paladin is a beacon of hope and strength.

The Paladin class below is built upon the ClassType framework, defining a character with high health, moderate mana, and a mix of offensive, defensive, and healing abilities. Paladins begin with โ€œDivine Strikeโ€, a melee attack imbued with holy energy, and later gain access to โ€œLay on Handsโ€, a miraculous healing spell that can restore an ally from the brink of death.

Will you wield the Light, bringing justice to the wicked and protection to the innocent? If so, the Paladinโ€™s oath is yours to take. โš”๏ธ๐Ÿ›ก๏ธโœจ

# It should inherit from the ClassType class
# It should have the following attributes:
# name (str), base_health (int), base_mana (int)
# It should have the following methods:
# special_ability() which is a method inherited from the ClassType class
...
    # define the __init__ method with the following attributes:
    # name (str), base_health (int), base_mana (int)
    # use the **kwargs to initialize the attributes
    # set the base_health and base_mana attributes to the values in kwargs with default values of 140 and 100 respectively
    ...
        # call the super() method to initialize the attributes
        # make sure to pass the name to the super() method paladin 
        # make sure to pass the base_health and base_mana to the super() method with default values of 140 and 100 respectively
        ...
        # Set the abilities to a dictionary with the key 1 and the value "Divine Strike - Strike with holy power, dealing extra damage!"
        # Set the spells to a list with the Spell object "Holy Light", 0 damage, 25 mana cost, and level required of 3
        # Set the spells to a list with the Spell object "Lay on Hands", 0 damage, 50 mana cost, and level required of 8
        # Set the spells to a list with the Spell object "Consecration", 15 damage, 20 mana cost, and level required of 5
        ...
        
    # Define the special_ability method with the following attributes:
    # self
    # return the abilities attribute 1
    ...
grader.check("Paladin-class")

Forging a Legend: The Essence of a Hero โš”๏ธ๐ŸŒŸ#

Every great saga begins with a hero. Whether a mighty warrior, a wise mage, or a shadowy rogue, every adventurer in Azeroth starts as a simple traveler with a name, and a chosen path. But through battle, experience, and the right gear, they grow into legends.

A character in this world is more than just a collection of statsโ€”they are a living story, shaped by the choices they make, the enemies they defeat, and the power they wield. As they gain experience, they level up, growing stronger with each battle. Through equipment, spells, and abilities, they carve out their own unique identity, setting themselves apart from others on their journey.

The Character class below serves as the core of any adventurer, seamlessly integrating:

  • Class Type ๐Ÿ”ฎ โ€“ Determining their combat style, abilities, and mana reserves.

  • Equipment Management ๐Ÿ›ก๏ธ โ€“ Controlling the weapons and armor they wield.

Heroes earn experience, level up, and harness their magical and physical prowess to become stronger. But the journey is long, and only those with true courage will rise above all others.

So, who will you become? Your adventure begins now. โšก๐Ÿ”ฅโœจ

# Build the Character class
# It should inherit from ClassType and EquipmentManager
# It should have the following attributes:
# name (str), class_type (ClassType), inventory (list) - default is an empty list, max_health (int) - default is 100, max_mana (int) - default is 50
...
    """
    A class to represent a character in the game.

    Attributes:
    -----------
    name : str
        The name of the character.
    class_type : ClassType
        The class type of the character.
    inventory : list
        The inventory of the character, default is an empty list.
    max_health : int
        The maximum health of the character, default is 100.
    max_mana : int
        The maximum mana of the character, default is 50.

    Methods:
    --------
    check_equipment(attribute):
        Checks if the character has any equipment equipped.
    base_health():
        Gets the base health of the character.
    base_health(value):
        Sets the base health of the character, ensuring it does not exceed max health or drop below zero.
    max_health():
        Gets the maximum health of the character.
    max_health(value):
        Sets the maximum health of the character, ensuring it is a positive value.
    base_mana():
        Gets the base mana of the character.
    base_mana(value):
        Sets the base mana of the character, ensuring it does not exceed max mana or drop below zero.
    max_mana():
        Gets the maximum mana of the character.
    max_mana(value):
        Sets the maximum mana of the character, ensuring it is a positive value.
    strength():
        Gets the strength of the character, including any equipment boosts.
    strength(value):
        Sets the strength of the character, ensuring it is never negative.
    agility():
        Gets the agility of the character, including any equipment boosts.
    agility(value):
        Sets the agility of the character, ensuring it is never negative.
    intellect():
        Gets the intellect of the character, including any equipment boosts.
    intellect(value):
        Sets the intellect of the character, ensuring it is never negative.
    gain_experience(xp):
        Adds experience points and levels up if needed.
    level_up():
        Increases the character's level and enhances their attributes.
    special_ability():
        Calls the special ability of the assigned class.
    cast_spell(spell_name):
        Attempts to cast a spell if known.
    add_to_inventory(item):
        Adds an item to the character's inventory.
    equip_from_inventory(item):
        Equips an item, removing any existing item in that slot first.
    unequip_item(slot):
        Unequips an item and removes its effects.
    view_equipped_items():
        Displays all currently equipped items.
    """
    
    # Write the __init__ method with the following parameters:
    # name (str), class_type (ClassType), inventory (list)- default is an empty list, max_health (int)- default is 100, max_mana (int)- default is 50
    ...
        """
        Constructs all the necessary attributes for the character object.

        Parameters:
        -----------
        name : str
            The name of the character.
        class_type : ClassType
            The class type of the character.
        inventory : list, optional
            The inventory of the character, default is an empty list.
        max_health : int, optional
            The maximum health of the character, default is 100.
        max_mana : int, optional
            The maximum mana of the character, default is 50.
        """
        # First initialize the max values
        # we want to use setters so by convention we use _ prefix to indicate a private variable
        # assign the max_health and max_mana to the private variables
        ...
        
        # Now initialize parent classes
        # super() is used to call the __init__ method of the parent class
        # We are initializing the ClassType
        # we pass the name, base_health, and base_mana to the super() method, these are obtained from the class_type object
        ...
        
        # Now we initialize the EquipmentManager
        # We can just call the EquipmentManager __init__ method, on the character object -- recall that this is the character class so self is the character object
        ...

        # Copy class-specific attributes
        # we can just assign the attributes to the character object
        # assign the name, class_type, spells, abilities, level, experience, inventory
        # for spells and abilities we can use the copy method to avoid shared reference, use the .copy() method
        ...
        
        # Initialize other attributes
        # we can just assign the attributes to the character object
        # assign the level = 1, experience = 0, inventory = inventory
        ...

        # Initialize other hidden attributes of the character object
        # strength = 10, agility = 10, intellect = 10
        # make sure to use the _ prefix to indicate a private variable
        ...
        
    # --- Check Equipment ---
    # an important utility is to check the equipment the character has equipped, and calculate the total attribute boost provided by the equipment
    # define a method called check_equipment(attribute) that takes an attribute (strength, agility, intellect) as input, it should return the total attribute boost provided by the equipment
    ...
        """
        Checks if the character has any equipment equipped.

        Parameters:
        -----------
        attribute : str
            The attribute to check for equipment.

        Returns:
        --------
        int
            The total attribute boost from equipped items.
        """
        # assign the initial attribute_boost to 0
        ...

        # iterate through the equipped items
        # if the item is not None and the item's stat matches the attribute, add the item's value to the attribute_boost
        # the value is always in the value attribute of the item, per the inheritance from the Item class
        ...
        
        # return the attribute_boost
        ...
        
    # --- Health ---
    # we can use the @property decorator to define a property for the base_health attribute
    ...
        """
        Gets the base health of the character.

        Returns:
        --------
        int
            The base health of the character.
        """
        # we can just return the private variable
        ...

    # we can use the @base_health.setter decorator to define a setter for the base_health attribute, this should take a value as input and set the private variable to the value
    ...
        """
        Sets the base health of the character, ensuring it does not exceed max health or drop below zero.

        Parameters:
        -----------
        value : int
            The new base health value.
        """
        # we can use the max and min functions to ensure the value is not below 0 or above the max health
        # this is the advantage of using setters and getters, we can control the value being set and ensure it is within a physical range
        ...

    # we can use the @property decorator to define a property for the max_health attribute
    ...
        """
        Gets the maximum health of the character.

        Returns:
        --------
        int
            The maximum health of the character.
        """
        # we can just return the private variable
        ...

    # we can use the @max_health.setter decorator to define a setter for the max_health attribute, this should take a value as input and set the private variable to the value
    ...
        """
        Sets the maximum health of the character, ensuring it is a positive value.

        Parameters:
        -----------
        value : int
            The new maximum health value.
        """
        # we can use the max function to ensure the value is not below 1
        ...

    # --- Mana ---
    # we can use the @property decorator to define a property for the base_mana attribute
    ...
        """
        Gets the base mana of the character.

        Returns:
        --------
        int
            The base mana of the character.
        """
        # we can just return the private variable
        ...

    # we can use the @base_mana.setter decorator to define a setter for the base_mana attribute, this should take a value as input and set the private variable to the value
    ...
        """
        Sets the base mana of the character, ensuring it does not exceed max mana or drop below zero.

        Parameters:
        -----------
        value : int
            The new base mana value.
        """
        # we can use the max and min functions to ensure the value is not below 0 or above the max mana
        ...

    # we can use the @property decorator to define a property for the max_mana attribute
    ...
        """
        Gets the maximum mana of the character.

        Returns:
        --------
        int
            The maximum mana of the character.
        """
        # we can just return the private variable
        ...

    # we can use the @max_mana.setter decorator to define a setter for the max_mana attribute, this should take a value as input and set the private variable to the value
    ...
        """
        Sets the maximum mana of the character, ensuring it is a positive value.

        Parameters:
        -----------
        value : int
            The new maximum mana value.
        """
        # we can use the max function to ensure the value is not below 1
        ...

    # --- Strength ---
    # we can use the @property decorator to define a property for the strength attribute
    ...
        """
        Gets the strength of the character, including any equipment boosts.

        Returns:
        --------
        int
            The total strength of the character.
        """
        # we can use the check_equipment method to get the attribute boost from the equipment
        ...
        # we can return the strength plus the attribute boost, remember to use the _ prefix to access the private variable
        ...

    # we can use the @strength.setter decorator to define a setter for the strength attribute, this should take a value as input and set the private variable to the value
    ...
        """
        Sets the strength of the character, ensuring it is never negative.

        Parameters:
        -----------
        value : int
            The new strength value.
        """
        # we can use the max function to ensure the value is not below 0
        ...

    # --- Agility ---
    # we can use the @property decorator to define a property for the agility attribute
    ...
        """
        Gets the agility of the character, including any equipment boosts.

        Returns:
        --------
        int
            The total agility of the character.
        """
        # we can use the check_equipment method to get the attribute boost from the equipment
        ...
        # we can return the agility plus the attribute boost, remember to use the _ prefix to access the private variable
        ...

    # we can use the @agility.setter decorator to define a setter for the agility attribute, this should take a value as input and set the private variable to the value
    ...
        """
        Sets the agility of the character, ensuring it is never negative.

        Parameters:
        -----------
        value : int
            The new agility value.
        """
        # we can use the max function to ensure the value is not below 0
        ...

    # --- Intellect ---
    # we can use the @property decorator to define a property for the intellect attribute
    ...
        """
        Gets the intellect of the character, including any equipment boosts.

        Returns:
        --------
        int
            The total intellect of the character.
        """
        # we can use the check_equipment method to get the attribute boost from the equipment
        ...
        # we can return the intellect plus the attribute boost, remember to use the _ prefix to access the private variable
        ...

    # we can use the @intellect.setter decorator to define a setter for the intellect attribute, this should take a value as input and set the private variable to the value
    ...
        """
        Sets the intellect of the character, ensuring it is never negative.

        Parameters:
        -----------
        value : int
            The new intellect value.
        """
        # we can use the max function to ensure the value is not below 0
        ...

    # --- Experience & Leveling ---
    
    # we want to define a method called gain_experience(xp) that takes an integer as input and adds the experience to the experience attribute
    # we also want to level up the character if the experience is greater than or equal to the level times 100
    # we can use the while loop to check if the experience is greater than or equal to the level times 100, and if it is, we can call the level_up method
    # we can use the += operator to add the experience to the experience attribute
    ...
        """
        Adds experience points and levels up if needed.

        Parameters:
        -----------
        xp : int
            The amount of experience points to add.
        """
        ...

    # we can define a method called level_up that increases the level and enhances the attributes
    # we can use the += operator to add the level to the level attribute by 1
    # we can use the += operator to add the max_health to the max_health attribute by 10
    # we can use the += operator to add the max_mana to the max_mana attribute by 5
    # we can use the += operator to add the strength to the strength attribute by 2
    # we can use the += operator to add the agility to the agility attribute by 2
    # we can use the += operator to add the intellect to the intellect attribute by 2
    # we can use the print function to print a message to the console "๐ŸŽ‰ {self.name} leveled up to Level {self.level}!"
    ...
    
    # --- Spell Casting ---
    # we can define a method called special_ability that calls the special_ability method of the class_type attribute
    # we can use the return statement to return the result of the special_ability method, this is in self.class_type.special_ability()
    ...
        """
        Calls the special ability of the assigned class.

        Returns:
        --------
        str
            The result of the special ability.
        """
        ...

    # we can define a method called cast_spell that takes a spell_name as input
    # we can use the for loop to iterate through the spells attribute of the class_type attribute
    # we can use the if statement to check if the spell_name is equal to the name of the spell
    # we can use the return statement to return the result of the spell.cast(self) method
    # we can use the return statement to return a message to the console "{self.name} does not know the spell {spell_name}."
    ...
        """
        Attempts to cast a spell if known.

        Parameters:
        -----------
        spell_name : str
            The name of the spell to cast.

        Returns:
        --------
        str
            The result of the spell casting attempt.
        """
        ...
        
    # --- Equipment ---
    # we can define a method called add_to_inventory that takes an item as input
    # we can use the append method to add the item to the inventory attribute
    # we can use the return statement to return a message to the console "{item.name} added to {self.name}'s inventory!"
    ...
        """
        Adds an item to the character's inventory.

        Parameters:
        -----------
        item : Item
            The item to add to the inventory.

        Returns:
        --------
        str
            A message confirming the item was added.
        """
        # we can use the append method to add the item to the inventory attribute
        # we can use the return statement to return a message to the console "{item.name} added to {self.name}'s inventory!"
        ...
    
    # we can define a method called equip_from_inventory that takes an item as input
    # we can use the if statement to check if the item.slot is in the equipped_items attribute
    # we can use the current_item variable to store the item in the equipped_items attribute
    # we can use the return statement to return a message to the console "Equipped {item.name} in {item.slot} slot!"
    # we can use the return statement to return a message to the console "Cannot equip this item."
    ...
        """
        Equips an item, removing any existing item in that slot first.
        Overrides the EquipmentManager's equip_item method.

        Parameters:
        -----------
        item : Item
            The item to equip.

        Returns:
        --------
        str
            A message confirming the item was equipped.
        """
        if item.slot in self.equipped_items:
            # Remove effects of currently equipped item if it exists
            current_item = self.equipped_items[item.slot]
     
            return f"Equipped {item.name} in {item.slot} slot!"
        return "Cannot equip this item."
    
    # we can define a method called view_equipped_items that displays all currently equipped items
    # we can use the for loop to iterate through the equipped_items attribute
    # we can use the status variable to store the status of the item
    # we can use the equipped_list variable to store the equipped items
    # we can use the return statement to return a formatted string showing all equipped items
    ...
        """
        Displays all currently equipped items.

        Returns:
        --------
        str
            A formatted string showing all equipped items.
        """
        # we can use the for loop to iterate through the equipped_items attribute
        # we can use the status variable to store the status of the item
        # we can use the equipped_list variable to store the equipped items
        # we can use the return statement to return a formatted string showing all equipped items
        equipped_list = []
        for slot, item in self.equipped_items.items():
            status = f"โš”๏ธ {item.name}" if item else "Empty"
            equipped_list.append(f"{slot.capitalize()}: {status}")
        
        return "\n".join(["Equipped Items:"] + equipped_list)
grader.check("Character-class")

Question 10 (Points: 55.0): Playing the Game Example#

### **Let's Play! ๐ŸŽฎโš”๏ธโœจ**

# We have provided a simple text-based game loop below.
# You can use this to test your code.
# This is just the start of your RPG game, with classes you can extend and modify this code to create your own RPG game!

# Create some sample items
items = [
    Item("Health Potion", "restore", "health", 50),
    Item("Mana Potion", "restore", "mana", 30),
    Armor("Leather Vest","agility", 5, slot="chest"),
    Weapon("Iron Sword", 20, stat="strength"),
    Weapon("Magic Staff", 15, stat="intellect")
]

def play_game():
    """Interactive game loop to test the RPG system."""
    print("Welcome to World of Warcraft RPG! ๐ŸŒŸ\n")
    
    # Character creation
    name = input("Enter your character's name: ")
    print("\nChoose your class:")
    print("1. Warrior โš”๏ธ")
    print("2. Mage ๐Ÿ”ฎ")
    print("3. Monk ๐Ÿฅ‹")
    print("4. Paladin ๐Ÿ›ก๏ธ")
    
    class_choice = input("\nEnter your choice (1-4): ")
    class_map = {
        "1": Warrior(name),
        "2": Mage(name),
        "3": Monk(name),
        "4": Paladin(name)
    }
    
    # Create character
    player = Character(
        name=name,
        class_type=class_map.get(class_choice, Warrior(name)), 
        inventory=items
    )
    
    print(f"\n{player.name} the {player.class_type.name} enters Azeroth! โš”๏ธ")
    
    while True:
        print("\nWhat would you like to do?")
        print("1. View Stats ๐Ÿ“Š")
        print("2. View Inventory ๐ŸŽ’")
        print("3. Cast Spell โœจ")
        print("4. Use Item ๐Ÿ”ฎ")
        print("5. Gain Experience ๐Ÿ“ˆ")
        print("6. Exit Game ๐Ÿšช")
        
        choice = input("\nEnter your choice (1-6): ")
        
        if choice == "1":
            print(f"\n{player.name}'s Stats:")
            print(f"Level: {player.level}")
            print(f"Health: {player.base_health}")
            print(f"Mana: {player.base_mana}")
            print(f"Strength: {player.strength}")
            print(f"Agility: {player.agility}")
            print(f"Intellect: {player.intellect}")
            
        elif choice == "2":
            print("\nInventory:")
            if not player.inventory:
                print("Empty inventory!")
            else:
                for item in player.inventory:
                    print(f"- {item.name}")
                    
        elif choice == "3":
            print("\nAvailable Spells:")
            for spell in player.spells:
                print(f"- {spell.name} (Level {spell.level_required})")
            spell_name = input("\nEnter spell name to cast (or press Enter to cancel): ")
            if spell_name:
                print(player.cast_spell(spell_name))
                
        elif choice == "4":
            if not items:
                print("\nNo items available!")
            else:
                print("\nAvailable Items:")
                for i, item in enumerate(items, 1):
                    print(f"{i}. {item.name}")
                try:
                    item_choice = int(input("\nEnter item number to use (or 0 to cancel): ")) - 1
                    if 0 <= item_choice < len(items):
                        print(items[item_choice].apply(player))
                except ValueError:
                    print("Invalid choice!")
                    
        elif choice == "5":
            xp = 100
            print(f"\nGaining {xp} experience points!")
            player.gain_experience(xp)
            
        elif choice == "6":
            print(f"\nFarewell, {player.name}! Your legend will live on in Azeroth! ๐Ÿ‘‹")
            break
            
        else:
            print("\nInvalid choice! Please try again.")
play_game()

Submitting Assignment#

Please run the following block of code using shift + enter to submit your assignment, you should see your score.

from pykubegrader.submit.submit_assignment import submit_assignment

submit_assignment("week7-lab", "1_world_of_warcraft")