修改了boss_fight的编码 , 添加输出boss技能列表

This commit is contained in:
Guanforever 2025-06-30 15:06:37 +08:00
parent e3e7e0b373
commit 04f54e0f3d

View File

@ -1,136 +1,110 @@
# -*-coding: GBK -*- #-*-coding: GBK -*-
import heapq # 导入堆模块,用于实现优先队列 import math
from typing import List, Optional, Tuple # 导入类型提示相关模块 import heapq
def boss_fight(B, PlayerSkills):
n = len(B)
m = len(PlayerSkills)
if n == 0:
return []
# 计算最大平均伤害用于启发式函数
max_avg = 0.0
for a, b in PlayerSkills:
if b + 1 > 0:
avg = a / (b + 1)
if avg > max_avg:
max_avg = avg
# 如果所有技能伤害为0则无法击败BOSS
if max_avg == 0:
return None
# 初始状态boss索引0血量B[0]冷却全0回合数0路径空
start_cooldown = tuple([0] * m)
total_remaining = sum(B)
#f_value = 当前回合数 + 估计剩余回合数
f_value = math.ceil(total_remaining / max_avg) if max_avg > 0 else total_remaining
def boss_strategy(coin: int, blood: int) -> Optional[Tuple[List[str], int]]: # 初始化优先队列 (f_value, round_count, boss_idx, boss_rem, cooldown, path)
# 使用分支限界法寻找最小回合数击败BOSS的技能序列 queue = [(f_value, 0, 0, B[0], start_cooldown, [])]
# 记录访问过的状态(boss_idx, boss_rem, cooldown) -> 最小回合数
visited = {}
visited[(0, B[0], start_cooldown)] = 0
all_path = []
# 优先队列按f_value排序
while queue:
# 优先扩展f_value最小的状态最有希望的状态
f_value, round_count, boss_idx, boss_rem, cooldown, path = heapq.heappop(queue)
state_key = (boss_idx, boss_rem, cooldown)
# 参数: # 状态检查:如果已有更好状态,跳过当前状态
# coin: 玩家初始金币数 if visited.get(state_key, float('inf')) < round_count:
# blood: BOSS初始血量
# 返回:
# 最小回合数的技能序列列表如果无解则返回None
start_coin = coin # 记录初始金币数,用于计算消耗金币
# 初始状态: (回合数, 剩余金币, BOSS血量, 充能, 连续E计数, 技能序列元组)
start_state = (0, coin, blood, 0, 0, ())
# 创建优先队列: 元素为 (优先级, 状态)
# 优先级元组: (回合数, 消耗金币, BOSS血量) - 值越小优先级越高
heap = []
heapq.heappush(heap, ((0, 0, blood), start_state)) # 将初始状态加入优先队列
# 创建访问集合: 用于避免重复状态
# 状态键: (回合数, 剩余金币, BOSS血量, 充能, min(连续E计数,3))
visited = set()
start_ce_compressed = min(0, 3) # 压缩连续E计数状态
visited.add((0, coin, blood, 0, start_ce_compressed)) # 将初始状态加入已访问集合
# 设置最大回合数限制,避免无限循环
max_round = blood * 2 # 每次至少造成1点伤害最多回合数为血量两倍
# 主循环: 处理优先队列中的状态
while heap:
# 从优先队列中取出优先级最高的状态
priority, state = heapq.heappop(heap)
# 解包状态元组
round_cnt, cur_coin, cur_blood, energy, ce, seq_tuple = state
# 检查是否已击败BOSS
if cur_blood <= 0:
return (list(seq_tuple), cur_coin) # 返回技能序列和剩余金币
# 超过最大回合数则跳过当前状态
if round_cnt >= max_round:
continue continue
# 尝试使用技能A # 所有BOSS已击败
if cur_coin >= 2: # 检查金币是否足够 if boss_idx >= n:
new_coin = cur_coin - 2 # 扣除金币 return path
new_blood = cur_blood - 1 # 减少BOSS血量
new_energy = energy + 1 # 增加充能 # 等待操作所有冷却时间减1回合数+1路径添加-1
new_ce = 0 # 使用非E技能重置连续E计数 new_cooldown_list = [max(0, c - 1) for c in cooldown]
new_round = round_cnt + 1 # 回合数+1 new_cooldown = tuple(new_cooldown_list)
new_seq = seq_tuple + ('A',) # 添加技能到序列 new_round = round_count + 1
new_state_key = (boss_idx, boss_rem, new_cooldown)
# 压缩连续E计数状态>=3视为3 # 若新状态更优,则加入队列
ce_compressed = min(new_ce, 3) if new_state_key not in visited or visited[new_state_key] > new_round:
# 创建状态键用于去重 visited[new_state_key] = new_round
state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) total_remaining = boss_rem + sum(B[boss_idx+1:])
estimate_rounds = math.ceil(total_remaining / max_avg) if max_avg > 0 else 0
# 检查是否为新状态 new_f = new_round + estimate_rounds
if state_key not in visited: new_path = path + [-1]
visited.add(state_key) # 标记为已访问 heapq.heappush(queue, (new_f, new_round, boss_idx, boss_rem, new_cooldown, new_path))
cost = start_coin - new_coin # 计算已消耗金币
# 创建新状态 # 使用技能
new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) for skill_idx, (a, b) in enumerate(PlayerSkills):
# 将新状态加入优先队列 if cooldown[skill_idx] != 0: # 技能不可用
heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) continue
# 尝试使用技能E new_boss_idx = boss_idx
cost_e = 3 # 默认消耗金币 new_boss_rem = boss_rem - a
if ce >= 2: # 检查是否为连续第三次使用E
cost_e = 2 # 第三次消耗2金币 # 击败当前BOSS
if new_boss_rem <= 0:
if cur_coin >= cost_e: # 检查金币是否足够 new_boss_idx += 1
new_coin = cur_coin - cost_e # 扣除金币 all_path.append(new_path)
new_blood = cur_blood - 3 # 减少BOSS血量 new_path = []
new_energy = energy + 1 # 增加充能 if new_boss_idx < n:
new_ce = ce + 1 # 增加连续E计数 new_boss_rem = B[new_boss_idx] # 切换至下一个BOSS
new_round = round_cnt + 1 # 回合数+1 else:
new_seq = seq_tuple + ('E',) # 添加技能到序列 new_boss_rem = 0 # 所有BOSS已击败
# 压缩连续E计数状态 # 更新冷却时间
ce_compressed = min(new_ce, 3) new_cooldown_list = [max(0, c - 1) for c in cooldown]
# 创建状态键用于去重 new_cooldown_list[skill_idx] = b # 重置当前技能冷却时间
state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) new_cooldown = tuple(new_cooldown_list)
new_round = round_count + 1
# 检查是否为新状态 new_path = path + [skill_idx]
if state_key not in visited:
visited.add(state_key) # 标记为已访问 # 所有BOSS已击败返回路径
cost = start_coin - new_coin # 计算已消耗金币 if new_boss_idx >= n:
# 创建新状态 return all_path
new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq)
# 将新状态加入优先队列 new_state_key = (new_boss_idx, new_boss_rem, new_cooldown)
heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) # 若新状态更优,则加入队列
if new_state_key not in visited or visited[new_state_key] > new_round:
# 尝试使用技能Q visited[new_state_key] = new_round
if energy >= 3 and cur_coin >= 3: # 检查充能和金币是否足够 total_remaining = new_boss_rem + sum(B[new_boss_idx+1:])
new_coin = cur_coin - 3 # 扣除金币 estimate_rounds = math.ceil(total_remaining / max_avg) if max_avg > 0 else 0
new_blood = cur_blood - 8 # 减少BOSS血量 new_f = new_round + estimate_rounds
new_energy = energy - 3 # 消耗充能 heapq.heappush(queue, (new_f, new_round, new_boss_idx, new_boss_rem, new_cooldown, new_path))
new_ce = 0 # 使用非E技能重置连续E计数
new_round = round_cnt + 1 # 回合数+1 return None # 无解
new_seq = seq_tuple + ('Q',) # 添加技能到序列
# 压缩连续E计数状态
ce_compressed = min(new_ce, 3)
# 创建状态键用于去重
state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed)
# 检查是否为新状态
if state_key not in visited:
visited.add(state_key) # 标记为已访问
cost = start_coin - new_coin # 计算已消耗金币
# 创建新状态
new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq)
# 将新状态加入优先队列
heapq.heappush(heap, ((new_round, cost, new_blood), new_state))
return None # 队列为空,无解
# 主程序入口 if __name__ == '__main__':
if __name__ == "__main__": B = [10, 20, 30, 40, 50]
# 测试示例: 金币=10, BOSS血量=10 PlayerSkills = [(5, 2), (8, 3), (3, 1)]
result = boss_strategy(20, 20) ans = boss_fight(B, PlayerSkills)
for i in ans:
if result is None: print(i)
print("无法击败BOSS")
else:
skill_sequence, remaining_coins = result
print("最小回合数技能序列:", skill_sequence) # 预期输出: ['A', 'A', 'A', 'Q']
print("剩余金币:", remaining_coins) # 预期输出: 1