diff --git a/greedy_3x3_algorithm.py b/greedy_3x3_algorithm.py deleted file mode 100644 index d423bbc..0000000 --- a/greedy_3x3_algorithm.py +++ /dev/null @@ -1,380 +0,0 @@ -""" -3x3视野贪心资源收集算法 - -该模块实现了一个基于3x3视野的贪心算法,用于在迷宫中收集资源。 -算法特点: -1. 每次移动时只考虑当前位置周围3x3范围内的资源 -2. 优先选择正价值资源(金币),如果没有则选择损失最小的负价值资源(陷阱) -3. 只能进行上下左右四个方向的移动 -4. 当视野内没有资源时,会进行探索性移动 -5. 避免无限循环,当连续多步无法找到新资源时会自动停止 - -使用方法: -```python -from greedy_3x3_algorithm import Greedy3x3Algorithm - -# 创建迷宫(二维数组,[y][x]格式) -maze = [ - ['s', '0', 'g5', '1', 't3'], - ['0', '1', '0', '0', 'g2'], - ['g3', '0', '1', 't2', '0'], - ['0', 't1', '0', '0', 'g4'], - ['1', '0', 'g1', '0', 'e'] -] - -# 创建算法实例并运行 -algorithm = Greedy3x3Algorithm(maze) -result = algorithm.run() - -# 获取结果 -print(f"总价值: {result['total_value']}") -print(f"路径: {result['path']}") -``` -""" - -import copy -from collections import deque - - -class Greedy3x3Algorithm: - """ - 3x3视野贪心资源收集算法 - - 该算法在每个位置只考虑周围3x3范围内的资源,选择价值最高的资源进行收集。 - 如果视野内没有资源,则进行探索性移动。 - """ - - def __init__(self, maze, start_pos=None, end_pos=None, debug=False): - """ - 初始化算法 - - Args: - maze: 二维列表,表示迷宫地图 ([y][x]格式) - start_pos: 起始位置 (x, y),默认自动寻找's' - end_pos: 目标位置 (x, y),默认自动寻找'e' - debug: 是否输出调试信息 - """ - self.original_maze = copy.deepcopy(maze) - self.maze = copy.deepcopy(maze) - self.rows = len(maze) - self.cols = len(maze[0]) if self.rows > 0 else 0 - self.debug = debug - - # 寻找起始位置和目标位置 - self.start_pos = start_pos or self._find_position('s') - self.end_pos = end_pos or self._find_position('e') - - if not self.start_pos: - raise ValueError("无法找到起始位置 's'") - if not self.end_pos: - raise ValueError("无法找到目标位置 'e'") - - # 初始化状态 - self.current_pos = self.start_pos - self.path = [self.start_pos] - self.collected_resources = [] - self.total_value = 0 - self.visited_resources = set() - self.explored_positions = set([self.start_pos]) - - if self.debug: - print(f"3x3视野贪心算法初始化") - print(f"迷宫大小: {self.rows}x{self.cols}") - print(f"起始位置: {self.start_pos}") - print(f"目标位置: {self.end_pos}") - - def _find_position(self, target): - """寻找地图中指定字符的位置,返回(x, y)格式""" - for y in range(self.rows): - for x in range(self.cols): - if self.maze[y][x].lower() == target.lower(): - return (x, y) - return None - - def get_3x3_vision(self, pos): - """ - 获取以pos为中心的3x3视野范围内的所有单元格 - - Args: - pos: 当前位置 (x, y) - - Returns: - dict: {(x, y): cell_value} 形式的字典 - """ - x, y = pos - vision = {} - - # 遍历3x3范围 - for dx in range(-1, 2): - for dy in range(-1, 2): - new_x, new_y = x + dx, y + dy - - # 检查边界 - if 0 <= new_x < self.cols and 0 <= new_y < self.rows: - vision[(new_x, new_y)] = self.maze[new_y][new_x] - - return vision - - def get_adjacent_positions(self, pos): - """ - 获取当前位置的上下左右四个相邻位置 - - Args: - pos: 当前位置 (x, y) - - Returns: - list: 可移动的相邻位置列表 - """ - x, y = pos - adjacent = [] - - # 上下左右四个方向 - directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] # 上、下、左、右 - - for dx, dy in directions: - new_x, new_y = x + dx, y + dy - - # 检查边界和可移动性 - if (0 <= new_x < self.cols and - 0 <= new_y < self.rows and - self._can_move_to((new_x, new_y))): - adjacent.append((new_x, new_y)) - - return adjacent - - def _can_move_to(self, pos): - """检查是否可以移动到指定位置""" - x, y = pos - cell = self.maze[y][x] - return cell != '1' # 不能移动到墙壁 - - def _evaluate_resource_value(self, cell): - """评估资源的价值""" - if cell.startswith('g'): - try: - return int(cell[1:]) - except ValueError: - return 0 - elif cell.startswith('t'): - try: - return -int(cell[1:]) - except ValueError: - return 0 - else: - return 0 - - def _find_best_resource_in_vision(self): - """ - 在3x3视野范围内找到价值最高的可到达资源 - - Returns: - tuple: (最佳资源位置, 资源价值) 或 (None, 0) - """ - vision = self.get_3x3_vision(self.current_pos) - adjacent_positions = self.get_adjacent_positions(self.current_pos) - - best_pos = None - best_value = float('-inf') - - # 只考虑相邻且在视野内的位置 - for pos in adjacent_positions: - if pos in vision and pos not in self.visited_resources: - cell = vision[pos] - value = self._evaluate_resource_value(cell) - - if value != 0 and value > best_value: - best_value = value - best_pos = pos - - return best_pos, best_value if best_pos else 0 - - def _find_exploration_target(self): - """当视野内没有资源时,寻找探索目标""" - adjacent = self.get_adjacent_positions(self.current_pos) - - # 优先选择未探索的位置 - unexplored = [pos for pos in adjacent if pos not in self.explored_positions] - if unexplored: - return unexplored[0] - - # 如果所有相邻位置都探索过,选择任意一个 - if adjacent: - return adjacent[0] - - return None - - def _collect_resource(self, pos): - """收集指定位置的资源""" - x, y = pos - cell = self.maze[y][x] - value = self._evaluate_resource_value(cell) - - if value != 0: - self.collected_resources.append({ - 'position': pos, - 'type': cell, - 'value': value - }) - self.total_value += value - self.visited_resources.add(pos) - - if self.debug: - print(f"收集资源: 位置{pos}, 类型{cell}, 价值{value}, 总价值{self.total_value}") - - def run(self, max_moves=1000, max_stuck=20): - """ - 运行3x3视野贪心资源收集算法 - - Args: - max_moves: 最大移动步数,防止无限循环 - max_stuck: 连续无资源的最大步数 - - Returns: - dict: 包含路径、收集的资源等信息的结果字典 - """ - if self.debug: - print("\\n开始3x3视野贪心资源收集...") - - moves = 0 - stuck_count = 0 - - while moves < max_moves and stuck_count < max_stuck: - moves += 1 - - # 在3x3视野内寻找最佳资源 - best_resource_pos, best_value = self._find_best_resource_in_vision() - - if best_resource_pos is not None: - if self.debug: - print(f"第{moves}步: 发现视野内资源 位置{best_resource_pos}, 价值{best_value}") - - # 移动到资源位置并收集 - self.current_pos = best_resource_pos - self.path.append(best_resource_pos) - self.explored_positions.add(best_resource_pos) - self._collect_resource(best_resource_pos) - - stuck_count = 0 # 重置无资源计数 - else: - # 视野内没有资源,进行探索性移动 - exploration_target = self._find_exploration_target() - - if exploration_target: - if self.debug: - print(f"第{moves}步: 视野内无资源,探索移动到 {exploration_target}") - self.current_pos = exploration_target - self.path.append(exploration_target) - self.explored_positions.add(exploration_target) - stuck_count += 1 - else: - if self.debug: - print(f"第{moves}步: 无法进行任何移动,结束收集") - break - - if self.debug: - if moves >= max_moves: - print(f"达到最大移动步数 {max_moves},结束收集") - elif stuck_count >= max_stuck: - print(f"连续 {max_stuck} 步未找到资源,结束收集") - print("3x3视野资源收集完成!") - - return self._get_result() - - def _get_result(self): - """获取算法执行结果""" - return { - 'path': self.path.copy(), - 'path_yx_format': [(y, x) for (x, y) in self.path], # 兼容现有代码的(y,x)格式 - 'collected_resources': self.collected_resources.copy(), - 'total_value': self.total_value, - 'total_moves': len(self.path) - 1, - 'resources_count': len(self.collected_resources), - 'start_pos': self.start_pos, - 'end_pos': self.end_pos, - 'final_pos': self.current_pos, - 'explored_positions_count': len(self.explored_positions), - 'algorithm_name': '3x3视野贪心算法' - } - - def get_marked_maze(self): - """ - 获取标记了路径的迷宫 - - Returns: - list: 标记后的迷宫,S=起点, E=终点, *=已收集资源, .=路径 - """ - marked_maze = copy.deepcopy(self.original_maze) - - # 标记路径点 - for i, (x, y) in enumerate(self.path): - if (x, y) == self.start_pos: - marked_maze[y][x] = 'S' # 起点 - elif (x, y) == self.end_pos: - marked_maze[y][x] = 'E' # 终点 - elif (x, y) in [r['position'] for r in self.collected_resources]: - marked_maze[y][x] = '*' # 已收集资源 - else: - marked_maze[y][x] = '.' # 路径点 - - return marked_maze - - def print_result(self): - """打印算法执行结果""" - result = self._get_result() - - print("\\n=== 3x3视野贪心算法执行结果 ===") - print(f"起始位置: {result['start_pos']}") - print(f"最终位置: {result['final_pos']}") - print(f"总移动步数: {result['total_moves']}") - print(f"探索位置数: {result['explored_positions_count']}") - print(f"收集资源数量: {result['resources_count']}") - print(f"资源总价值: {result['total_value']}") - - if result['collected_resources']: - print("\\n收集的资源详情:") - for i, resource in enumerate(result['collected_resources'], 1): - print(f" {i}. 位置{resource['position']}: {resource['type']} (价值: {resource['value']})") - else: - print("\\n未收集到任何资源") - - # 显示标记后的迷宫 - marked_maze = self.get_marked_maze() - print("\\n标记路径后的迷宫:") - print("S: 起点, E: 终点, *: 已收集资源, .: 路径") - for row in marked_maze: - print(' '.join(f"{cell:>2}" for cell in row)) - - -def demo(): - """演示函数""" - # 创建示例迷宫 - demo_maze = [ - ['s', '0', 'g5', '1', 't3'], - ['0', '1', '0', '0', 'g2'], - ['g3', '0', '1', 't2', '0'], - ['0', 't1', '0', '0', 'g4'], - ['1', '0', 'g1', '0', 'e'] - ] - - print("=== 3x3视野贪心算法演示 ===") - print("迷宫说明:") - print(" s: 起点, e: 终点") - print(" g数字: 金币资源 (正收益)") - print(" t数字: 陷阱资源 (负收益)") - print(" 0: 可通行路径, 1: 墙壁") - print("\\n原始迷宫:") - for row in demo_maze: - print(' '.join(f"{cell:>2}" for cell in row)) - - # 运行算法 - algorithm = Greedy3x3Algorithm(demo_maze, debug=True) - result = algorithm.run() - - # 打印结果 - algorithm.print_result() - - return algorithm, result - - -if __name__ == "__main__": - demo() diff --git a/greedy_resource_collector.py b/greedy_resource_collector.py deleted file mode 100644 index 0095a7d..0000000 --- a/greedy_resource_collector.py +++ /dev/null @@ -1,448 +0,0 @@ -import copy -from collections import deque - -class GreedyResourceCollector: - """ - 基于贪心算法的资源收集器 - 每次移动时选择3x3视野范围内最高价值的资源 - 只能进行上下左右移动 - """ - - def __init__(self, maze, start_pos=None, end_pos=None): - """ - 初始化贪心资源收集器 - - Args: - maze: 迷宫地图,2D列表 - start_pos: 起始位置 (row, col),如果为None则自动寻找 - end_pos: 目标位置 (row, col),如果为None则自动寻找 - """ - self.original_maze = copy.deepcopy(maze) - self.maze = copy.deepcopy(maze) - self.rows = len(maze) - self.cols = len(maze[0]) if self.rows > 0 else 0 - - # 寻找起始位置和目标位置 - self.start_pos = start_pos or self._find_position('s') - self.end_pos = end_pos or self._find_position('e') - - if not self.start_pos: - raise ValueError("无法找到起始位置 's'") - if not self.end_pos: - raise ValueError("无法找到目标位置 'e'") - - self.current_pos = self.start_pos - self.path = [self.start_pos] - self.collected_resources = [] - self.total_value = 0 - self.visited_resources = set() - - print(f"起始位置: {self.start_pos}") - print(f"目标位置: {self.end_pos}") - - def _find_position(self, target): - """寻找地图中指定字符的位置""" - for i in range(self.rows): - for j in range(self.cols): - if self.maze[i][j].lower() == target.lower(): - return (i, j) - return None - - def get_3x3_vision(self, pos): - """ - 获取以pos为中心的3x3视野范围内的所有单元格 - - Args: - pos: 当前位置 (row, col) - - Returns: - dict: {(row, col): cell_value} 形式的字典 - """ - row, col = pos - vision = {} - - # 遍历3x3范围 - for dr in range(-1, 2): - for dc in range(-1, 2): - new_row, new_col = row + dr, col + dc - - # 检查边界 - if 0 <= new_row < self.rows and 0 <= new_col < self.cols: - vision[(new_row, new_col)] = self.maze[new_row][new_col] - - return vision - - def get_adjacent_cells(self, pos): - """ - 获取当前位置的上下左右四个相邻位置 - - Args: - pos: 当前位置 (row, col) - - Returns: - list: 可移动的相邻位置列表 - """ - row, col = pos - adjacent = [] - - # 上下左右四个方向 - directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] - - for dr, dc in directions: - new_row, new_col = row + dr, col + dc - - # 检查边界和可移动性 - if (0 <= new_row < self.rows and - 0 <= new_col < self.cols and - self.can_move_to((new_row, new_col))): - adjacent.append((new_row, new_col)) - - return adjacent - - def can_move_to(self, pos): - """ - 检查是否可以移动到指定位置 - - Args: - pos: 目标位置 (row, col) - - Returns: - bool: 是否可以移动 - """ - row, col = pos - cell = self.maze[row][col] - - # 不能移动到墙壁 - if cell == '1': - return False - - return True - - def evaluate_resource_value(self, cell): - """ - 评估资源的价值 - - Args: - cell: 单元格内容 - - Returns: - int: 资源价值,正数表示收益,负数表示损失 - """ - if cell.startswith('g'): - # 金币资源,提取数值 - try: - return int(cell[1:]) - except ValueError: - return 0 - elif cell.startswith('t'): - # 陷阱资源,提取数值并取负 - try: - return -int(cell[1:]) - except ValueError: - return 0 - else: - # 其他类型单元格没有资源价值 - return 0 - - def find_best_resource_in_vision(self): - """ - 在3x3视野范围内找到价值最高的可到达资源 - 如果视野内没有正价值资源,则考虑移动到更有利的位置 - - Returns: - tuple: (最佳资源位置, 资源价值) 或 (None, 0) - """ - vision = self.get_3x3_vision(self.current_pos) - - best_pos = None - best_value = float('-inf') - - # 首先只考虑正价值资源 - for pos, cell in vision.items(): - # 跳过已访问的资源 - if pos in self.visited_resources: - continue - - # 跳过当前位置 - if pos == self.current_pos: - continue - - # 跳过不可移动的位置 - if not self.can_move_to(pos): - continue - - # 检查是否为资源 - value = self.evaluate_resource_value(cell) - if value > 0 and value > best_value: # 只考虑正价值资源 - # 确保可以到达这个位置 - path_to_resource = self.find_path_to_target(pos) - if path_to_resource: # 可以到达 - best_value = value - best_pos = pos - - # 如果视野内没有正价值资源,考虑负价值资源(陷阱) - if best_pos is None: - for pos, cell in vision.items(): - if pos in self.visited_resources or pos == self.current_pos: - continue - if not self.can_move_to(pos): - continue - - value = self.evaluate_resource_value(cell) - if value < 0 and value > best_value: # 选择损失最小的陷阱 - path_to_resource = self.find_path_to_target(pos) - if path_to_resource: - best_value = value - best_pos = pos - - # 如果视野内完全没有资源,寻找最近的正价值资源 - if best_pos is None: - best_pos, best_value = self.find_nearest_valuable_resource() - - return best_pos, best_value if best_pos else 0 - - def find_nearest_valuable_resource(self): - """ - 在整个地图上寻找最近的高价值正资源 - - Returns: - tuple: (最佳资源位置, 资源价值) 或 (None, 0) - """ - best_pos = None - best_score = float('-inf') - - for i in range(self.rows): - for j in range(self.cols): - pos = (i, j) - cell = self.maze[i][j] - - # 跳过已访问的资源 - if pos in self.visited_resources: - continue - - # 跳过当前位置 - if pos == self.current_pos: - continue - - # 检查是否为正价值资源 - value = self.evaluate_resource_value(cell) - if value > 0: # 只考虑正价值资源 - # 计算到达该资源的路径 - path_to_resource = self.find_path_to_target(pos) - if path_to_resource: - # 计算性价比:价值/距离 - distance = len(path_to_resource) - score = value / distance - - if score > best_score: - best_score = score - best_pos = pos - - if best_pos: - value = self.evaluate_resource_value(self.maze[best_pos[0]][best_pos[1]]) - return best_pos, value - - return None, 0 - - def find_path_to_target(self, target_pos): - """ - 使用BFS找到到目标位置的最短路径 - - Args: - target_pos: 目标位置 (row, col) - - Returns: - list: 从当前位置到目标位置的路径(不包含当前位置) - """ - if self.current_pos == target_pos: - return [] - - queue = deque([(self.current_pos, [])]) - visited = {self.current_pos} - - while queue: - pos, path = queue.popleft() - - # 获取相邻位置 - for next_pos in self.get_adjacent_cells(pos): - if next_pos in visited: - continue - - new_path = path + [next_pos] - - # 找到目标 - if next_pos == target_pos: - return new_path - - visited.add(next_pos) - queue.append((next_pos, new_path)) - - return [] # 无法到达 - - def collect_resource(self, pos): - """ - 收集指定位置的资源 - - Args: - pos: 资源位置 (row, col) - """ - row, col = pos - cell = self.maze[row][col] - value = self.evaluate_resource_value(cell) - - if value != 0: - self.collected_resources.append({ - 'position': pos, - 'type': cell, - 'value': value - }) - self.total_value += value - self.visited_resources.add(pos) - - print(f"收集资源: 位置{pos}, 类型{cell}, 价值{value}, 总价值{self.total_value}") - - def run_greedy_collection(self): - """ - 运行贪心资源收集算法 - - Returns: - dict: 包含路径、收集的资源等信息 - """ - print("开始贪心资源收集...") - - while True: - # 在3x3视野内寻找最佳资源 - best_resource_pos, best_value = self.find_best_resource_in_vision() - - if best_resource_pos is None: - print("视野内没有更多资源可收集") - break - - print(f"发现最佳资源: 位置{best_resource_pos}, 价值{best_value}") - - # 计算到最佳资源的路径 - path_to_resource = self.find_path_to_target(best_resource_pos) - - if not path_to_resource: - print(f"无法到达资源位置{best_resource_pos}") - self.visited_resources.add(best_resource_pos) # 标记为无法到达 - continue - - # 移动到资源位置 - for next_pos in path_to_resource: - self.current_pos = next_pos - self.path.append(next_pos) - print(f"移动到: {next_pos}") - - # 收集资源 - self.collect_resource(best_resource_pos) - - print("资源收集完成!") - return self.get_collection_result() - - def get_collection_result(self): - """ - 获取收集结果 - - Returns: - dict: 包含路径、资源、统计信息的字典 - """ - return { - 'path': self.path.copy(), - 'collected_resources': self.collected_resources.copy(), - 'total_value': self.total_value, - 'total_moves': len(self.path) - 1, - 'resources_count': len(self.collected_resources), - 'start_pos': self.start_pos, - 'end_pos': self.end_pos, - 'final_pos': self.current_pos - } - - def print_result_summary(self): - """打印收集结果摘要""" - result = self.get_collection_result() - - print("\n=== 贪心资源收集结果摘要 ===") - print(f"起始位置: {result['start_pos']}") - print(f"最终位置: {result['final_pos']}") - print(f"总移动步数: {result['total_moves']}") - print(f"收集资源数量: {result['resources_count']}") - print(f"资源总价值: {result['total_value']}") - - print("\n收集的资源详情:") - for i, resource in enumerate(result['collected_resources'], 1): - print(f" {i}. 位置{resource['position']}: {resource['type']} (价值: {resource['value']})") - - print(f"\n完整移动路径: {' -> '.join(map(str, result['path']))}") - - def visualize_path_on_maze(self): - """ - 在迷宫上可视化移动路径 - - Returns: - list: 标记了路径的迷宫副本 - """ - visual_maze = copy.deepcopy(self.original_maze) - - # 标记路径 - for i, pos in enumerate(self.path): - row, col = pos - if pos == self.start_pos: - visual_maze[row][col] = 'S' # 起点 - elif pos == self.end_pos: - visual_maze[row][col] = 'E' # 终点 - elif pos in [r['position'] for r in self.collected_resources]: - # 已收集的资源位置 - visual_maze[row][col] = '*' - else: - # 路径点 - visual_maze[row][col] = str(i % 10) - - return visual_maze - - def print_visual_maze(self): - """打印可视化的迷宫""" - visual_maze = self.visualize_path_on_maze() - - print("\n=== 路径可视化迷宫 ===") - print("S: 起点, E: 终点, *: 已收集资源, 数字: 路径步骤") - for row in visual_maze: - print(' '.join(f"{cell:>2}" for cell in row)) - - -def demo_greedy_resource_collection(): - """演示贪心资源收集算法""" - - # 创建一个示例迷宫 - demo_maze = [ - ['s', '0', 'g5', '1', 't3'], - ['0', '1', '0', '0', 'g2'], - ['g3', '0', '1', 't2', '0'], - ['0', 't1', '0', '0', 'g4'], - ['1', '0', 'g1', '0', 'e'] - ] - - print("=== 贪心资源收集算法演示 ===") - print("迷宫说明:") - print(" s: 起点, e: 终点") - print(" g数字: 金币资源 (正收益)") - print(" t数字: 陷阱资源 (负收益)") - print(" 0: 可通行路径, 1: 墙壁") - print("\n原始迷宫:") - for row in demo_maze: - print(' '.join(f"{cell:>2}" for cell in row)) - - # 创建贪心收集器并运行 - collector = GreedyResourceCollector(demo_maze) - result = collector.run_greedy_collection() - - # 打印结果 - collector.print_result_summary() - collector.print_visual_maze() - - return collector, result - - -if __name__ == "__main__": - # 运行演示 - collector, result = demo_greedy_resource_collection() diff --git a/main.py b/main.py index 5578ada..6d6c1f9 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,6 @@ from draw import Button, Toast from save_ui import SaveLoadUI from boss_fight_ui import BossFightUI from mechanism_ui import MechanismUI -from greedy_3x3_algorithm import Greedy3x3Algorithm from config import * import sys import os diff --git a/maze.py b/maze.py index 315b312..e3665d1 100644 --- a/maze.py +++ b/maze.py @@ -3,7 +3,6 @@ from maze_generator import MazeGenerator from SourceCollector import SourceCollector from tanxin import * from simple_save_manager import simple_save_manager -from greedy_3x3_algorithm import Greedy3x3Algorithm from config import UI_WIDTH import time import random diff --git a/tanxin.py b/tanxin.py index 056c0ff..a66d5cc 100644 --- a/tanxin.py +++ b/tanxin.py @@ -50,6 +50,9 @@ class Greedy3x3ResourceCollector: self.oscillation_detection = [] # 用于检测来回走动的历史 self.max_oscillation_length = 6 # 检测来回走动的最大长度 + # 预处理每个点到终点的距离 + self.distance_to_end = self._calculate_distance_to_end() + print(f"3x3视野贪心算法初始化") print(f"起始位置: {self.start}") print(f"目标位置: {self.end}") @@ -58,7 +61,8 @@ class Greedy3x3ResourceCollector: """寻找地图中指定字符的位置,返回(x, y)格式""" for y in range(self.rows): for x in range(self.cols): - if self.map_data[y][x].lower() == target.lower(): + cell_value = str(self.map_data[y][x]).lower() + if cell_value.startswith(target.lower()): return (x, y) return None @@ -160,14 +164,16 @@ class Greedy3x3ResourceCollector: def find_best_resource_in_3x3_vision(self): """ - 在3x3视野内寻找最佳资源 - 优先级:金币 > 未走过 > 走过的路(优先很久之前走过的路) > 墙/陷阱 + 在3x3视野内寻找最佳资源,新的优先级顺序: + 1. 金币(优先直接相邻,也考虑对角线上可通过两步到达的) + 2. 空地(优先离终点更近的) + 3. boss或机关 + 4. 陷阱(尽可能减少损失) + 5. 墙壁不考虑 + 加入死胡同检测和回溯机制 """ x, y = self.current_pos - best_pos = None - best_value = float('-inf') - best_visited_time = float('inf') # 更新当前位置的访问次数 self.position_visit_count[self.current_pos] = self.position_visit_count.get(self.current_pos, 0) + 1 @@ -233,67 +239,135 @@ class Greedy3x3ResourceCollector: if least_visited: return least_visited, 0 # 访问次数最少的位置,价值为0 - # 在3x3视野内寻找最佳位置 + # 按照新的优先级在3x3视野内寻找最佳位置 + # 1. 收集相邻和对角线上的所有单元格 + adjacent_cells = [] # 相邻的单元格 [(pos, cell_type, value)] + diagonal_cells = [] # 对角线上的单元格 [(pos, cell_type, value, can_reach)] + for i in range(-1, 2): for j in range(-1, 2): - # 跳过自身和对角线位置 - if (i == 0 and j == 0) or (i != 0 and j != 0): - continue - nx, ny = x + i, y + j # 检查位置是否在地图范围内 if 0 <= nx < self.cols and 0 <= ny < self.rows: - cell = self.map_data[ny][nx] pos = (nx, ny) + cell = self.map_data[ny][nx] # 检查是否是墙,不能走 if cell == '1': continue - + # 计算资源价值 value = self.evaluate_resource_value(cell) + cell_type = self._get_cell_type(cell) - # 检查是否已经走过这个位置 - is_visited = pos in self.explored_positions - visited_time = self.position_visit_count.get(pos, 0) - - # 计算探索潜力 - exploration_potential = self.calculate_exploration_potential(pos) - - # 优先级计算逻辑 - # 1. 金币优先 - if value > 0: - if (value > best_value or - (value == best_value and - ((not is_visited and best_visited_time > 0) or - (is_visited and visited_time < best_visited_time)))): - best_value = value - best_pos = pos - best_visited_time = visited_time if is_visited else 0 - # 2. 没有金币,选择未走过的路 - elif not is_visited: - if best_value <= 0 and (best_visited_time > 0 or exploration_potential > best_value): - best_value = exploration_potential - best_pos = pos - best_visited_time = 0 - # 3. 如果都走过了,选择走过次数最少的路 - elif is_visited and visited_time < best_visited_time: - if best_value <= 0: - best_value = -visited_time # 负值,访问次数越少越好 - best_pos = pos - best_visited_time = visited_time + # 相邻位置(上下左右) + if i == 0 or j == 0: + if i != 0 or j != 0: # 排除自身位置 + adjacent_cells.append((pos, cell_type, value)) + # 对角线位置 + else: + # 判断是否可以两步到达 + can_reach = self._can_reach_diagonal_coin(self.current_pos, pos) + diagonal_cells.append((pos, cell_type, value, can_reach)) + + # 2. 优先级1:查找相邻的金币 + adjacent_coins = [(pos, value) for pos, cell_type, value in adjacent_cells + if cell_type == 'gold' and value > 0] + + if adjacent_coins: + # 如果有多个金币,选择价值最高的 + best_coin = max(adjacent_coins, key=lambda x: x[1]) + return best_coin + + # 3. 优先级2:查找可达的对角线上的金币 + diagonal_coins = [(pos, value) for pos, cell_type, value, can_reach in diagonal_cells + if cell_type == 'gold' and value > 0 and can_reach] + + if diagonal_coins: + # 如果有多个可达的对角线金币,选择价值最高的 + best_diag_coin = max(diagonal_coins, key=lambda x: x[1]) + # 计算到达这个对角线金币的两步路径中的第一步 + dx, dy = best_diag_coin[0] + step_x = 1 if dx > x else -1 + step_y = 1 if dy > y else -1 + + # 检查两种可能路径的第一步 + path1_pos = (x + step_x, y) + path2_pos = (x, y + step_y) + + # 选择离终点更近的路径 + dist1 = self.distance_to_end.get(path1_pos, float('inf')) + dist2 = self.distance_to_end.get(path2_pos, float('inf')) + + if dist1 <= dist2 and self.can_move_to(path1_pos): + return path1_pos, 0 + elif self.can_move_to(path2_pos): + return path2_pos, 0 + + # 4. 优先级3:查找空地,优先选择离终点更近的 + empty_spaces = [(pos, self.distance_to_end.get(pos, float('inf'))) + for pos, cell_type, _ in adjacent_cells + if cell_type == 'empty'] + + if empty_spaces: + # 选择离终点最近的空地 + best_empty = min(empty_spaces, key=lambda x: x[1]) + return best_empty[0], 0 + + # 5. 优先级4:boss或机关 + mechanism_positions = [(pos, value) for pos, cell_type, value in adjacent_cells + if cell_type in ['boss', 'mechanism']] + + if mechanism_positions: + # 选择任意一个boss或机关位置 + return mechanism_positions[0][0], mechanism_positions[0][1] + + # 6. 优先级5:陷阱,尽可能减少损失 + trap_positions = [(pos, value) for pos, cell_type, value in adjacent_cells + if cell_type == 'trap'] + + if trap_positions: + # 选择损失最小的陷阱(value是负数,所以用max) + best_trap = max(trap_positions, key=lambda x: x[1]) + return best_trap # 如果找不到合适的位置,就选择任意一个可行的相邻位置 - if best_pos is None: - for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]: - nx, ny = x + dx, y + dy - if (0 <= nx < self.cols and 0 <= ny < self.rows and - self.map_data[ny][nx] != '1'): # 使用'1'表示墙壁 - best_pos = (nx, ny) - break + for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]: + nx, ny = x + dx, y + dy + if (0 <= nx < self.cols and 0 <= ny < self.rows and + self.map_data[ny][nx] != '1'): # 使用'1'表示墙壁 + return (nx, ny), 0 - return best_pos, best_value if best_value > float('-inf') else 0 + # 如果实在没有可行位置,返回None + return None, 0 + + def _get_cell_type(self, cell): + """ + 获取单元格类型 + + Args: + cell: 单元格内容 + + Returns: + str: 'gold', 'trap', 'boss', 'mechanism', 'empty', 'wall', 'start', 'end' + """ + if cell.startswith('g'): + return 'gold' + elif cell.startswith('t'): + return 'trap' + elif cell.startswith('b'): + return 'boss' + elif cell.startswith('l'): + return 'mechanism' + elif cell == 's': + return 'start' + elif cell == 'e': + return 'end' + elif cell == '1': + return 'wall' + else: + return 'empty' # 包括 '0' 和其他可通行的单元格 def find_exploration_target(self): """ @@ -623,6 +697,227 @@ class Greedy3x3ResourceCollector: return potential + def _calculate_distance_to_end(self): + """ + 使用BFS预处理计算每个点到终点的距离 + 返回字典 {(x, y): distance} + """ + distances = {} + queue = deque([(self.end, 0)]) # (位置, 距离) + visited = {self.end} + + # 方向:上、下、左、右 + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + + while queue: + (x, y), dist = queue.popleft() + distances[(x, y)] = dist + + # 检查四个方向 + for dx, dy in directions: + nx, ny = x + dx, y + dy + + # 检查边界和可行性 + if (0 <= nx < self.cols and + 0 <= ny < self.rows and + self.map_data[ny][nx] != '1' and # 不是墙 + (nx, ny) not in visited): + + visited.add((nx, ny)) + queue.append(((nx, ny), dist + 1)) + + print(f"已预处理完成从终点的距离计算,可达点数量: {len(distances)}") + return distances + + def _can_reach_diagonal_coin(self, current_pos, diagonal_pos): + """ + 检查对角线上的金币是否可通过两步到达 + + Args: + current_pos: 当前位置 (x, y) + diagonal_pos: 对角线上的金币位置 (x, y) + + Returns: + bool: 是否可以通过两步到达 + """ + cx, cy = current_pos + dx, dy = diagonal_pos + + # 计算方向 + step_x = 1 if dx > cx else -1 + step_y = 1 if dy > cy else -1 + + # 检查两种可能的两步路径 + path1 = [(cx + step_x, cy), diagonal_pos] # 先横后纵 + path2 = [(cx, cy + step_y), diagonal_pos] # 先纵后横 + + # 检查路径1是否可行 + path1_valid = True + for x, y in path1: + if not (0 <= x < self.cols and 0 <= y < self.rows and self.map_data[y][x] != '1'): + path1_valid = False + break + + # 检查路径2是否可行 + path2_valid = True + for x, y in path2: + if not (0 <= x < self.cols and 0 <= y < self.rows and self.map_data[y][x] != '1'): + path2_valid = False + break + + return path1_valid or path2_valid + + def add_path_to_map(self): + """ + 将路径标记到地图上 + + Returns: + list: 标记了路径的地图 + """ + marked_map = copy.deepcopy(self.original_map) + + # 标记起点和终点 + sx, sy = self.start + ex, ey = self.end + marked_map[sy][sx] = 'S' + marked_map[ey][ex] = 'E' + + # 标记路径 + for i, (x, y) in enumerate(self.path): + # 跳过起点和终点 + if (x, y) == self.start or (x, y) == self.end: + continue + + # 检查是否是资源位置 + cell = self.original_map[y][x] + if (x, y) in self.visited_resources: + marked_map[y][x] = '*' # 已收集资源 + else: + # 只有不是特殊位置才标记为路径 + if not (cell.startswith('g') or cell.startswith('t') or + cell.startswith('b') or cell.startswith('l')): + marked_map[y][x] = '.' # 路径 + + return marked_map + + + """ + 传统的贪心路径寻找算法 + """ + +class GreedyPlayer: + """ + 传统贪心路径寻找算法 + """ + + def __init__(self, map_data): + """ + 初始化贪心玩家 + + Args: + map_data: 迷宫地图,2D列表 (注意:这里是[y][x]格式) + """ + self.map_data = copy.deepcopy(map_data) + self.rows = len(map_data) + self.cols = len(map_data[0]) if self.rows > 0 else 0 + + # 寻找起点和终点 + self.start = None + self.end = None + for y in range(self.rows): + for x in range(self.cols): + cell_value = str(self.map_data[y][x]).lower() + if cell_value.startswith('s'): + self.start = (x, y) + elif cell_value.startswith('e'): + self.end = (x, y) + + if not self.start or not self.end: + raise ValueError("无法找到起点或终点") + + self.path = [] + self.marked_map = copy.deepcopy(map_data) + self.total_reward = 0 + + def find_path(self): + """ + 使用传统贪心算法寻找路径 + """ + current = self.start + self.path = [current] + visited = set([current]) + + while current != self.end: + x, y = current + best_move = None + best_value = float('-inf') + + # 检查四个方向 + for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]: + nx, ny = x + dx, y + dy + + if (0 <= nx < self.cols and 0 <= ny < self.rows and + str(self.map_data[ny][nx]) != '1' and + (nx, ny) not in visited): + + # 计算移动价值 + cell = str(self.map_data[ny][nx]) + value = 0 + + # 终点最高价值 + if cell.lower().startswith('e'): + value = float('inf') + # 金币为正价值 + elif cell.lower().startswith('g'): + try: + value = int(cell[1:]) + except ValueError: + value = 1 + # 陷阱为负价值 + elif cell.lower().startswith('t'): + try: + value = -int(cell[1:]) + except ValueError: + value = -1 + + if value > best_value: + best_value = value + best_move = (nx, ny) + + if best_move: + # 更新当前位置 + current = best_move + self.path.append(current) + visited.add(current) + + # 收集资源 + x, y = current + cell = str(self.map_data[y][x]) + if cell.lower().startswith('g'): + try: + self.total_reward += int(cell[1:]) + except ValueError: + self.total_reward += 1 + elif cell.lower().startswith('t'): + try: + self.total_reward -= int(cell[1:]) + except ValueError: + self.total_reward -= 1 + + # 标记路径 + if not cell.lower().startswith('e'): + self.marked_map[y][x] = '.' + else: + # 无法继续移动 + break + + return self.path + + def get_total_reward(self): + """ + 获取收集到的总奖励 + """ + return self.total_reward # 使用示例 def main():