ゲームキャラクター開発
CoddyのPythonジャーニー「Object Oriented Programming」セクションの一部 — レッスン 63/64。
チャレンジ
中級このチャレンジでは、包括的なテストカバレッジを備えたマルチファイルRPGキャラクターシステムを実装します。
character.py- 基本となる Character クラスを実装しますwarrior.py- Warrior サブクラスを実装しますmage.py- Mage サブクラスを実装しますrogue.py- Rogue サブクラスを実装しますability.py- Ability クラスを実装します
各ファイルには、実装のガイドとなる詳細な TODO コメントが含まれています。これらのコメントに従って、コードがすべての要件を満たすようにしてください。
自分で試してみよう
from character import Character
from warrior import Warrior
from mage import Mage
from rogue import Rogue
from ability import Ability
# すべてのシナリオとエッジケースを網羅する包括的なテストケースハンドラー
test_case = input()
if test_case == "character_creation":
# 異なるキャラクタークラスの作成をテスト
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":
# 異なるクラスのレベルアップをテスト
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":
# 基本的な戦闘メカニズムをテスト
warrior = Warrior("Aragorn", 5)
enemy = Character("Orc", 3)
print(f"Initial HP - {warrior.name}: {warrior.health}, {enemy.name}: {enemy.health}")
# 戦士が敵を攻撃
warrior.attack(enemy)
print(f"After warrior attack - Enemy HP: {enemy.health}")
# 敵が反撃
enemy.attack(warrior)
print(f"After enemy attack - Warrior HP: {warrior.health}")
# 生存確認
print(f"Is warrior alive? {warrior.is_alive()}")
print(f"Is enemy alive? {enemy.is_alive()}")
elif test_case == "class_specific_attacks":
# クラス固有の攻撃実装をテスト
warrior = Warrior("Aragorn", 5)
mage = Mage("Gandalf", 5)
rogue = Rogue("Legolas", 5)
target = Character("Training Dummy", 10)
target.defense = 0 # 純粋なダメージ比較のために防御力を排除
# 攻撃の合間にターゲットの体力をリセット
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}")
# 魔導師のマナ回復をチェック
initial_mana = mage.mana
mage.attack(target)
print(f"Mage mana before attack: {initial_mana}, after attack: {mage.mana}")
elif test_case == "abilities":
# アビリティシステムをテスト
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
# 魔導師のアビリティ使用をテスト
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
# 戦士のアビリティ使用をテスト
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}")
# マナ不足のテスト
mage.mana = 0
mage.use_ability(0, target)
elif test_case == "damage_calculation":
# 防御力を考慮したダメージ計算をテスト
warrior = Warrior("Aragorn", 5)
low_defense = Character("Goblin", 3)
low_defense.defense = 2
high_defense = Character("Armored Knight", 3)
high_defense.defense = 15
# 低防御力を攻撃
damage_to_low = warrior.attack(low_defense)
# 高防御力を攻撃
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}")
# 最小ダメージルールのテスト
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":
# キャラクター間のフルバトルシミュレーションをテスト
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} ---")
# 戦士のターン
if round_num % 3 == 0 and warrior.mana >= cleave.mana_cost:
warrior.use_ability(0, mage)
else:
warrior.attack(mage)
# 魔導師が倒されたかチェック
if not mage.is_alive():
print(f"{mage.name} has been defeated!")
break
# 魔導師のターン
if mage.mana >= fireball.mana_cost:
mage.use_ability(0, warrior)
else:
mage.attack(warrior)
# 戦士が倒されたかチェック
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
# 無限ループ防止のための制限
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":
# 包括的な継承の検証
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":
# メソッドオーバーライドの挙動をテスト
print('Testing method overriding...')
# インスタンスを作成し、オーバーライドされたメソッドをテスト
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":
# 属性アクセスのテスト
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":
# 境界条件とエッジ値のテスト
print('Testing boundary conditions...')
# 体力0のキャラクターをテスト
char = Character("Test", 1)
char.health = 0
print(f"Character at 0 HP is alive: {char.is_alive()}")
# 体力1のキャラクターをテスト
char2 = Character("Test2", 1)
char2.health = 1
print(f"Character at 1 HP is alive: {char2.is_alive()}")
# 無効なアビリティインデックス(負の値)をテスト
warrior = Warrior("Test", 1)
result = warrior.use_ability(-1, char)
print(f"Invalid negative ability index returns: {result}")
# 無効なアビリティインデックス(大きすぎる値)をテスト
result = warrior.use_ability(999, char)
print(f"Invalid high ability index returns: {result}")
# 超高防御力に対する最小ダメージ(1)をテスト
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":
# エラーハンドリングと例外シナリオのテスト
print('Testing error handling...')
# マナ不足でのアビリティ使用をテスト
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}")
# アビリティを習得していない状態でのアビリティ使用をテスト
warrior = Warrior("TestWarrior", 1)
result = warrior.use_ability(0, target)
print(f"Using non-existent ability returns: {result}")
# 体力が負の値にならないことをテスト
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":
# 混合オブジェクトによるポリモーフィックな挙動をテスト
print('Testing polymorphic behavior...')
# 異なるキャラクタータイプのリストを作成
characters = [
Character("Generic", 1),
Warrior("WarriorTest", 1),
Mage("MageTest", 1),
Rogue("RogueTest", 1)
]
# すべてがCharacterとして扱えることをテスト
for char in characters:
print(f"{char.name}: Type={type(char).__name__}, IsAlive={char.is_alive()}")
# ポリモーフィックなメソッド呼び出しをテスト
target = Character("Target", 10)
target.health = 1000 # 生き残るために高い体力を設定
for char in characters:
damage = char.attack(target)
print('Polymorphic behavior test completed')
elif test_case == "stress_test":
# 多数のオブジェクトによる負荷テスト
import time
start_time = time.time()
objects = []
for i in range(50):
try:
objects.append(Character(f'test_{i}'))
except:
pass # 作成エラーを適切に処理
try:
objects.append(Warrior(f'test_{i}'))
except:
pass # 作成エラーを適切に処理
try:
objects.append(Mage(f'test_{i}'))
except:
pass # 作成エラーを適切に処理
try:
objects.append(Rogue(f'test_{i}'))
except:
pass # 作成エラーを適切に処理
try:
objects.append(Ability(f'test_{i}', 10, 20))
except:
pass # 作成エラーを適切に処理
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":
# 包括的な検証テスト
print('=== Comprehensive Validation Test ===')
# テスト 1: 基本的なオブジェクト作成
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 ===')