A*搜索四方向寻路 C++代码实现

眼馋A*算法很久了,可是很久却还不能入门。昨天终于狠下心来,花一天使劲折腾它,终于写出了A*搜索,(我写的是自动寻路系统,很多网游里面用的那种)。我也在网上搜了很久。但一直没有找到c++的实现,于是就自己造了这个轮子。下面是几张运行的截图:



关于A*算法的理论原理,网上已经有很多文章介绍了,而我只是初学,理论不是特别清晰,所以也不在此献丑了。仅在此贴上代码(已添加注释)(代码是在手机上完成的,所以缩进可能有些地方怪怪的。。。),之后附上个人的心得。
/*
    A*寻路.cpp 四方向版
         --sxysxy 2016-2-15 
         
    常数挺大的。。。可能小图跑不过dij 或者 spfa......
    代码写得灰常乱,因为本就不熟。。。然后还不想麻烦...
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <time.h>
#include <queue>
using namespace std;
#define INF (0x23333333)
#define MAXN (302)

//寻四方向用
const int dl[] = {1,-1,0,0};
const int dc[] = {0,0,-1,1};

int map[MAXN][MAXN]; //地图
int n,m;   //地图的行数列数
int g[MAXN][MAXN]; //已用代价,参数为行列坐标
int h[MAXN][MAXN]; //估计还需代价,参数为行列坐标
bool in_close[MAXN][MAXN]; //在关闭列表中,参数为行列坐标
bool in_open[MAXN][MAXN]; //在开启列表中,参数为行列坐标
bool ok = false;  //立一个找到解的flag
struct point
{
	int l,c;
	point(){}
	point(int _l, int _c){l=_l;c=_c;}
	bool operator<(const point &o) const
	{
		return g[l][c]+h[l][c]>g[o.l][o.c]+h[o.l][o.c];
		//启发数值在优先队列里面从小到大...
	}
};
point path[MAXN][MAXN];  //记录路径用
int sl,sc,tl,tc; //出发/目标点的位置
#define mkpt(a,b) (point{a,b})  
void find_path()
{
	int i,j;
	int cl,cc,nl,nc;
	//cl,cc当前处理的点的位置,
	//nl,nc当前处理的点的邻居的位置
	priority_queue<point> open_list;
	//用优先队列维护开启列表
	if(map[sl][sc] || map[tl][tc])return; //出发点或者目标点不可通行,返回
	for(i = 1; i <= n; i++)
	{
	    for(j = 1; j <= m; j++)
	    {
	        h[i][j] = (int)sqrt((double)(i-tl)*(i-tl)+(double)(j-tc)*(j-tc))+1;  //估计代价 = 这个点到目标点的几何距离向上取整
	        g[i][j] = INF; //已用代价初始化为INF
	    }
	}
	
	//出发点扔到open_list
	g[sl][sc] = 0;
	in_open[sl][sc] = true;
	open_list.push(mkpt(sl,sc));
	
	while(open_list.size())
	{
		cl = open_list.top().l;
		cc = open_list.top().c;
		open_list.pop();
		if(cl == tl && cc == tc)
		{  //找到目标,跳出循环
			ok = true;
			break;
		}
		//当前点算入关闭列表中
		in_close[cl][cc] = true;
		for(i = 0; i < 4; i++)
		{
			nl = cl+dl[i];
			nc = cc+dc[i];
			if(map[nl][nc] == 1)continue; //不可通行
			if(in_close[nl][nc])continue; //在关闭列表
			if(! in_open[nl][nc])
			{  //发现新节点
				open_list.push(mkpt(nl,nc));
			}else if(g[cl][cc]+1 >= g[nl][nc])
			    continue; //不是更好的解,continue
			    
			//找到一个更优的解,记录路径,更新g值
			path[nl][nc] = mkpt(cl,cc);
			g[nl][nc] = g[cl][cc] + 1;
		}
	}
}

void print_res()
{
	int l,c;
	int i,j;
	if(!ok)
	{
		printf("无法到达!\n");
		return;
	}
	printf("从出发点到目标点所需步数为:%d\n", g[tl][tc]);
	//回溯路径
	l = tl;
        c = tc;
	while(true)
	{
		map[l][c] = '*'-'0';
	    if(l == sl && c == sc)break;
	    i = path[l][c].l;
	    j = path[l][c].c;
	    l = i;
	    c = j;
	}
	map[sl][sc] = '%'-'0';
	//打印解法
	printf("走法如下 %%是出发点,*是路径:\n");
	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= m; j++)
		{
			printf("%c ", map[i][j]+'0');
		}
		putchar('\n');
	}
	
}

int main()
{
    int i, j;
    printf("=======A*搜索 四方向寻路系统=======\n");
    printf("先输入两个整数,n,m,表示下面将要输入一个n行m列的迷宫\n");
    scanf("%d %d", &n, &m);
    for(i = 0; i <= n+1; i++)
        for(j = 0; j <= m+1; j++)
            map[i][j] = 1;  //先初始化为全部为不可通行路块,便于处理
    printf("接下来输入这n行m列的迷宫,用0表示可通行的路块,1表示不可通行的路块\n");
    for(i = 1; i <= n; i++)
        for(j = 1; j <= m; j++)
            scanf("%d", &map[i][j]);
    printf("接下来输入起点和终点的位置,位置用行列来表示,行列从1开始计算\n");
    printf("起点位置:");
    scanf("%d %d", &sl, &sc);
    printf("终点位置:");
    scanf("%d %d", &tl, &tc);
    find_path();
    print_res();
    return 0;
}
心得体会方面,那就先说说心灵上的收获,那就是,不要怕一些东西难,真的狠心去学它了,总是能学到一些知识的,,,(怎么感觉跟小学生作文似的)

关于这个算法的方面:玄学!这跑起来来复杂度真是个玄学!启发式函数真是太奇妙,程序猿们要敢想,只要能够让优秀的解先被选到,即可。



  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的Python代码实现a*算法游戏自动寻路的示例: ``` import heapq def heuristic(a, b): # 计算两点间的曼哈顿距离 return abs(a[0] - b[0]) + abs(a[1] - b[1]) def astar(start, goal, graph): # 初始化起点和终点的f值 start_f = heuristic(start, goal) goal_f = 0 # 初始化起点的g值和f值 open_list = [(start_f, start)] g_score = {start: 0} f_score = {start: start_f} while open_list: # 获取当前f值最小的点 current_f, current = heapq.heappop(open_list) if current == goal: # 找到了终点,返回路径 path = [] while current in graph: path.append(current) current = graph[current] return path[::-1] # 遍历当前点的邻居 for neighbor in graph.get(current, []): # 计算邻居的g值 tentative_g = g_score[current] + 1 if neighbor not in g_score or tentative_g < g_score[neighbor]: # 更新邻居的g值和f值 g_score[neighbor] = tentative_g h_score = heuristic(neighbor, goal) f_score[neighbor] = tentative_g + h_score heapq.heappush(open_list, (f_score[neighbor], neighbor)) graph[neighbor] = current # 没有找到路径,返回空列表 return [] # 用一个字典来表示地图,'x'表示障碍物,'g'表示终点 graph = {'A': ['B', 'C'], 'B': ['D', 'E'], 'C': ['F', 'G'], 'D': [], 'E': ['H'], 'F': [], 'G': [], 'H': ['I'], 'I': ['J'], 'J': ['K'], 'K': ['L'], 'L': ['M'], 'M': ['g'], 'g': []} start = 'A' goal = 'g' path = astar(start, goal, graph) print(path) ``` 在这个示例中,我们使用了一个字典来表示地图,其中每个键都是一个节点,对应的值是它的邻居。我们使用了一个heuristic函数来计算两点之间的曼哈顿距离,以作为估价函数来帮助a*算法搜索最短路径。我们使用了一个优先队列(实现为堆)来按照f值排序并选择下一个要扩展的节点。我们使用了一个字典来记录每个节点的g值和f值,以及每个节点的父节点,以便在找到路径后可以回溯出完整的路径。最后,我们测试了代码并输出了找到的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值