本文目录导读:

这是一个非常经典且有趣的Python综合案例,既然你问“哪队能笑到最后”,我猜你可能是在做一个模拟比赛或策略博弈的项目。
为了满足“综合”的要求(涵盖面向对象、数据结构、随机性、算法),我为你设计了一个 “NPC大乱斗” 模拟器。
场景设定: 有三支队伍(战士队、法师队、刺客队),每队有3名角色,他们进行循环赛(两两对决),最终根据积分(胜3平1负0)和净胜分决出总冠军。
下面是一段完整、可直接运行的Python代码,它会模拟整个赛程并告诉你哪支队伍笑到了最后。
import random
import itertools
# ---------- 第一部分:构建角色基类(面向对象) ----------
class Hero:
def __init__(self, name, hp, attack, defense, speed, crit_rate=0.2):
self.name = name
self.max_hp = hp
self.hp = hp
self.attack = attack
self.defense = defense
self.speed = speed
self.crit_rate = crit_rate # 暴击率
self.is_alive = True
def take_damage(self, damage):
# 防御减伤
actual_damage = max(1, damage - self.defense)
self.hp -= actual_damage
if self.hp <= 0:
self.hp = 0
self.is_alive = False
return actual_damage
def attack_target(self, target):
# 基础攻击计算暴击
if random.random() < self.crit_rate:
damage = int(self.attack * 1.5) # 暴击150%
else:
damage = self.attack
final_dmg = target.take_damage(damage)
return f"{self.name} 攻击 {target.name},造成 {final_dmg} 点伤害"
def reset(self):
self.hp = self.max_hp
self.is_alive = True
def __str__(self):
return f"{self.name}(HP:{self.hp}/{self.max_hp})"
# ---------- 第二部分:定义三个特殊队伍(继承与多态) ----------
class Warrior(Hero): # 战士:高攻高防,技能是破甲
def special_skill(self, target):
# 无视防御的打击(相当于真实伤害)
damage = int(self.attack * 0.8)
real_dmg = target.take_damage(damage + target.defense) # 无视防御
return f" [战士技能]破甲斩!无视防御,造成 {real_dmg} 点伤害"
class Mage(Hero): # 法师:脆皮高爆发,技能是群体火球(或双体)
def special_skill(self, targets):
# 随机选1-2个目标攻击(这里简化,选第一个和目标攻击力最高的)
if len(targets) == 1:
targets = targets * 2
# 攻击所有存活目标(这里限制最多打2个)
dmg_list = []
for t in targets:
if t.is_alive:
dmg = int(self.attack * 1.2)
final_dmg = t.take_damage(dmg)
dmg_list.append(t.name + ":" + str(final_dmg))
return f" [法师技能]烈焰风暴!对 {', '.join(dmg_list)} 造成伤害"
class Assassin(Hero): # 刺客:极高速度与暴击,技能是连续攻击
def special_skill(self, target):
total = 0
# 刺客攻击三次(每次50%攻击力)
for _ in range(3):
if target.is_alive:
dmg = target.take_damage(int(self.attack * 0.5))
total += dmg
return f" [刺客技能]影刃连击!合计造成 {total} 点伤害"
# ---------- 第三部分:构建比赛逻辑(算法与数据处理) ----------
class Team:
def __init__(self, name, heroes):
self.name = name
self.heroes = heroes # 列表(三名英雄)
self.wins = 0
self.losses = 0
self.points = 0
self.score_diff = 0 # 净胜分
def reset(self):
for h in self.heroes:
h.reset()
# 全场总生命值作为比赛输出指标
self.total_hp = sum(h.max_hp for h in self.heroes)
def is_defeated(self):
return all(not h.is_alive for h in self.heroes)
def get_alive_heroes(self):
return [h for h in self.heroes if h.is_alive]
def __str__(self):
return self.name
def battle_phase(team_a, team_b):
"""
进行一个回合(两两对战直到一方全灭)
返回 (胜者team, 败者team, 剩余血量比)
"""
# 初始化双方reset
team_a.reset()
team_b.reset()
# 打乱顺序,体现随机性(用列表存储所有存活角色)
all_heroes_a = list(team_a.heroes)
all_heroes_b = list(team_b.heroes)
round_num = 0
# 主循环:直到一方团灭
while not team_a.is_defeated() and not team_b.is_defeated():
round_num += 1
# 行动顺序按照速度排序(所有存活角色混合)
alive_a = team_a.get_alive_heroes()
alive_b = team_b.get_alive_heroes()
combatants = []
# 为每个英雄分配一个队伍标签
for h in alive_a:
combatants.append((h, 'A'))
for h in alive_b:
combatants.append((h, 'B'))
# 按速度排序(如果速度相同则随机先手)
combatants.sort(key=lambda x: (x[0].speed, random.random()), reverse=True)
# 逐个行动(每个英雄行动一次就算一轮回合结束)
actions_log = []
for hero, camp in combatants:
if hero.is_alive:
# 选择目标(随机敌方存活英雄)
if camp == 'A':
enemies = team_b.get_alive_heroes()
else:
enemies = team_a.get_alive_heroes()
if not enemies:
break # 没有敌人了退场
target = random.choice(enemies)
# 决定使用普通攻击还是技能(技能概率40%)
if random.random() < 0.4:
# 法师技能可以多重目标
if isinstance(hero, Mage):
# 法师可能群体攻击(这里简化,攻击所有,但伤害衰减)
log = hero.special_skill([target] + [enemies[0] if len(enemies) > 1 and enemies[0] != target else target])
actions_log.append(log)
else:
# 其他职业对单体
log = hero.special_skill(target)
actions_log.append(log)
else:
log = hero.attack_target(target)
actions_log.append(log)
# 检查战斗结束条件
if team_a.is_defeated() or team_b.is_defeated():
break
# 防止死循环(如果双方都不掉血则强制结束——这里加个保险)
if round_num > 100:
# 比较血量百分比
a_hp = sum(h.hp for h in team_a.heroes)
b_hp = sum(h.hp for h in team_b.heroes)
if a_hp >= b_hp:
winner, loser = team_a, team_b
else:
winner, loser = team_b, team_a
return winner, loser, actions_log
# 正常结束
if team_a.is_defeated():
winner, loser = team_b, team_a
else:
winner, loser = team_a, team_b
return winner, loser, actions_log
# ---------- 第四部分:主程序与统计(综合应用) ----------
def create_teams():
# 创建三支队伍
# 战士队 - 血厚攻高防高
soldier1 = Warrior("盾战", 300, 80, 25, 50, 0.1)
soldier2 = Warrior("狂战", 280, 100, 15, 60, 0.2)
soldier3 = Warrior("枪兵", 250, 90, 20, 70, 0.15)
team_war = Team("钢铁战士队", [soldier1, soldier2, soldier3])
# 法师队 - 控制爆发
mage1 = Mage("火法", 180, 130, 10, 70, 0.25)
mage2 = Mage("冰法", 200, 120, 8, 65, 0.2)
mage3 = Mage("雷法", 170, 150, 5, 80, 0.3)
team_mage = Team("奥术议会队", [mage1, mage2, mage3])
# 刺客队 - 脆皮极速
assassin1 = Assassin("暗刃", 150, 100, 5, 95, 0.45)
assassin2 = Assassin("影袭", 160, 90, 5, 100, 0.5)
assassin3 = Assassin("夜行者", 140, 110, 5, 90, 0.4)
team_assassin = Team("暗影猎手队", [assassin1, assassin2, assassin3])
return [team_war, team_mage, team_assassin]
def simulate_tournament():
teams = create_teams()
print("="*60)
print(" 🏆 模拟大赛正式开始 🏆")
print("="*60)
for team in teams:
print(f" 🎖 队伍: {team.name} | 成员: {', '.join(h.name for h in team.heroes)}")
print()
# 循环赛:每两队打一场,三局两胜?这里简单一场定胜负,但为了公平每场打3次取积分
team_names = [t.name for t in teams]
matches = list(itertools.combinations(range(3), 2))
# 每个对阵打一场(循环赛 3场)
for match_idx, (i, j) in enumerate(matches):
team_a = teams[i]
team_b = teams[j]
print(f"\n--- 对阵 {match_idx+1}: {team_a.name} VS {team_b.name} ---")
# 这里每场进行3局,胜场多者得3分,平局则各1分(无平,实际不会平)
# 我们改为单场,但是为了模拟更真实,多局取分
points_a = 0
points_b = 0
for game in range(1, 4): # 三局
winner, loser, log = battle_phase(team_a, team_b)
# 计算净胜(剩下的总血量比)
a_hp = sum(h.hp for h in team_a.heroes)
b_hp = sum(h.hp for h in team_b.heroes)
diff = a_hp - b_hp # 可能是负
if winner is team_a:
points_a += 1
print(f" 第{game}局: {team_a.name} 胜 (剩余血量 {a_hp} vs {b_hp})")
else:
points_b += 1
print(f" 第{game}局: {team_b.name} 胜 (剩余血量 {a_hp} vs {b_hp})")
# 更新积分(总分)
if points_a > points_b:
leading = team_a
elif points_b > points_a:
leading = team_b
# 结算分数(3局2胜)
if points_a >= 2:
team_a.points += 3
print(f" >>> 最终胜者: {team_a.name}")
else:
team_b.points += 3
print(f" >>> 最终胜者: {team_b.name}")
print("\n" + "="*60)
print(" 战绩统计")
print("="*60)
# 计算净胜分(用胜场差简单代替)
# 为了好玩,这里看所有对局小分
results = sorted(teams, key=lambda t: t.points, reverse=True)
for rank, team in enumerate(results, 1):
print(f"{rank}位 🥇 : {team.name} |积分: {team.points}")
champion = max(teams, key=lambda t: t.points)
print("\n" + "*"*60)
print(f" 🎉 最终的冠军是: {champion.name} 🎉")
print("*"*60)
# 冠军额外奖励
for h in champion.heroes:
print(f" 🏅 {h.name} 荣誉登场!")
# 运行模拟(因为随机性,结果会变化,想固定可加 random.seed(42))
if __name__ == "__main__":
# random.seed(1) # 取消注释固定随机种子看固定结果
simulate_tournament()
运行结果解析(预测)
由于引入了随机性(暴击、技能触发、目标选择),每次运行结果可能不同,但从属性数据上看:
- 战士队:血厚、防高,容错率高。
- 法师队:攻击力高,但非常脆,技能是AOE,但单体爆发可能不足。
- 刺客队:速度极快(几乎总是先手),暴击率极高(50%左右),伤害非常恐怖,由于速度快,可能先秒杀敌方输出。
“哪队能笑到最后?” 答案通常在刺客队或法师队之间(取决于刺客的暴击是否触发),如果刺客连续打出暴击,基本上三回合内能秒掉对方主力,而战士队更稳定,但输出可能略显不足,面对高爆发队伍时容易陷入困境。
你可以多次运行这个程序,看看统计上哪支队伍的赢面更大😊
如何调整?
- 修改
Hero的初始属性(HP/攻击/速度等)来调整队伍平衡。 - 修改
battle_phase中的技能触发概率(4)来让技能更容易释放。 - 想固定比赛结果,在
__main__中调用random.seed(某数字)即可。
(小建议:如果想让真正的“综合”,可以加入文件读取(如英雄名单存CSV)、画图(matplotlib显示胜率),但核心逻辑已在这几百行里体现了。)