curriculum/challenges/english/blocks/lab-game-character-stats/68cabc534d2e741f33a3fe1d.md
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:
Create a class named GameCharacter that represents a game character and manages character stats.
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.Create a name property for read-only access to the character's name.
For the health property:
0, and caps the health at 100.For the mana property:
0, and caps the mana at 50.Create a getter for level to return the character's current level.
Define a method named level_up that:
100 and mana to 50 using their corresponding property setters.<name> leveled up to <level>! (where <name> and <level> should be replaced by the character's name and new level, respectively).Define a __str__ method that returns a formatted string including:
Kratos, right after the instantiation, should be represented as the following:Name: Kratos
Level: 1
Health: 100
Mana: 50
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
You should have a GameCharacter class.
({ test: () => assert(runPython(`_Node(_code).has_class("GameCharacter")`)) })
You should have an __init__ method in the GameCharacter class.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("__init__")`)
})
The __init__ method should have two parameters, with the first being self.
({
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.
({
test: () => runPython(`
character = GameCharacter("Kratos")
assert character._name == "Kratos"
`)
})
You should assign 100 to self._health inside the __init__ method.
({
test: () => runPython(`
character = GameCharacter("Kratos")
assert character._health == 100
`)
})
You should assign 50 to self._mana inside the __init__ method.
({
test: () => runPython(`
character = GameCharacter("Kratos")
assert character._mana == 50
`)
})
You should assign 1 to self._level inside the __init__ method.
({
test: () => runPython(`
character = GameCharacter("Kratos")
assert character._level == 1
`)
})
You should have a name method in the GameCharacter class.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("name")`)
})
The name method should have only one parameter, self.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("name").has_args("self")`)
})
You should return self._name in the name method.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("name").has_return("self._name")`)
})
The name method should have a @property decorator.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("name").has_decorators("property")`)
})
You should have a health method in the GameCharacter class.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("health")`)
})
The health method should have only one parameter, self.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("health").has_args("self")`)
})
You should return self._health in the health method.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("health").has_return("self._health")`)
})
The health method should have a @property decorator.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("health").has_decorators("property")`)
})
You should create a health setter method.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_functions("health")[1]`)
})
The health setter method should have a @health.setter decorator.
({
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.
({
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.
({
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.
({
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.
({
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.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("mana")`)
})
The mana method should have only one parameter, self.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("mana").has_args("self")`)
})
You should return self._mana in the mana method.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("mana").has_return("self._mana")`)
})
The mana method should have a @property decorator.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("mana").has_decorators("property")`)
})
You should create a mana setter method.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_functions("mana")[1]`)
})
The mana setter method should have a @mana.setter decorator.
({
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.
({
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.
({
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.
({
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.
({
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.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("level")`)
})
The level method should have only one parameter, self.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level").has_args("self")`)
})
You should return self._level in the level method.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").find_function("level").has_return("self._level")`)
})
The level method should have a @property decorator.
({
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.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("level_up")`)
})
The level_up method should have only one parameter, self.
({
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.
({
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.
({
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.
({
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).
({
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.
({
test: () => runPython(`assert _Node(_code).find_class("GameCharacter").has_function("__str__")`)
})
The __str__ method should have only one parameter, self.
({
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.
({
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
`)
})
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}"
)