153 lines
5.5 KiB
Python
153 lines
5.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
import heapq
|
||
from collections import defaultdict
|
||
|
||
def boss_fight(B, PlayerSkills):
|
||
"""
|
||
使用改进的A*算法求解Boss战斗的最优策略
|
||
|
||
参数:
|
||
B: Boss血量序列 [boss1_hp, boss2_hp, ...]
|
||
PlayerSkills: 玩家技能列表 [(damage1, cooldown1), (damage2, cooldown2), ...]
|
||
|
||
返回:
|
||
每个Boss对应的攻击序列列表,例如:[[0, 1, 0], [2, -1, 1], ...]
|
||
其中数字表示技能索引,-1表示等待
|
||
如果无解则返回None
|
||
"""
|
||
n = len(B) # Boss数量
|
||
m = len(PlayerSkills) # 技能数量
|
||
if n == 0:
|
||
return []
|
||
|
||
# 如果所有技能伤害为0,则无法击败Boss
|
||
if all(skill[0] == 0 for skill in PlayerSkills):
|
||
return None
|
||
|
||
def more_accurate_heuristic(boss_idx, boss_remaining_hp):
|
||
"""更精确的启发式函数"""
|
||
if boss_idx >= n:
|
||
return 0
|
||
|
||
# 计算剩余总血量
|
||
remaining_hp = boss_remaining_hp + sum(B[boss_idx + 1:])
|
||
|
||
# 考虑技能的平均有效伤害(考虑冷却时间)
|
||
total_damage_per_turn = 0
|
||
for damage, cooldown in PlayerSkills:
|
||
if damage > 0:
|
||
# 有效伤害 = 伤害 / (冷却时间 + 1)
|
||
effective_damage = damage / (cooldown + 1)
|
||
total_damage_per_turn += effective_damage
|
||
|
||
if total_damage_per_turn > 0:
|
||
return max(1, int((remaining_hp + total_damage_per_turn - 1) / total_damage_per_turn))
|
||
return remaining_hp
|
||
|
||
# 使用更紧密的优先队列来保证最优性
|
||
# 状态: (boss_idx, boss_hp, cooldown_tuple)
|
||
start_state = (0, B[0], tuple([0] * m))
|
||
|
||
# 优先队列: (f_score, g_score, state, path)
|
||
queue = [(more_accurate_heuristic(0, B[0]), 0, start_state, [])]
|
||
|
||
# 记录到达每个状态的最短路径长度
|
||
g_score = {start_state: 0}
|
||
|
||
while queue:
|
||
f, g, (boss_idx, boss_hp, cooldown), path = heapq.heappop(queue)
|
||
|
||
# 如果所有Boss都被击败
|
||
if boss_idx >= n:
|
||
# 重构路径为每个Boss的序列
|
||
result_paths = [[] for _ in range(n)]
|
||
current_boss = 0
|
||
current_hp = B[0]
|
||
|
||
for action in path:
|
||
result_paths[current_boss].append(action)
|
||
if action != -1:
|
||
damage = PlayerSkills[action][0]
|
||
current_hp -= damage
|
||
if current_hp <= 0:
|
||
current_boss += 1
|
||
if current_boss < n:
|
||
current_hp = B[current_boss]
|
||
|
||
return result_paths
|
||
|
||
current_state = (boss_idx, boss_hp, cooldown)
|
||
|
||
# 如果已经找到到达此状态的更短路径,跳过
|
||
if current_state in g_score and g_score[current_state] < g:
|
||
continue
|
||
|
||
# 生成所有可能的后继状态
|
||
neighbors = []
|
||
|
||
# 选项1: 等待
|
||
new_cooldown = tuple(max(0, cd - 1) for cd in cooldown)
|
||
neighbors.append((-1, boss_idx, boss_hp, new_cooldown))
|
||
|
||
# 选项2: 使用每个可用技能
|
||
for skill_idx in range(m):
|
||
if cooldown[skill_idx] == 0: # 技能可用
|
||
damage, skill_cooldown = PlayerSkills[skill_idx]
|
||
new_hp = boss_hp - damage
|
||
new_boss_idx = boss_idx
|
||
|
||
# 更新冷却时间
|
||
new_cooldown = list(max(0, cd - 1) for cd in cooldown)
|
||
new_cooldown[skill_idx] = skill_cooldown
|
||
new_cooldown = tuple(new_cooldown)
|
||
|
||
# 检查Boss是否被击败
|
||
if new_hp <= 0:
|
||
new_boss_idx += 1
|
||
if new_boss_idx < n:
|
||
new_hp = B[new_boss_idx]
|
||
|
||
neighbors.append((skill_idx, new_boss_idx, new_hp, new_cooldown))
|
||
|
||
# 处理每个邻居状态
|
||
for action, new_boss_idx, new_boss_hp, new_cooldown in neighbors:
|
||
new_state = (new_boss_idx, new_boss_hp, new_cooldown)
|
||
tentative_g = g + 1
|
||
|
||
# 如果找到更好的路径到达邻居状态
|
||
if new_state not in g_score or tentative_g < g_score[new_state]:
|
||
g_score[new_state] = tentative_g
|
||
h = more_accurate_heuristic(new_boss_idx, new_boss_hp)
|
||
f_score = tentative_g + h
|
||
new_path = path + [action]
|
||
|
||
heapq.heappush(queue, (f_score, tentative_g, new_state, new_path))
|
||
|
||
return None # 无解
|
||
|
||
|
||
if __name__ == '__main__':
|
||
# 测试用例
|
||
B = [19, 17, 14, 19]
|
||
PlayerSkills = [(6, 2), (9, 5), (5, 3), (4, 3), (2, 0)]
|
||
|
||
print("Boss血量序列:", B)
|
||
print("玩家技能 (伤害, 冷却):", PlayerSkills)
|
||
print()
|
||
|
||
result = boss_fight(B, PlayerSkills)
|
||
|
||
if result:
|
||
print("每个Boss的攻击序列:")
|
||
for i, boss_sequence in enumerate(result):
|
||
print(f"Boss {i+1}: {boss_sequence}")
|
||
|
||
# 合并所有序列
|
||
full_sequence = []
|
||
for boss_sequence in result:
|
||
full_sequence.extend(boss_sequence)
|
||
print(f"完整序列: {''.join(map(str, full_sequence))}")
|
||
print(f"总步数: {len(full_sequence)}")
|
||
else:
|
||
print("无解 - 无法击败所有Boss")
|
||
|