maze_python/strict_3x3_greedy.py
2025-07-01 10:12:59 +08:00

338 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import copy
from collections import deque
class Strict3x3GreedyCollector:
"""
严格的3x3视野贪心资源收集器
每次移动时只考虑3x3视野范围内的资源
如果视野内没有资源,则随机移动探索
"""
def __init__(self, maze, start_pos=None, end_pos=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()
self.explored_positions = set([self.start_pos])
print(f"严格3x3视野模式")
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视野范围内的所有单元格"""
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):
"""获取当前位置的上下左右四个相邻位置"""
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):
"""检查是否可以移动到指定位置"""
row, col = pos
cell = self.maze[row][col]
# 不能移动到墙壁
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_3x3_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
# 检查是否可以直接到达(相邻位置)
if pos not in self.get_adjacent_cells(self.current_pos):
continue
# 检查是否为资源
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_cells(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):
"""收集指定位置的资源"""
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_strict_3x3_collection(self, max_moves=1000):
"""
运行严格3x3视野贪心资源收集算法
Args:
max_moves: 最大移动步数,防止无限循环
Returns:
dict: 包含路径、收集的资源等信息
"""
print("\\n开始严格3x3视野贪心资源收集...")
moves = 0
stuck_count = 0 # 连续无法找到资源的次数
max_stuck = 20 # 最大连续无资源次数
while moves < max_moves and stuck_count < max_stuck:
moves += 1
# 在3x3视野内寻找最佳资源
best_resource_pos, best_value = self.find_best_resource_in_3x3_vision()
if best_resource_pos is not None:
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:
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:
print(f"{moves}步: 无法进行任何移动,结束收集")
break
if moves >= max_moves:
print(f"达到最大移动步数 {max_moves},结束收集")
elif stuck_count >= max_stuck:
print(f"连续 {max_stuck} 步未找到资源,结束收集")
print("严格3x3视野资源收集完成")
return self.get_collection_result()
def get_collection_result(self):
"""获取收集结果"""
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,
'explored_positions': len(self.explored_positions)
}
def print_result_summary(self):
"""打印收集结果摘要"""
result = self.get_collection_result()
print("\\n=== 严格3x3视野贪心收集结果摘要 ===")
print(f"起始位置: {result['start_pos']}")
print(f"最终位置: {result['final_pos']}")
print(f"总移动步数: {result['total_moves']}")
print(f"探索位置数: {result['explored_positions']}")
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']})")
# 显示路径的关键点
path_points = result['path']
if len(path_points) <= 10:
path_str = ' -> '.join(map(str, path_points))
else:
path_str = f"{path_points[0]} -> ... -> {path_points[-1]} (共{len(path_points)}个位置)"
print(f"\\n移动路径: {path_str}")
def visualize_path_on_maze(self):
"""在迷宫上可视化移动路径"""
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 in [r['position'] for r in self.collected_resources]:
# 已收集的资源位置
visual_maze[row][col] = '*'
elif i == len(self.path) - 1:
# 最终位置
visual_maze[row][col] = 'F'
else:
# 路径点
visual_maze[row][col] = '.'
return visual_maze
def print_visual_maze(self):
"""打印可视化的迷宫"""
visual_maze = self.visualize_path_on_maze()
print("\\n=== 严格3x3视野路径可视化迷宫 ===")
print("S: 起点, F: 终点, *: 已收集资源, .: 路径")
for row in visual_maze:
print(' '.join(f"{cell:>2}" for cell in row))
def compare_algorithms():
"""比较不同算法的效果"""
# 创建一个更大的示例迷宫
demo_maze = [
['s', '0', 'g5', '1', 't3', '0', 'g8'],
['0', '1', '0', '0', 'g2', '1', '0'],
['g3', '0', '1', 't2', '0', '0', 'g6'],
['0', 't1', '0', '0', 'g4', '1', '0'],
['1', '0', 'g1', '0', '0', '0', 't5'],
['0', 'g7', '0', '1', '0', 'g9', '0'],
['t4', '0', '0', '0', '1', '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))
print("\\n" + "="*60)
print("严格3x3视野贪心算法:")
print("="*60)
# 运行严格3x3视野算法
strict_collector = Strict3x3GreedyCollector(demo_maze)
strict_result = strict_collector.run_strict_3x3_collection()
strict_collector.print_result_summary()
strict_collector.print_visual_maze()
return strict_collector, strict_result
if __name__ == "__main__":
# 运行比较演示
strict_collector, strict_result = compare_algorithms()