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

381 lines
13 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.

"""
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()