Back to Freecodecamp

Build a Game Character Stats Tracker

curriculum/challenges/english/blocks/lab-game-character-stats/68cabc534d2e741f33a3fe1d.md

latest13.6 KB
Original Source

--description--

In this lab, you'll build a game character stats tracker. The program will allow you to create a character with specific attributes, update those attributes, and retrieve the current stats of the character.

Objective: Fulfill the user stories below and get all the tests to pass to complete the lab.

User Stories:

  1. Create a class named GameCharacter that represents a game character and manages character stats.

  2. When instantiated, a new GameCharacter object should have the following attributes:

    • _name set to the string given at the moment of the instantiation.
    • _health set to 100.
    • _mana set to 50.
    • _level set to 1.
  3. Create a name property for read-only access to the character's name.

  4. For the health property:

    • Define a getter that returns the current health.
    • Define a setter that prevents health from being set below 0, and caps the health at 100.
  5. For the mana property:

    • Define a getter that returns the current mana.
    • Define a setter that prevents mana from being set below 0, and caps the mana at 50.
  6. Create a getter for level to return the character's current level.

  7. Define a method named level_up that:

    • Increases the character's level by 1.
    • Resets health to 100 and mana to 50 using their corresponding property setters.
    • Prints a message in the form of <name> leveled up to <level>! (where <name> and <level> should be replaced by the character's name and new level, respectively).
  8. Define a __str__ method that returns a formatted string including:

    • The character's name.
    • The character's level.
    • The character's current health.
    • The character's current mana. For example, a character named Kratos, right after the instantiation, should be represented as the following:
    md
    Name: Kratos
    Level: 1
    Health: 100
    Mana: 50
    

Usage example

python
hero = GameCharacter('Kratos') # Creates a new character named Kratos
print(hero)  # Displays the character's stats

hero.health -= 30  # Decreases health by 30
hero.mana -= 10    # Decreases mana by 10
print(hero)  # Displays the updated stats

hero.level_up()  # Levels up the character
print(hero)  # Displays the stats after leveling up

--hints--

You should have a GameCharacter class.

js
({ test: () => assert(runPython(`_Node(_code).has_class("GameCharacter")`)) })

You should have an __init__ method in the GameCharacter class.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("__init__")`) 
})

The __init__ method should have two parameters, with the first being self.

js
({ 
    test: () => runPython(`
    import inspect
    params = list(inspect.signature(GameCharacter.__init__).parameters)
    assert params[0] == "self"
    assert len(params) == 2
    `) 
})

You should set self._name to the string given at the moment of instantiation inside the __init__ method.

js
({ 
    test: () => runPython(`
    character = GameCharacter("Kratos")
    assert character._name == "Kratos"
    `) 
})

You should assign 100 to self._health inside the __init__ method.

js
({ 
    test: () => runPython(`
    character = GameCharacter("Kratos")
    assert character._health == 100
    `) 
})

You should assign 50 to self._mana inside the __init__ method.

js
({ 
    test: () => runPython(`
    character = GameCharacter("Kratos")
    assert character._mana == 50
    `) 
})

You should assign 1 to self._level inside the __init__ method.

js
({ 
    test: () => runPython(`
    character = GameCharacter("Kratos")
    assert character._level == 1
    `) 
})

You should have a name method in the GameCharacter class.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("name")`) 
})

The name method should have only one parameter, self.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("name").has_args("self")`) 
})

You should return self._name in the name method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("name").has_return("self._name")`)
})

The name method should have a @property decorator.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("name").has_decorators("property")`) 
})

You should have a health method in the GameCharacter class.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("health")`) 
})

The health method should have only one parameter, self.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("health").has_args("self")`) 
})

You should return self._health in the health method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("health").has_return("self._health")`)
})

The health method should have a @property decorator.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("health").has_decorators("property")`) 
})

You should create a health setter method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_functions("health")[1]`) 
})

The health setter method should have a @health.setter decorator.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_functions("health")[1].has_decorators("health.setter")`) 
})

The health setter method should have two parameters, with the first being self.

js
({ 
    test: () => runPython(`
    import inspect
    params = list(inspect.signature(GameCharacter.health.fset).parameters)
    assert params[0] == "self"
    assert len(params) == 2`) 
})

You should set self._health to 0 if the value given to the health setter is less than 0.

js
({ 
    test: () => runPython(`
    char = GameCharacter("test")
    char.health = -1
    assert char.health == 0
    char.health = -10
    assert char.health == 0
`)})

You should set self._health to 100 if the value given to the health setter is greater than 100.

js
({ 
    test: () => runPython(`
    char = GameCharacter("test")
    char.health = 101
    assert char.health == 100
    char.health = 200
    assert char.health == 100
