人狗大战Ⅲ

import random


# 1. 元类:追踪所有角色类的创建
class MetaCharacter(type):
    """元类:记录所有角色类并自动添加种族标识"""
    character_types = []  # 存储所有角色类

    def __new__(cls, name: str, bases: tuple, namespace: dict):
        new_cls = super().__new__(cls, name, bases, namespace)
        if name != "BaseCharacter":  # 排除基类
            cls.character_types.append(new_cls)
            print(f"元类创建角色类: {name}")
        return new_cls


# 2. 基类:所有角色的抽象基类,由元类MetaCharacter创建
class BaseCharacter(metaclass=MetaCharacter):
    """角色基类,定义核心属性与行为"""
    __slots__ = ("_name", "_hp", "_attack", "_defense")  # 限制动态属性
    race: str = "Unknown"  # 类属性:种族标识
    default_hp: int = 100  # 类属性:默认生命值 hp的全称为health points 
    default_attack: int = 10  # 类属性:默认攻击力
    default_defense: int = 5  # 类属性:默认防御力  

    def __init__(self, name: str):
        # 私有属性:名称、生命值、攻击力、防御力
        self._name = name.strip()  # 移除首尾空格,标准化名称 
        self._hp = self.default_hp  # 初始化生命值为默认值
        self._attack = self.default_attack  # 初始化攻击力为默认值
        self._defense = self.default_defense  # 初始化防御力为默认值

    # 封装:属性访问控制
    @property
    def name(self) -> str:
        return self._name

    @property
    def hp(self) -> int:
        return self._hp

    @hp.setter # 生命值 setter 方法,确保非负
    def hp(self, value: int):
        self._hp = max(0, value)  # 确保生命值不为负

    @property
    def attack(self) -> int:
        return self._attack

    @attack.setter  # 攻击力 setter 方法,确保非负
    def attack(self, value: int):
        if value < 0:
            raise ValueError("攻击力不能为负")
        self._attack = value

    # 类方法:批量设置种族默认属性
    @classmethod
    def set_race_defaults(cls, hp: int, attack: int, defense: int): # 生命值、攻击力、防御力的默认值
        cls.default_hp = hp
        cls.default_attack = attack
        cls.default_defense = defense
        print(f"[{cls.race}] 种族默认属性更新: HP={hp}, 攻击={attack}, 防御={defense}")

    # 静态方法:伤害计算工具
    @staticmethod
    def calculate_damage(attacker: 'BaseCharacter', defender: 'BaseCharacter') -> int:
        base_damage = max(1, attacker.attack - defender._defense // 2)
        # 生命值低于30%时伤害加成
        if defender.hp < defender.default_hp * 0.3:
            base_damage = int(base_damage * 1.5)
        return base_damage

    # 核心方法:攻击目标(多态基础)
    def attack_target(self, target: 'BaseCharacter'):
        if self.hp <= 0:
            print(f"{self.name}已倒下,无法攻击!")
            return
        if target.hp <= 0: 
            print(f"{target.name}已被击败,无需攻击!")
            return
        # 只要目标生命值大于0,就可以攻击
        damage = self.calculate_damage(self, target)
        target.hp -= damage
        print(f"{self.name}攻击了{target.name},造成{damage}点伤害!")
        if target.hp <= 0:
            print(f"{target.name}被击败了!")

    # 特殊方法:字符串表示
    def __str__(self) -> str:
        return f"{self.race} {self.name} | HP: {self.hp}/{self.default_hp} | 攻击: {self.attack} | 防御: {self._defense}"

    # 特殊方法:角色组合(组队)
    def __add__(self, other: 'BaseCharacter') -> 'Team':
        if not isinstance(other, BaseCharacter):
            raise TypeError("只能与角色组队")
        return Team([self, other])

    # 特殊方法:调用实例使用技能
    def __call__(self, skill: 'BaseSkill'): # 鸭子类型:只要有cast方法即可
        if self.hp <= 0:
            print(f"{self.name}无法使用技能(已倒下)")
            return
        skill.cast(self)  # 调用技能的cast方法,返回伤害值



# 3. 类装饰器:添加临时增益效果
def temporary_buff(bonus_hp: int = 0, bonus_attack: int = 0):
    """类装饰器:为角色添加临时属性加成(兼容 __slots__,不新增实例字段)"""
    def decorator(cls):
        original_init = cls.__init__

        def new_init(self, *args, **kwargs):
            # 先调用原始初始化,确保已有的 __slots__ 字段就绪
            original_init(self, *args, **kwargs)
            # 直接将加成体现在现有的基础属性上,避免新增字段触发 __slots__ 限制
            self.hp += bonus_hp
            self.attack = self.attack + bonus_attack
            print(f"{self.name}获得临时增益: HP+{bonus_hp}, 攻击+{bonus_attack}")

        # 不重写 attack property,避免访问不存在的 _bonus_attack 字段
        cls.__init__ = new_init
        return cls
    return decorator


# 4. 武器类(组合关系:角色持有武器)
class Weapon:
    """武器类,与角色形成组合关系"""
    __slots__ = ("_name", "_damage", "_durability")  # 限制属性

    def __init__(self, name: str, damage: int, durability: int = 100):
        self._name = name
        self._damage = damage
        self._durability = durability

    @property
    def name(self) -> str:
        return self._name

    @property
    def damage(self) -> int:
        return self._damage if self._durability > 0 else 0

    @property
    def durability(self) -> int:
        return self._durability

    def use(self) -> int:
        """使用武器,消耗耐久度"""
        if self._durability <= 0:
            print(f"{self.name}已损坏,无法使用!")
            return 0
        self._durability = max(0, self._durability - 10)
        return self._damage

    def __str__(self) -> str:
        return f"[{self.name} 伤害:{self.damage} 耐久:{self.durability}%]"


# 5. 人类类(继承+多态+组合)
@temporary_buff(bonus_hp=20, bonus_attack=3)  # 应用类装饰器
class Human(BaseCharacter):
    """人类角色类"""
    race = "Human"
    __slots__ = ("_intelligence", "_weapon")  # 扩展基类slots

    def __init__(self, name: str, intelligence: int = 5, weapon: Weapon = None):
        super().__init__(name)  # 调用父类构造
        self._intelligence = intelligence
        # 组合关系:人类必须持有武器(默认拳头)
        self._weapon = weapon or Weapon("拳头", 2)

    @property
    def intelligence(self) -> int:
        return self._intelligence

    @intelligence.setter
    def intelligence(self, value: int):
        self._intelligence = max(0, value)

    @property
    def weapon(self) -> Weapon:
        return self._weapon

    # 多态:重写攻击方法(使用武器)
    def attack_target(self, target: BaseCharacter):
        weapon_damage = self._weapon.use()
        original_attack = self.attack
        self.attack += weapon_damage  # 临时叠加武器伤害
        super().attack_target(target)  # 调用父类攻击逻辑
        self.attack = original_attack  # 恢复原始攻击
        print(f"[{self.weapon}]造成额外{weapon_damage}点伤害")

    def __str__(self) -> str:
        base_str = super().__str__()
        return f"{base_str} | 智力: {self._intelligence} | 武器: {self._weapon}"


# 6. 狗类(继承+多态)
class Dog(BaseCharacter):
    """狗角色类"""
    race = "Dog"
    __slots__ = ("_agility", "_breed")  # 扩展属性

    def __init__(self, name: str, breed: str = "普通犬", agility: int = 8):
        super().__init__(name)
        self._agility = agility
        self._breed = breed

    @property
    def agility(self) -> int:
        return self._agility

    @agility.setter
    def agility(self, value: int):
        self._agility = max(0, value)

    # 多态:重写攻击方法(敏捷影响暴击)
    def attack_target(self, target: BaseCharacter):
        # 敏捷越高,暴击概率越高
        crit_prob = self._agility / 20
        is_crit = random.random() < crit_prob

        original_attack = self.attack
        if is_crit:
            self.attack *= 2
            print(f"{self.name}触发暴击!攻击翻倍!")

        super().attack_target(target)
        self.attack = original_attack  # 恢复

    def __str__(self) -> str:
        base_str = super().__str__()
        return f"{base_str} | 品种: {self._breed} | 敏捷: {self._agility}"


# 7. 技能系统(鸭子类型)
class BaseSkill:
    """技能基类,定义鸭子类型接口"""
    def __init__(self, name: str, cost: int = 10):
        self.name = name
        self.cost = cost  # 技能消耗(生命值)

    def cast(self, caster: BaseCharacter) -> int: # 施法逻辑(必须实现)    
        """施法逻辑(必须实现)"""
        raise NotImplementedError("技能必须实现cast方法")


class FireballSkill(BaseSkill): 
    """火球术(人类专属)"""
    def __init__(self):
        super().__init__("火球术", cost=15)

    def cast(self, caster: BaseCharacter) -> int: # 施法逻辑(必须实现)
        """施法逻辑(必须实现)"""
        if not isinstance(caster, Human):
            print(f"{caster.name}无法使用火球术(非人类)")
            return
        if caster.hp < self.cost:
            print(f"{caster.name}生命值不足,无法释放{self.name}")
            return

        # 消耗生命值,伤害与智力相关
        caster.hp -= self.cost
        damage = 20 + caster.intelligence * 3
        print(f"{caster.name}释放{self.name},消耗{self.cost}HP,造成{damage}点火焰伤害!")
        return damage


class BiteSkill(BaseSkill):
    """撕咬(狗专属)"""
    def __init__(self):
        super().__init__("疯狂撕咬", cost=5)

    def cast(self, caster: BaseCharacter) -> int: # 施法逻辑(必须实现)
        """施法逻辑(必须实现)"""  
        if not isinstance(caster, Dog):
            print(f"{caster.name}无法使用撕咬(非犬类)")
            return
        if caster.hp < self.cost:
            print(f"{caster.name}生命值不足,无法释放{self.name}")
            return

        # 消耗生命值,伤害与敏捷相关
        caster.hp -= self.cost
        damage = 15 + caster.agility * 2
        print(f"{caster.name}使用{self.name},消耗{self.cost}HP,造成{damage}点撕裂伤害!")
        return damage


# 8. 队伍类(聚合关系)
class Team:
    """队伍类,聚合多个角色(角色可属于多个队伍)"""
    def __init__(self, members): # members 队伍成员列表
        self.members = members

    def __str__(self) -> str:
        return f"队伍成员: {[m.name for m in self.members]}"

    def is_defeated(self) -> bool:
        """判断队伍是否全灭"""
        return all(m.hp <= 0 for m in self.members)

    def attack(self, enemy_team: 'Team'):
        """队伍攻击另一队伍(支持技能释放)"""
        if self.is_defeated():
            print("己方队伍已全灭,无法攻击!")
            return
        if enemy_team.is_defeated():
            print("敌方队伍已全灭,无需攻击!")
            return

        print("\n----- 队伍交锋 -----")
        for attacker in self.members:
            if attacker.hp <= 0:
                continue
            # 随机选择敌方目标
            targets = [e for e in enemy_team.members if e.hp > 0]
            if not targets:
                continue
            target = random.choice(targets)

            used_skill = False
            # 概率释放各自专属技能
            if isinstance(attacker, Human) and random.random() < 0.4:
                damage = FireballSkill().cast(attacker)
                if isinstance(damage, int) and damage > 0:
                    target.hp -= damage
                    print(f"{attacker.name}用技能对{target.name}造成{damage}点伤害!")
                    if target.hp <= 0:
                        print(f"{target.name}被击败了!")
                    used_skill = True
            elif isinstance(attacker, Dog) and random.random() < 0.5:
                damage = BiteSkill().cast(attacker)
                if isinstance(damage, int) and damage > 0:
                    target.hp -= damage
                    print(f"{attacker.name}用技能对{target.name}造成{damage}点伤害!")
                    if target.hp <= 0:
                        print(f"{target.name}被击败了!")
                    used_skill = True

            if not used_skill:
                attacker.attack_target(target)


# 9. 战斗系统(关联关系)
class Battle:
    """战斗场景,关联多个角色/队伍"""
    def __init__(self, team1: Team, team2: Team):
        self.team1 = team1
        self.team2 = team2
        self.round = 0

    def start(self, max_rounds: int = 5):
        """开始战斗,最多进行max_rounds回合"""
        print("\n===== 人狗大战 正式开始 =====")
        while self.round < max_rounds:
            self.round += 1
            print(f"\n===== 第{self.round}回合 =====")

            # 随机决定先手
            if random.random() < 0.5:
                self.team1.attack(self.team2)
                if self.team2.is_defeated():
                    break
                self.team2.attack(self.team1)
            else:
                self.team2.attack(self.team1)
                if self.team1.is_defeated():
                    break
                self.team1.attack(self.team2)

            # 检查是否有队伍全灭
            if self.team1.is_defeated() or self.team2.is_defeated():
                break

        # 战斗结果
        print("\n===== 战斗结束 =====")
        if self.team1.is_defeated():
            print("狗队获胜!")
        elif self.team2.is_defeated():
            print("人类队获胜!")
        else:
            print("平局!")

        # 打印最终状态
        print("\n【最终状态】")
        for m in self.team1.members + self.team2.members:
            print(m)


# 测试代码
if __name__ == "__main__":
    # 配置种族默认属性
    Human.set_race_defaults(hp=150, attack=12, defense=8)
    Dog.set_race_defaults(hp=120, attack=15, defense=5)

    # 创建武器
    sword = Weapon("精铁剑", 10, durability=90)
    axe = Weapon("巨斧", 15, durability=60)

    # 创建角色
    alice = Human("Alice", intelligence=9, weapon=sword)
    bob = Human("Bob", intelligence=6, weapon=axe)
    dog1 = Dog("大黄", breed="藏獒", agility=12)
    dog2 = Dog("小黑", breed="狼犬", agility=10)

    # 打印初始状态
    print("\n【初始状态】")
    print(alice)
    print(bob)
    print(dog1)
    print(dog2)

    # 测试组队(__add__方法)
    team_human = alice + bob
    team_dog = dog1 + dog2
    print(f"\n{team_human}")
    print(f"{team_dog}")

    # 测试技能使用(__call__方法)
    print("\n【技能测试】")
    alice(FireballSkill())  # alice使用火球术
    dog1(BiteSkill())       # dog1使用撕咬

    # 开始战斗
    battle = Battle(team_human, team_dog)
    battle.start(max_rounds=4)
    
posted @ 2025-10-22 17:41  wangya216  阅读(86)  评论(0)    收藏  举报