Menu
Coddy logo textTech

ゲームキャラクター開発

CoddyのPythonジャーニー「Object Oriented Programming」セクションの一部 — レッスン 63/64。

challenge icon

チャレンジ

中級

このチャレンジでは、包括的なテストカバレッジを備えたマルチファイル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 ===')

Object Oriented Programmingのすべてのレッスン