`)})

You should set self._health to the value given to the health setter when the value is between 0 and 100.

js
({ 
    test: () => runPython(`
    char = GameCharacter("test")
    char.health = 95
    assert char.health == 95
    char.health = 1
    assert char.health == 1
    char.health = 0
    assert char.health == 0
    char.health = 100
    assert char.health == 100
`)})

You should have a mana method in the GameCharacter class.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("mana")`) 
})

The mana method should have only one parameter, self.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("mana").has_args("self")`) 
})

You should return self._mana in the mana method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("mana").has_return("self._mana")`)
})

The mana method should have a @property decorator.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("mana").has_decorators("property")`) 
})

You should create a mana setter method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_functions("mana")[1]`) 
})

The mana setter method should have a @mana.setter decorator.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_functions("mana")[1].has_decorators("mana.setter")`) 
})

The mana setter method should have two parameters, with the first being self.

js
({ 
    test: () => runPython(`
    import inspect
    params = list(inspect.signature(GameCharacter.mana.fset).parameters)
    assert params[0] == "self"
    assert len(params) == 2`) 
})

You should set self._mana to 0 if the value given to the mana setter is less than 0.

js
({ 
    test: () => runPython(`
    char = GameCharacter("test")
    char.mana = -1
    assert char.mana == 0
    char.mana = -10
    assert char.mana == 0
`)})

You should set self._mana to 50 if the value given to the mana setter is greater than 50.

js
({ 
    test: () => runPython(`
    char = GameCharacter("test")
    char.mana = 51
    assert char.mana == 50
    char.mana = 100
    assert char.mana == 50
`)})

You should set self._mana to the value given to the mana setter if the value is between 0 and 50.

js
({ 
    test: () => runPython(`
    char = GameCharacter("test")
    char.mana = 25
    assert char.mana == 25
    char.mana = 0
    assert char.mana == 0
    char.mana = 50
    assert char.mana == 50
`)})

You should have a level method in the GameCharacter class.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("level")`) 
})

The level method should have only one parameter, self.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level").has_args("self")`) 
})

You should return self._level in the level method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level").has_return("self._level")`)
})

The level method should have a @property decorator.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level").has_decorators("property")`) 
})

You should have a level_up method in the GameCharacter class.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("level_up")`) 
})

The level_up method should have only one parameter, self.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level_up").has_args("self")`) 
})

You should increase self._level by 1 in the level_up method.

js
({ 
  test: () => runPython(`
    node = _Node(_code).find_class("GameCharacter").find_function("level_up")
    assert (
        node.has_stmt("self._level += 1") or
        node.has_stmt("self._level = self._level + 1")
    )
`)
})

You should set self.health to 100 in the level_up method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level_up").has_stmt("self.health = 100")`) 
})

You should set self.mana to 50 in the level_up method.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level_up").has_stmt("self.mana = 50")`) 
})

The level_up method should print <name> leveled up to <level>! (where <name> and <level> should be replaced by the character's name and new level, respectively).

js
({
  test: () => runPython(`
    import io
    import sys
            
    captured_output = io.StringIO()
    sys.stdout = captured_output
            
    gc = GameCharacter("test")
    gc.level_up()
            
    sys.stdout = sys.__stdout__
    output = captured_output.getvalue()
            
    assert "test leveled up to 2!" in output
`)
})

You should have a __str__ method in the GameCharacter class.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("__str__")`) 
})

The __str__ method should have only one parameter, self.

js
({ 
    test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("__str__").has_args("self")`) 
})

Your __str__ method should return a string with the character's stats using the provided format.

js
({ 
  test: () => runPython(`
    import io
    import sys
            
    captured_output = io.StringIO()
    sys.stdout = captured_output
            
    gc = GameCharacter("test")
    gc.mana = 15
    gc.health = 77
    print(gc)
            
    sys.stdout = sys.__stdout__
    output = captured_output.getvalue()
    expected = """Name: test
    Level: 1
    Health: 77
    Mana: 15"""
    assert expected in output
`)
})

--seed--

--seed-contents--

py

--solutions--

py
class GameCharacter:
    def __init__(self, name):
        self._name = name
        self._health = 100
        self._mana = 50
        self._level = 1

    @property
    def name(self):
        return self._name

    @property
    def health(self):
        return self._health

    @health.setter
    def health(self, value):
        if value < 0:
            self._health = 0
        elif value > 100:
            self._health = 100
        else:
            self._health = value

    @property
    def mana(self):
        return self._mana

    @mana.setter
    def mana(self, value):
        if value < 0:
            self._mana = 0
        elif value > 50:
            self._mana = 50
        else:
            self._mana = value

    @property
    def level(self):
        return self._level

    def level_up(self):
        self._level += 1
        self.health = 100
        self.mana = 50
        print(f"{self._name} leveled up to {self._level}!")

    def __str__(self):
        return (
            f"Name: {self._name}\n"
            f"Level: {self._level}\n"
            f"Health: {self._health}\n"
            f"Mana: {self._mana}"
        )