Desarrollo de personajes de videojuegos
Parte de la sección Programación orientada a objetos del Journey de Python de Coddy. Lección 63 de 64.
Desafío
IntermedioEn este desafío, implementarás un sistema de personajes de RPG en varios archivos con una cobertura de pruebas exhaustiva.
character.py- Implementa la clase base Characterwarrior.py- Implementa la subclase Warriormage.py- Implementa la subclase Magerogue.py- Implementa la subclase Rogueability.py- Implementa la clase Ability
Cada archivo contiene comentarios detallados TODO que guían tu implementación. Sigue estos comentarios para asegurarte de que tu código cumpla todos los requisitos.
Pruébalo tú mismo
from character import Character
from warrior import Warrior
from mage import Mage
from rogue import Rogue
from ability import Ability
# Gestor completo de casos de prueba que abarca todos los escenarios y casos límite
test_case = input()
if test_case == "character_creation":
# Probar la creación de distintas clases de personajes
warrior = Warrior("Aragorn", 1)
mage = Mage("Gandalf", 1)
rogue = Rogue("Legolas", 1)
print(f"Warrior: {warrior.name}, HP: {warrior.health}, Mana: {warrior.mana}, Str: {warrior.strength}")
print(f"Mage: {mage.name}, HP: {mage.health}, Mana: {mage.mana}, Int: {mage.intelligence}")
print(f"Rogue: {rogue.name}, HP: {rogue.health}, Mana: {rogue.mana}, Agi: {rogue.agility}")
elif test_case == "character_levelup":
# Probar la subida de nivel de distintas clases
warrior = Warrior("Aragorn")
mage = Mage("Gandalf")
rogue = Rogue("Legolas")
print("Before level up:")
print(f"Warrior - Level: {warrior.level}, HP: {warrior.max_health}, Str: {warrior.strength}")
print(f"Mage - Level: {mage.level}, Mana: {mage.max_mana}, Int: {mage.intelligence}")
print(f"Rogue - Level: {rogue.level}, Agi: {rogue.agility}")
warrior.level_up()
mage.level_up()
rogue.level_up()
print("\nAfter level up:")
print(f"Warrior - Level: {warrior.level}, HP: {warrior.max_health}, Str: {warrior.strength}")
print(f"Mage - Level: {mage.level}, Mana: {mage.max_mana}, Int: {mage.intelligence}")
print(f"Rogue - Level: {rogue.level}, Agi: {rogue.agility}")
elif test_case == "combat_basic":
# Probar las mecánicas básicas de combate
warrior = Warrior("Aragorn", 5)
enemy = Character("Orc", 3)
print(f"Initial HP - {warrior.name}: {warrior.health}, {enemy.name}: {enemy.health}")
# El guerrero ataca al enemigo
warrior.attack(enemy)
print(f"After warrior attack - Enemy HP: {enemy.health}")
# El enemigo contraataca
enemy.attack(warrior)
print(f"After enemy attack - Warrior HP: {warrior.health}")
# Comprobar si sigue con vida
print(f"Is warrior alive? {warrior.is_alive()}")
print(f"Is enemy alive? {enemy.is_alive()}")
elif test_case == "class_specific_attacks":
# Probar las implementaciones de ataque específicas de cada clase
warrior = Warrior("Aragorn", 5)
mage = Mage("Gandalf", 5)
rogue = Rogue("Legolas", 5)
target = Character("Training Dummy", 10)
target.defense = 0 # Eliminar la defensa para comparar el daño sin interferencias
# Restablecer la salud del objetivo entre ataques
initial_health = target.health
warrior.attack(target)
warrior_damage = initial_health - target.health
target.health = initial_health
mage.attack(target)
mage_damage = initial_health - target.health
target.health = initial_health
rogue.attack(target)
rogue_damage = initial_health - target.health
print(f"Warrior damage: {warrior_damage:.1f}")
print(f"Mage damage: {mage_damage:.1f}")
print(f"Rogue damage: {rogue_damage:.1f}")
# Comprobar la regeneración de maná del mago
initial_mana = mage.mana
mage.attack(target)
print(f"Mage mana before attack: {initial_mana}, after attack: {mage.mana}")
elif test_case == "abilities":
# Probar el sistema de habilidades
fireball = Ability("Fireball", 30, 25)
slash = Ability("Slash", 15, 20)
mage = Mage("Gandalf", 3)
warrior = Warrior("Aragorn", 3)
mage.learn_ability(fireball)
warrior.learn_ability(slash)
target = Character("Orc", 5)
initial_health = target.health
# Probar el uso de una habilidad por parte del mago
print(f"Mage mana before: {mage.mana}")
mage.use_ability(0, target)
print(f"Mage mana after: {mage.mana}")
print(f"Target health: {target.health}")
target.health = initial_health
# Probar el uso de una habilidad por parte del guerrero
print(f"Warrior mana before: {warrior.mana}")
warrior.use_ability(0, target)
print(f"Warrior mana after: {warrior.mana}")
print(f"Target health: {target.health}")
# Probar qué ocurre cuando no hay suficiente maná
mage.mana = 0
mage.use_ability(0, target)
elif test_case == "damage_calculation":
# Probar el cálculo del daño teniendo en cuenta la defensa
warrior = Warrior("Aragorn", 5)
low_defense = Character("Goblin", 3)
low_defense.defense = 2
high_defense = Character("Armored Knight", 3)
high_defense.defense = 15
# Atacar a un objetivo con poca defensa
damage_to_low = warrior.attack(low_defense)
# Atacar a un objetivo con mucha defensa
damage_to_high = warrior.attack(high_defense)
print(f"Damage to low defense target: {damage_to_low:.1f}")
print(f"Damage to high defense target: {damage_to_high:.1f}")
# Probar la regla del daño mínimo
super_defense = Character("Impenetrable Shield", 1)
super_defense.defense = 100
damage_to_super = warrior.attack(super_defense)
print(f"Damage to extremely high defense: {damage_to_super:.1f}")
elif test_case == "full_battle_simulation":
# Probar una batalla completa entre personajes
warrior = Warrior("Aragorn", 5)
mage = Mage("Saruman", 5)
fireball = Ability("Fireball", 30, 40)
ice_spike = Ability("Ice Spike", 25, 35)
cleave = Ability("Cleave", 20, 30)
warrior.learn_ability(cleave)
mage.learn_ability(fireball)
mage.learn_ability(ice_spike)
print(f"Battle begins: {warrior.name} vs {mage.name}")
print(f"{warrior.name}: {warrior.health}/{warrior.max_health} HP, {warrior.mana}/{warrior.max_mana} Mana")
print(f"{mage.name}: {mage.health}/{mage.max_health} HP, {mage.mana}/{mage.max_mana} Mana")
round_num = 1
while warrior.is_alive() and mage.is_alive():
print(f"\n--- Round {round_num} ---")
# Turno del guerrero
if round_num % 3 == 0 and warrior.mana >= cleave.mana_cost:
warrior.use_ability(0, mage)
else:
warrior.attack(mage)
# Comprobar si el mago ha sido derrotado
if not mage.is_alive():
print(f"{mage.name} has been defeated!")
break
# Turno del mago
if mage.mana >= fireball.mana_cost:
mage.use_ability(0, warrior)
else:
mage.attack(warrior)
# Comprobar si el guerrero ha sido derrotado
if not warrior.is_alive():
print(f"{warrior.name} has been defeated!")
break
print(f"Status: {warrior.name} ({warrior.health:.1f} HP, {warrior.mana} Mana) | {mage.name} ({mage.health:.1f} HP, {mage.mana} Mana)")
round_num += 1
# Límite para evitar bucles infinitos
if round_num > 10:
print("Battle exceeded 10 rounds and was called a draw.")
break
print("\nBattle Results:")
print(f"{warrior.name}: {warrior.health:.1f}/{warrior.max_health} HP remaining")
print(f"{mage.name}: {mage.health:.1f}/{mage.max_health} HP remaining")
if warrior.is_alive() and not mage.is_alive():
print(f"{warrior.name} wins!")
elif mage.is_alive() and not warrior.is_alive():
print(f"{mage.name} wins!")
else:
print("The battle ended in a draw!")
elif test_case == "inheritance_validation_test":
# Validación exhaustiva de la herencia
objects = []
if 'Character' in locals():
objects.append(Character('test_param'))
if 'Warrior' in locals():
objects.append(Warrior('test_param'))
if 'Mage' in locals():
objects.append(Mage('test_param'))
if 'Rogue' in locals():
objects.append(Rogue('test_param'))
if 'Ability' in locals():
objects.append(Ability('test_param', 10, 20))
for obj in objects:
print(f'{type(obj).__name__}:')
print(f' MRO: {[cls.__name__ for cls in type(obj).__mro__]}')
print()
elif test_case == "method_overriding_test":
# Probar el comportamiento de la sobrescritura de métodos
print('Testing method overriding...')
# Crear instancias y probar los métodos sobrescritos
if 'Warrior' in locals():
obj = Warrior('test')
print(f'Warrior methods work correctly')
if 'Mage' in locals():
obj = Mage('test')
print(f'Mage methods work correctly')
if 'Rogue' in locals():
obj = Rogue('test')
print(f'Rogue methods work correctly')
elif test_case == "attribute_access_test":
# Probar el acceso a los atributos
print('Testing attribute access...')
if 'Character' in locals():
obj = Character('test')
print(f'Character attributes accessible')
if 'Warrior' in locals():
obj = Warrior('test')
print(f'Warrior attributes accessible')
if 'Mage' in locals():
obj = Mage('test')
print(f'Mage attributes accessible')
if 'Rogue' in locals():
obj = Rogue('test')
print(f'Rogue attributes accessible')
if 'Ability' in locals():
obj = Ability('test', 10, 20)
print(f'Ability attributes accessible')
elif test_case == "boundary_conditions_test":
# Probar las condiciones límite y los valores extremos
print('Testing boundary conditions...')
# Probar un personaje con 0 puntos de salud
char = Character("Test", 1)
char.health = 0
print(f"Character at 0 HP is alive: {char.is_alive()}")
# Probar un personaje con 1 punto de salud
char2 = Character("Test2", 1)
char2.health = 1
print(f"Character at 1 HP is alive: {char2.is_alive()}")
# Probar un índice de habilidad no válido (negativo)
warrior = Warrior("Test", 1)
result = warrior.use_ability(-1, char)
print(f"Invalid negative ability index returns: {result}")
# Probar un índice de habilidad no válido (demasiado alto)
result = warrior.use_ability(999, char)
print(f"Invalid high ability index returns: {result}")
# Probar el daño mínimo (1) contra una defensa extremadamente alta
attacker = Character("Attacker", 1)
defender = Character("Defender", 1)
defender.defense = 1000
initial_hp = defender.health
attacker.attack(defender)
damage = initial_hp - defender.health
print(f"Minimum damage dealt: {damage}")
print('Boundary conditions test completed')
elif test_case == "error_handling_test":
# Probar el manejo de errores y los casos de excepción
print('Testing error handling...')
# Probar el uso de una habilidad con maná insuficiente
mage = Mage("TestMage", 1)
ability = Ability("Expensive", 1000, 50)
mage.learn_ability(ability)
target = Character("Target", 1)
result = mage.use_ability(0, target)
print(f"Ability with insufficient mana returns: {result}")
# Probar el uso de una habilidad sin haber aprendido ninguna
warrior = Warrior("TestWarrior", 1)
result = warrior.use_ability(0, target)
print(f"Using non-existent ability returns: {result}")
# Comprobar que la salud no sea negativa
char = Character("Test", 1)
char.take_damage(1000)
print(f"Health after massive damage: {char.health}")
print('Error handling test completed')
elif test_case == "polymorphic_behavior_test":
# Probar el comportamiento polimórfico con distintos objetos
print('Testing polymorphic behavior...')
# Crear una lista de distintos tipos de personajes
characters = [
Character("Generic", 1),
Warrior("WarriorTest", 1),
Mage("MageTest", 1),
Rogue("RogueTest", 1)
]
# Comprobar que todos puedan tratarse como Character
for char in characters:
print(f"{char.name}: Type={type(char).__name__}, IsAlive={char.is_alive()}")
# Probar las llamadas a métodos polimórficos
target = Character("Target", 10)
target.health = 1000 # Salud alta para sobrevivir
for char in characters:
damage = char.attack(target)
print('Polymorphic behavior test completed')
elif test_case == "stress_test":
# Prueba de estrés con múltiples objetos
import time
start_time = time.time()
objects = []
for i in range(50):
try:
objects.append(Character(f'test_{i}'))
except:
pass # Gestionar los errores de creación sin interrumpir la ejecución
try:
objects.append(Warrior(f'test_{i}'))
except:
pass # Gestionar los errores de creación sin interrumpir la ejecución
try:
objects.append(Mage(f'test_{i}'))
except:
pass # Gestionar los errores de creación sin interrumpir la ejecución
try:
objects.append(Rogue(f'test_{i}'))
except:
pass # Gestionar los errores de creación sin interrumpir la ejecución
try:
objects.append(Ability(f'test_{i}', 10, 20))
except:
pass # Gestionar los errores de creación sin interrumpir la ejecución
end_time = time.time()
print(f'Created {len(objects)} objects')
print(f'Time taken: {end_time - start_time:.4f} seconds')
print('Stress test completed')
elif test_case == "comprehensive_validation":
# Prueba de validación exhaustiva
print('=== Comprehensive Validation Test ===')
# Prueba 1: Creación básica de objetos
print('1. Basic Object Creation:')
success_count = 0
classes = ['Character', 'Warrior', 'Mage', 'Rogue', 'Ability']
try:
obj = Character('test')
success_count += 1
print(f' Character: Created successfully')
except Exception as e:
print(f' Character: Creation failed - {e}')
try:
obj = Warrior('test')
success_count += 1
print(f' Warrior: Created successfully')
except Exception as e:
print(f' Warrior: Creation failed - {e}')
try:
obj = Mage('test')
success_count += 1
print(f' Mage: Created successfully')
except Exception as e:
print(f' Mage: Creation failed - {e}')
try:
obj = Rogue('test')
success_count += 1
print(f' Rogue: Created successfully')
except Exception as e:
print(f' Rogue: Creation failed - {e}')
try:
obj = Ability('test', 10, 20)
success_count += 1
print(f' Ability: Created successfully')
except Exception as e:
print(f' Ability: Creation failed - {e}')
print(f' Successfully created {success_count}/{len(classes)} classes')
print('=== Validation Complete ===')Todas las lecciones de Programación orientada a objetos
1Fundamentos de la POO
Introducción a la POOArchivos externosClases vs. objetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Repaso: calculadora sencilla4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosRepaso: jerarquía de empleados7Métodos especiales
Introducción a los métodos mágicosSobrecarga de operadoresMétodos mágicos de contenedoresRepaso: lista personalizada10Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy13Desafíos finales
Plataforma de aprendizaje en líneaSistema bancarioDesarrollo de personajes de videojuegosServicio de alquiler de vehículos2Decoradores
Introducción a los decoradoresDecorador de propiedadDecorador de método estáticoDecorador de método de clase5Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas8Conceptos avanzados de POO
Composición frente a herenciaMixinsMétodos estáticos y de claseDecoradores de claseGestores de contexto11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Propiedades de clase
Variables de instancia vs. variables de claseDecoradores de propiedadesAtributos privadosRepaso: gestor de cuentas bancariasPractica por tu cuenta: Compilador de Python online