⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 新建 文本文档 (2).txt

📁 算法的基本思想是……大家想看就可以下载哦
💻 TXT
字号:
A**寻路算法简介

阅读本文以前,可能大家已经接触过A*算法,如果没有,那也没关系。想了解A*算法的更多内容,可以去http://articles.gameres.com/搜索A*,那里有足够的文章让您理解A*算法的基本思路。
一、A**算法的基本思想

参考A*算法的文章《A* Pathfinding for Beginners》,我同样使用这个例题作为开头:
	0	1	2	3	4	5	6
0	 
图1.1
1	
2	
3	
4	
如图,绿色是起点,红色是终点,蓝色是障碍物,这样的地图可以在内存中表示成一个二维数组:

0 0 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 1 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0
x1=1 y1=2
x2=5 y2=2
暂时限定不允许出界。允许横走、直走和斜走,求最短的到达目标的路径。A**算法的基本思路就是:首先求出每一点到达终点的最短路径的长度(下面简称值),然后本着总是往值更少的位置走的原则,则走过的一定是最短路径。
首先,我们设置Value数组,用于记录每点的值。在未计算之前,全部标志为-1,就得到如下的数组:

-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	-1	-1	-1 

毫无疑问,终点离终点的距离是0,所以(5,2)的值可以置为0。因此值数组内容变成这样:
-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	-1	0	-1 
-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	-1	-1	-1 

这样,又由于它周围的点距离终点的距离不会超过它离终点距离+1,因此值数组变成这样:

-1	-1	-1	-1	-1	-1	-1 
-1	-1	-1	-1	1	1	1 
-1	-1	-1	-1	1	0	1 
-1	-1	-1	-1	1	1	1 
-1	-1	-1	-1	-1	-1	-1 

-1	-1	-1	2	2	2	2 
-1	-1	-1	-1	1	1	1 
-1	-1	-1	-1	1	0	1 
-1	-1	-1	-1	1	1	1 
-1	-1	-1	2	2	2	2 

要注意到,(3,1)、(3,2)、(3,3)三个点,虽然在点(4,2)周围,但是由于这三个点不可到达,所以搜索时不应改变他们的值。

-1	-1	3	2	2	2	2 
-1	-1	3	-1	1	1	1 
-1	-1	-1	-1	1	0	1 
-1	-1	3	-1	1	1	1 
-1	-1	3	2	2	2	2 

-1	4	3	2	2	2	2 
-1	4	3	-1	1	1	1 
-1	4	4	-1	1	0	1 
-1	4	3	-1	1	1	1 
-1	4	3	2	2	2	2 

5		4	3	2	2	2	2 
5		4	3	-1	1	1	1 
5		4	4	-1	1	0	1 
5		4	3	-1	1	1	1 
5		4	3	2	2	2	2 

这样,我们得到起点(1,2)到达目标需要4步,又由于(1,2)-(2,1)-(3,0)-(4,1)-(5,2)是一条值递减的路径,因此它也是从(1,2)点到达(5,2)点的最短路径。
换句话说,由于(1,2)点的值为4,(2,1)点的值为3,因此(1,2)点走到终点比(2,1)多需要一步,所以(1,2)点走向(2,1)点一定是更接近而不是更远离终点,这样走完全可以成为最短路径的一步。接下来每一步都保证值递减,也就是说经过了4步之后,到达的地点值一定为0,而地图上唯一值为0的位置就是终点,即4步后到达终点。
以上算法仍然属于广度优先算法,但它和经典广度优先算法的区别在于,经典广度优先算法运用结点的方式记录每个点的坐标,和走到这个点的父结点的坐标,而这个算法仅仅记录每点到终点的距离。当找到目标时,经典广度优先寻找终点结点的祖先结点并依次记录下来,而以上算法则不断在当前点周围寻找比当前点更接近终点的点,并且移动到该点。
:)当然,到目前为止,还没有看出我所谓A**算法有任何优势,但我可以用这样一种非广度优先方法来实现程序:

反复按顺序搜索整个数组,如果发现有已求值的点,它周围有未求值或者已知值但不如经过当前点的路线,则用新值覆盖下该点。知道找不到这样的点为止代码如下:

#define p(a,x,y) *(a+(x)+(y)*Width)				//为了更直观
int		Width,Height,Size;					//宽、高、总大小
char		*MAP;							//储存地图信息的数组
int		*Value;							//储存搜索信息的数组
int		x1,y1,x2,y2;
void	WORK_TDZL1()
{
	int i,j,
		b;									//用于标记
	for (i=0;i<Size;i++)
		*(Value+i)=-1;							//搜索前把所有位置标志为-1
	p(Value,x2,y2)=0;							//把终点标记为0
	b=1;

	while (b)
	{
		b=0;
		for (i=0;i<Width;i++)
			for (j=0;j<Height;j++)
			if (p(Value,i,j)>-1)
			{
				int x,y,k;
				for (k=0;k<8;k++)
				{
					x=i;y=j;
					switch (k)
					{
						case 0:x++;break;
						case 1:x--;break;
						case 2:y++;break;
						case 3:y--;break;
						case 4:x++;y++;break;
						case 5:x++;y--;break;
						case 6:x--;y++;break;
						case 7:x--;y--;break;
						default:break;
					}
					if ((x<0)||(y<0)||(x>Width)||(y>Height)) continue;
					if ((p(MAP,x,y)==0)&&((p(Value,x,y)==-1)||(p(Value,x,y)>p(Value,i,j)+1)))
					{
						p(Value,x,y)=p(Value,i,j)+1;
						b=1;
					}
				}
			}
	}
	if (p(Value,x1,y1)>-1)								//输出结果
	{
		int x,y,k;

		printf("Total %d step\n",p(Value,x1,y1));
		i=x1;j=y1;
		while ((i!=x2)||(j!=y2))
		{
			for (k=0;k<8;k++)
			{
				x=i;y=j;
				switch (k)
				{
					case 0:x++;break;
					case 1:x--;break;
					case 2:y++;break;
					case 3:y--;break;
					case 4:x++;y++;break;
					case 5:x++;y--;break;
					case 6:x--;y++;break;
					case 7:x--;y--;break;
					default:break;
				}
				if ((x<0)||(y<0)||(x>Width)||(y>Height)) continue;
				if (p(Value,x,y)==p(Value,i,j)-1)
				{
					i=x;j=y;break;
				}
			}
		//每次在这里取i和j的值
		}
		return;
	}
	printf("No answer!\n");
}

