A-start寻路算法 Python 实现

A-start寻路算法 Python 实现

# -*- coding:utf-8 -*-
import heapq

import time
from typing import List, Optional


class SearchNode:

    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y
        # search property
        self.h = 0.0  # Manhattan Distance
        self.g = 0.0  # 实际代价
        self.f = 0.0  # 优先级
        self.parent: Optional[SearchNode] = None
        # 是否关闭
        self.closed = False

    def __hash__(self):
        return hash((self.x, self.y))

    def __lt__(self, other):
        return self.f < other.f

    def __repr__(self):
        return f"({self.x},{self.y})"

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __sub__(self, other):
        # 符合向量减法
        x = other.x - self.x
        y = other.y - self.y
        return SearchNode(x, y)


class AStarDetector:

    def __init__(self, step=None):
        """

        Args:
            step: 步长
        """

        if not step:
            self.step = 1
        else:
            self.step = step

    def find_shortest_path(self, start_node: SearchNode, end_node: SearchNode) -> List[SearchNode]:
        """
        返回最短路径
        Args:
            start_node:
            end_node:

        Returns:
        """

        if start_node == end_node:
            return [start_node, end_node]

        # 初始化开放列表和关闭列表
        open_list = [start_node]

        heapq.heapify(open_list)
        start_time = time.time()
        closes = []
        while open_list and time.time() - start_time < 0.03:
            # while open_list:
            # 选择当前f值最小的节点进行探索
            current_node = heapq.heappop(open_list)
            current_node.closed = True
            closes.append(current_node)
            if current_node == end_node:
                # 如果当前节点是目标节点,重构路径并返回
                result_path = []
                while current_node:
                    result_path.append(current_node)
                    current_node = current_node.parent
                return result_path[::-1]
            # 获取相邻节点
            neighbors = self.get_neighbors(current_node)

            for neighbor in neighbors:
                if neighbor.closed:
                    continue

                tentative_g = current_node.g + self.heuristics_calc_cost(current_node, neighbor)
                if neighbor not in open_list or tentative_g < neighbor.g:
                    # 更新节点信息
                    neighbor.g = tentative_g
                    neighbor.h = self.calculate_distance(neighbor, end_node)
                    neighbor.f = neighbor.g + neighbor.h
                    neighbor.parent = current_node

                    if neighbor not in open_list:
                        heapq.heappush(open_list, neighbor)

        return []

    def get_neighbors(self, current_node: SearchNode) -> List[SearchNode]:
        """
         实现获取相邻节点的逻辑, 避让在这里处理,如果需要避让就不要返回那个点
        Args:
            current_node:
        Returns:

        """
        neighbors = []
        x = current_node.x
        y = current_node.y

        def check(x, y):
            neighbors.append(SearchNode(x, y))

        # 上
        check(x, y + self.step)
        # 右
        check(x + self.step, y)
        # 下
        check(x, y - self.step)
        # 左
        check(x - self.step, y)

        return neighbors

    @staticmethod
    def calculate_distance(node1: SearchNode, node2: SearchNode) -> float:
        """
        实现计算两个节点之间的曼哈顿距离,启发函数
        Args:
            node1:
            node2:

        Returns:

        """
        dx = abs(node1.x - node2.x)
        dy = abs(node1.y - node2.y)

        return dx + dy

    @staticmethod
    def heuristics_calc_cost(current_node: SearchNode, neighbor: SearchNode):
        """
        代价函数
        Args:
            current_node:
            neighbor:

        Returns:

        """
        # 同向优先保持不会一直转弯
        a = neighbor - current_node

        # TODO 考虑格点距离
        if current_node.parent:
            b = current_node - current_node.parent
        else:
            return 1
        if a == b:
            return 1
        else:
            return 2


if __name__ == '__main__':
    a = AStarDetector(step=1)
    s = SearchNode(0, 0)
    e = SearchNode(4, 4)

    print(a.find_shortest_path(s, e))

### A* 寻路算法 Python 实现 A* 寻路算法是一种用于路径寻找和图遍历的流行算法,它通过启发式方法来提高效率。该算法广泛应用于游戏中的人工智能部分,比如让游戏角色能够避开障碍物并找到到达目标位置的最佳路线。 #### 初始化节点类 为了实现这个算法,首先定义一个表示地图上各个位置的`Node`类: ```python class Node: """初始化节点""" def __init__(self, parent=None, position=None): self.parent = parent self.position = position self.g = 0 # 到起始节点的距离成本 self.h = 0 # 启发式的估计到结束节点的成本 self.f = 0 # 总成本 def __eq__(self, other): return self.position == other.position ``` #### 定义辅助函数 接着创建一些帮助函数来进行必要的操作,例如计算两个点间的曼哈顿距离作为启发式评估的一部分: ```python def manhattan_distance(point_a, point_b): """返回两点间基于曼哈顿公式的距离""" (x1, y1), (x2, y2) = point_a, point_b return abs(x1 - x2) + abs(y1 - y2) def reconstruct_path(current_node): path = [] current = current_node while current is not None: path.append(current.position) current = current.parent return path[::-1] # 反转列表以获得正确的顺序 ``` #### 主要逻辑流程 核心在于循环直到开放列表为空或者找到了通往目的地的有效路径为止: ```python def astar(maze, start, end): """ 返回从start到end的一条最短路径以及其长度; 如果不存在这样的路径,则返回None。 """ # 创建起点和终点对象 start_node = Node(None, tuple(start)) start_node.g = start_node.h = start_node.f = 0 end_node = Node(None, tuple(end)) end_node.g = end_node.h = end_node.f = 0 open_list = [] # 待处理队列 closed_list = [] # 已经访问过的节点集合 open_list.append(start_node) adjacent_squares = ((0, -1), (0, 1), (-1, 0), (1, 0)) while len(open_list) > 0: # 获取当前f值最小的那个节点 current_node = min(open_list, key=lambda o: o.f) # 将此节点移至已关闭列表中 open_list.remove(current_node) closed_list.append(current_node) # 找到了目标则重建路径并退出 if current_node == end_node: return reconstruct_path(current_node)[^4] children = [] for new_position in adjacent_squares: node_position = ( current_node.position[0] + new_position[0], current_node.position[1] + new_position[1] ) within_range_criteria = [ node_position[0] >= 0, node_position[0] < len(maze), node_position[1] >= 0, node_position[1] < len(maze[node_position[0]]), ] walkable_terrain_criteria = maze[node_position[0]][node_position[1]] != 1 if all(within_range_criteria) and walkable_terrain_criteria: new_node = Node( current_node, node_position ) children.append(new_node) for child in children: if len([closed_child for closed_child in closed_list if closed_child == child]) > 0: continue child.g = current_node.g + 1 child.h = manhattan_distance(child.position, end_node.position) child.f = child.g + child.h if len([open_node for open_node in open_list \ if child == open_node and child.g > open_node.g]) > 0: continue open_list.append(child) warn('无法抵达') return None ``` 上述代码实现了基本版本的A*寻路算法,并利用了曼哈顿距离作为启发式估算器[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值