From 2601cdc863da05b922dc60e267b48f49823fbca4 Mon Sep 17 00:00:00 2001 From: Guan Inf <2307786059@qq.com> Date: Thu, 26 Jun 2025 21:30:21 +0800 Subject: [PATCH] init --- SourceCollector.py | 144 +++++++++++++++++++++++++++++++++++++++++++++ boss_fight.py | 136 ++++++++++++++++++++++++++++++++++++++++++ maze.csv | 30 +++++----- readme.md | 100 +++++++++++++++++++++++++++++++ 4 files changed, 395 insertions(+), 15 deletions(-) create mode 100644 SourceCollector.py create mode 100644 boss_fight.py create mode 100644 readme.md diff --git a/SourceCollector.py b/SourceCollector.py new file mode 100644 index 0000000..0c3b69a --- /dev/null +++ b/SourceCollector.py @@ -0,0 +1,144 @@ +import csv + +class TreeNode: + def __init__(self): + self.fa = None + self.children = [] + self.pos = None + self.val = 0 + self.id = 0 + self.dp = 0 + self.path = [] + self.dp_path = [] + +class SourceCollector: + def __init__(self, filename, maze=None): + self.filename = filename + self.maze = maze + self.start_pos = None + self.end_pos = None + self.path = [] + + if self.filename: + self.maze = [] + with open(f"{self.filename}",'r') as f: + reader = csv.reader(f) + for row in reader: + t = [] + for i in row: + if i.startswith('b') or i.startswith('l'): + t.append('0') + else: + t.append(i) + self.maze.append(t) + self.rowNums = len(self.maze) + self.colNums = len(self.maze[0]) + + + for i in range(self.rowNums): + for j in range(self.colNums): + if self.maze[i][j] =='s': + self.start_pos = (i,j) + if self.maze[i][j] =='e': + self.end_pos = (i,j) + + def dfs_show(self,u): + if u.id != 0: + print(f"id: {u.id} , fa:{u.fa.id} , val:{u.val}") + else: + print(f"id: {u.id} , val:{u.val}") + print(u.path) + for child in u.children: + + self.dfs_show(child) + + def outofmap(self,x,y): + return x < 0 or y < 0 or x > self.rowNums or y > self.colNums + def build_a_tree(self): + sn = TreeNode() + sn.pos = self.start_pos + id = 0 + sn.id = id + sn.val = 0 + sn.path = [sn.pos] + + st = [[False] * self.colNums for _ in range(self.rowNums)] + qsk = [] + sx, sy = self.start_pos + st[sx][sy] = True + qsk.append((self.start_pos[0],self.start_pos[1], sn,[])) + dx = [-1,0,1,0] + dy = [0,-1,0,1] + + while qsk: + x, y, u,path = qsk.pop() + for _x, _y in zip(dx,dy): + nx, ny = x + _x, y + _y + if self.outofmap(nx,ny): + continue + if self.maze[nx][ny] == '1' or st[nx][ny]: + continue + + st[nx][ny] = True + to = self.maze[nx][ny] + new_path = path + [(nx,ny)] + if to.startswith('g') or to.startswith('t'): + new_node = TreeNode() + id+=1 + new_node.id = id + new_node.pos = (nx, ny) + new_node.fa = u + num_str = to[1:] + new_node.path = new_path + + try: + if to.startswith('g'): + new_node.val = int(num_str) + else: + new_node.val = -int(num_str) + except ValueError: + print("wa ! ") + u.children.append(new_node) + + qsk.append((nx, ny, new_node,[])) + else: + qsk.append((nx, ny, u,new_path)) + + return sn + def dfs(self,sn): + sn.dp = sn.val + for child in sn.children: + # print(f"cur : {child.pos} , fa : {child.fa.pos} , childrens : {child.path}") + self.dfs(child) + if child.dp > 0: + sn.dp += child.dp + sn.dp_path += child.path + child.dp_path + child.path[::-1] + + + def find_path(self): + self.path = [] + sn = self.build_a_tree() + self.dfs(sn) + return self.path + +if __name__ == '__main__': + obj = SourceCollector(filename="maze.csv") + sn = obj.build_a_tree() + # obj.dfs_show(sn) + obj.dfs(sn) + print(len(sn.dp_path)) + print(sn.pos) + pre = sn.pos + for _ in sn.dp_path: + dx,dy = _[0] - pre[0],_[1]-pre[1] + if dx > 0: + print("down") + elif dx < 0: + print("up") + elif dy > 0: + print("right") + elif dy < 0: + print("left") + pre = _ + + diff --git a/boss_fight.py b/boss_fight.py new file mode 100644 index 0000000..b1cdc4f --- /dev/null +++ b/boss_fight.py @@ -0,0 +1,136 @@ +# -*-coding: GBK -*- +import heapq # 导入堆模块,用于实现优先队列 +from typing import List, Optional, Tuple # 导入类型提示相关模块 + + +def boss_strategy(coin: int, blood: int) -> Optional[Tuple[List[str], int]]: + # 使用分支限界法寻找最小回合数击败BOSS的技能序列 + + # 参数: + # coin: 玩家初始金币数 + # 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 + + # 尝试使用技能A + if cur_coin >= 2: # 检查金币是否足够 + new_coin = cur_coin - 2 # 扣除金币 + new_blood = cur_blood - 1 # 减少BOSS血量 + new_energy = energy + 1 # 增加充能 + new_ce = 0 # 使用非E技能,重置连续E计数 + new_round = round_cnt + 1 # 回合数+1 + new_seq = seq_tuple + ('A',) # 添加技能到序列 + + # 压缩连续E计数状态(>=3视为3) + 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)) + + # 尝试使用技能E + cost_e = 3 # 默认消耗金币 + if ce >= 2: # 检查是否为连续第三次使用E + cost_e = 2 # 第三次消耗2金币 + + if cur_coin >= cost_e: # 检查金币是否足够 + new_coin = cur_coin - cost_e # 扣除金币 + new_blood = cur_blood - 3 # 减少BOSS血量 + new_energy = energy + 1 # 增加充能 + new_ce = ce + 1 # 增加连续E计数 + new_round = round_cnt + 1 # 回合数+1 + new_seq = seq_tuple + ('E',) # 添加技能到序列 + + # 压缩连续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)) + + # 尝试使用技能Q + if energy >= 3 and cur_coin >= 3: # 检查充能和金币是否足够 + new_coin = cur_coin - 3 # 扣除金币 + new_blood = cur_blood - 8 # 减少BOSS血量 + new_energy = energy - 3 # 消耗充能 + new_ce = 0 # 使用非E技能,重置连续E计数 + new_round = round_cnt + 1 # 回合数+1 + 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__": + # 测试示例: 金币=10, BOSS血量=10 + result = boss_strategy(20, 20) + + if result is None: + print("无法击败BOSS") + else: + skill_sequence, remaining_coins = result + print("最小回合数技能序列:", skill_sequence) # 预期输出: ['A', 'A', 'A', 'Q'] + print("剩余金币:", remaining_coins) # 预期输出: 1 diff --git a/maze.csv b/maze.csv index 9d5d660..59c8e46 100644 --- a/maze.csv +++ b/maze.csv @@ -1,16 +1,16 @@ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 -1,0,l30,e,0,1,0,1,0,t17,1,0,g13,1,g23,1 -1,1,1,1,0,1,0,0,0,0,1,0,0,1,0,1 -1,0,0,t14,0,0,0,1,0,0,1,1,0,1,t20,1 -1,0,t17,0,0,1,0,1,0,0,1,0,0,1,0,1 -1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1 -1,0,0,0,l19,0,0,1,0,0,1,0,0,1,0,1 -1,1,0,1,1,1,1,1,0,0,0,0,0,1,0,1 -1,0,l30,0,0,t18,0,g14,0,0,1,0,0,0,0,1 -1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1 -1,0,0,g26,0,0,0,0,0,b66,1,0,1,0,0,1 -1,1,0,1,0,1,1,1,0,t20,1,l22,1,0,g27,1 -1,0,0,1,g16,0,0,1,0,0,0,t17,s,0,0,1 -1,1,1,1,1,1,1,1,g12,1,1,0,1,0,1,1 -1,0,0,0,0,0,0,t7,0,0,1,0,1,0,0,1 -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +1,0,0,1,0,e,t7,1,0,0,0,0,0,g19,0,1 +1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1 +1,0,l25,0,t5,0,0,1,0,0,0,0,t9,0,g27,1 +1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1 +1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,1 +1,0,1,0,1,0,0,1,1,1,1,0,0,0,0,1 +1,0,0,0,1,0,0,1,0,0,0,0,1,0,0,1 +1,1,1,0,0,0,0,1,1,1,1,0,1,0,1,1 +1,l25,g10,0,1,0,0,0,0,1,0,0,1,0,b73,1 +1,1,1,1,1,t9,1,1,g20,1,0,0,1,0,g12,1 +1,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1 +1,0,0,0,1,0,0,1,0,1,0,0,1,0,0,1 +1,1,1,0,0,0,0,1,t7,1,0,1,1,0,0,1 +1,g12,0,0,1,0,s,1,0,0,t13,0,1,l17,0,1 +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..79cfb31 --- /dev/null +++ b/readme.md @@ -0,0 +1,100 @@ +# 绠楁硶椹卞姩鐨勮糠瀹帰闄╂父鎴忓紑鍙 + +## 璁捐鐩爣 + +***\*鍦板浘锛歕**** + +涓涓簩缁寸煩闃碉紝閲団饯鍒嗘不娉曗剑鎴愶紝饨嗗饨村尯鍩燂紝瀛樺湪鍞紑閫氳矾銆 + +杈撯紛锛氳糠瀹昂饧 銆 + +杈撳嚭锛氳糠瀹煩闃碉紙鍙瓨鍌ㄤ负JSON鎴朇SV锛夛紝鍖呮嫭璧风偣Start锛圫锛夈 缁堢偣Exit锛圗锛夈佸澹侊紙#锛夈侀氳矾锛堢┖鏍硷級銆佽祫婧愶紙渚嬪饩﹀竵G锛夈 闄烽槺Trap锛圱锛夈佹満鍏矻ocker锛圠锛夈丅OSS锛圔锛夈 + + + +澧欏锛氫笉鍙氳繃锛屾棤value鐨勮妭鐐 + +閫氳矾锛氬彲閫氳繃锛屾棤value鐨勮妭鐐 + +閲戝竵锛氬彲閫氳繃锛屾湁value 鐨勮妭鐐广侭OSS鎴樻椂鐨勮鍔ㄩ渶瑕佹秷鑰楅噾甯 + +闄烽槺锛氬彲閫氳繃锛屼絾缁忚繃鏃朵細鎵i櫎鐜╁鐨勯噾甯 + +鏈哄叧锛氫笁浣嶅瘑鐮侀攣銆備竴鑸垎甯冨湪鏌愭潯璺殑灏藉ご锛屽繀椤诲紑鍚墍鏈夋満鍏冲悗锛岀粓鐐瑰ぇ闂ㄦ墠浼氭墦寮 + +BOSS锛氬湪蹇呯粡涔嬭矾涓婏紝鏈塿alue(琛閲) , 蹇呴』鎵撹触鎵嶈兘缁х画鍓嶈繘 + + + + + +***\*鐜╁锛歕**** + +鏈変笁绉嶆敾鍑绘柟寮忥紙鍒濆鍏呰兘涓0锛夛細 + +A锛氭秷鑰2鏋氶噾甯侀犳垚1鐐逛激瀹冲苟鑾峰緱1鐐瑰厖鑳 + +E锛氭秷鑰3鏋氶噾甯侀犳垚3鐐逛激瀹冲苟鑾峰緱1鐐瑰厖鑳斤紝杩炵画绗笁娆′娇鐢‥鎶鑳芥椂灏戞秷鑰1鏋氶噾甯 + +Q锛氭秷鑰3鏋氶噾甯佸拰3鐐瑰厖鑳斤紝閫犳垚8鐐逛激瀹 + + + +## 浠诲姟鍒嗚В + +### 1. 鍒嗘不娉曠敓鎴愯糠瀹 + +**闇姹 : ** + +杈撳叆 : 姝f暣鏁 n( 100>=n>=7 ) , 鐢熸垚绫诲瀷閫夋嫨(json鎴栬卌sv) + +杈撳嚭 : json鏂囦欢 , csv鏂囦欢 , 琛ㄧず鍦板浘 , 鏃犲绔嬪尯 , 瀛樺湪鍞竴閫氳矾 + +S : 璧风偣 + +E : 缁堢偣 + +\# :澧欏 + +blank : 閫氳矾 + +G : 璧勬簮 + +T : 闄烽槺 + +L : 鏈哄叧 + +B : Boss + +**閫掑綊鍒嗗壊娉曠敓鎴愯糠瀹** + + + + + + + +### 2. 鍔ㄦ佽鍒掕繘琛岃祫婧愭敹闆嗚矾寰勮鍒 + + + + + +### 3. 璐績绠楁硶璁捐瀹炴椂璧勬簮鎷惧彇绛栫暐 + + + + + +### 4. 鍥炴函娉曡В杩峰叧鍗 + + + + + +### 5. 鍒嗘敮闄愮晫璁捐boss鎴 + + + + +