这段程序的意思是:首先,我们知道终点到终点的距离为0,然后不断扫描整幅地图,如果发现某点A的值已知,而它周围的某点B值未知且非障碍物,或者它B的值大于A的值+1,则将B的值设为A的值+1。因为A点可达,且B点非障碍物,因此B点一定可达并且值不会大于A点的值+1,因为由A点到B点为一可行策略。
然而,运行如上程序时我们会发现,它对付从左上到右下的路径非常在行,但是对于含由U型路径或回型路径甚至仅仅是从右下到左上的路径,它会变得非常缓慢。于是将程序优化如下:
void		WORK_TDZL3()
{
	int i,j,
		b;					//用于标记
	for (i=0;i<Size;i++)
		*(Value+i)=-1;
	p(Value,x2,y2)=0;
	b=1;

	while (b)
	{
		b=0;
		for (i=0;i<Width;i++)
			for (j=0;j<Height;j++)
			if (p(Value,i,j)>-1)
			{
				int x,y,k;
				for (k=0;k<3;k++)
				{
					x=i;y=j;
					switch (k)
					{
						case 0:y++;break;
						case 1:x++;y++;break;
						default:break;
					}
					if ((x<0)||(y<0)||(x>Width)||(y>Height)) continue;
					if ((p(MAP,x,y)==0)&&((p(Value,x,y)==-1)||(p(Value,x,y)>p(Value,i,j)+1)))
					{
						p(Value,x,y)=p(Value,i,j)+1;
						b=1;
					}
				}
			}

		for (i=0;i<Width;i++)
			for (j=Height-1;j>=0;j--)
			if (p(Value,i,j)>-1)
			{
				int x,y,k;
				for (k=0;k<3;k++)
				{
					x=i;y=j;
					switch (k)
					{
						case 0:x++;break;
						case 1:x++;y--;break;
						default:break;
					}
					if ((x<0)||(y<0)||(x>Width)||(y>Height)) continue;
					if ((p(MAP,x,y)==0)&&((p(Value,x,y)==-1)||(p(Value,x,y)>p(Value,i,j)+1)))
					{
						p(Value,x,y)=p(Value,i,j)+1;
						b=1;
					}
				}
			}

		for (i=Width-1;i>=0;i--)
			for (j=0;j<Height;j++)
			if (p(Value,i,j)>-1)
			{
				int x,y,k;
				for (k=0;k<3;k++)
				{
					x=i;y=j;
					switch (k)
					{
						case 0:x--;break;
						case 1:x--;y++;break;
						default:break;
					}
					if ((x<0)||(y<0)||(x>Width)||(y>Height)) continue;
					if ((p(MAP,x,y)==0)&&((p(Value,x,y)==-1)||(p(Value,x,y)>p(Value,i,j)+1)))
					{
						p(Value,x,y)=p(Value,i,j)+1;
						b=1;
					}
				}
			}

		for (i=Width-1;i>=0;i--)
			for (j=Height-1;j>=0;j--)
			if (p(Value,i,j)>-1)
			{
				int x,y,k;
				for (k=0;k<3;k++)
				{
					x=i;y=j;
					switch (k)
					{
						case 0:y--;break;
						case 1:x--;y--;break;
						default:break;
					}
					if ((x<0)||(y<0)||(x>Width)||(y>Height)) continue;
					if ((p(MAP,x,y)==0)&&((p(Value,x,y)==-1)||(p(Value,x,y)>p(Value,i,j)+1)))
					{
						p(Value,x,y)=p(Value,i,j)+1;
						b=1;
					}
				}
			}

	}

	if (p(Value,x1,y1)>-1)
	{
		//输出结果
		int x,y,k;
		printf("Total %d step\n",p(Value,x1,y1));
		i=x1;j=y1;
		while ((i!=x2)||(j!=y2))
		{
			for (k=0;k<8;k++)
			{
				x=i;y=j;
				switch (k)
				{
					case 0:x++;break;
					case 1:x--;break;
					case 2:y++;break;
					case 3:y--;break;
					case 4:x++;y++;break;
					case 5:x++;y--;break;
					case 6:x--;y++;break;
					case 7:x--;y--;break;
					default:break;
				}
				if ((x<0)||(y<0)||(x>Width)||(y>Height)) continue;
				if (p(Value,x,y)==p(Value,i,j)-1)
				{
					i=x;j=y;break;
				}
			}
		//每次在这里取i和j的值
		}
		return;
	}
	printf("No answer!\n");
}

:)由于时间关系在此不再详述,测试程序、代码及测试数据将在近期上传,比A*算法究竟好上几百倍大家自己体会吧,这可是即时对战游戏设计者梦寐以求的算法哦。本算法的特点是不怕地图大,不怕回形路,另外,本算法还有一个最大好处,就是对目标的一次计算,地图上所有点到达目标的路径都可以很方便的求出。当然具体运用时还得修改不少地方,但相信我的这篇文章你对你有所帮助。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -