C++ A* Pathfinding Algorithm


     Because to develop game assistants, we need to solve the problem of pathfinding. Of course, there are many ways to find paths for game assistants. For example, fixed-point pathfinding is to pre-set several coordinate points. As long as there are no obstacles in the straight line between the points, it can be like a train. Run down the same way. For the large map in the game, such as taking an item from an NPC at point A and handing it to an NPC on the other end of the large map, it is more suitable to use this fixed-point pathfinding method. This method is simple and rude, and has effectiveness. The disadvantage is that if someone hits you halfway, you may deviate from the intended route and find your way home. At this point, we can combine the A* algorithm to clean up the stubble that interferes with our maintenance of world peace, and then automatically plan a route back to the point closest to the character, and continue to walk along the route. One of the problems of the A* algorithm is that it is easy to walk against the wall, especially when the channel is relatively "thick", but if you add other judgment conditions to the A* algorithm to optimize the pathfinding logic, it will increase the amount of calculation in each step of judgment. , although the basic A* algorithm has the problem of sticking to the wall, it is a choice with a balance between the amount of calculation and the calculation result.


First introduce the operation logic of the A* algorithm




     As shown in the simple map, the green square is the starting point (represented by A), the blue one in the middle is the obstacle, and the red square (represented by B) is the destination. In order to represent the map with a two-dimensional array, We divide the map into small squares.



Since it is written in C++, of course, the STL standard template library is used. STL provides several container types, which are implemented here using the list container.

Start pathfinding:

first set up 4 lists to

open the list

to close the list -- the closed list is all the checked squares . The

inspection list

result list -- stores the final path that has been determined, and finally walks along this path


1. First traverse From the 8 grids around the starting point, find all passable grids, calculate their FHG values ​​respectively, put them into the structure, and then put the structure into the open list.




     list容器提供了一个sort()方法,sort()方法又有一个重载版本,允许我们自定义一个函数来规定排序逻辑,因此我们可以指定sort()方法按照结构体内的某个变量来进行排序,在这里我们当然按照F值大小来进行排序,对比前后两个list元素的F值大小来进行排序。完成一次排序后,开启列表第一位的元素就是F值最小的那个格子了。


在这里需要说明一下F H G值分别代表什么,以及如何算出。

H


H值代表某个格子与终点的距离,或者也可以理解为移动到终点所需要花费的代价。H值有多种方法计算,比较常见的算法为曼哈顿算法和欧几里得算法,欧几里得算法其实就是勾股定理,计算的是某点与终点的直线距离;而曼哈顿算法则更简单粗暴一些,是用某点的X坐标减去终点X坐标,Y坐标减去终点Y坐标,最后取绝对值,然后把两个绝对值X Y相加就得到H值了。本例用的是曼哈顿算法。

G


G值就是当前格子移动到周围格子的路程(代价),比如说直着走肯定比斜着走路程短,经过业界大神夜以继日不眠不休的论证之后决定把直着的路程定义为10,斜着走的路程定义为14。

F


F值就是以上两个值G+H之和,反应了一个格子的总性价比。然后我们就依靠这个性价比来判断走这个格子划算还是走那个格子划算。



2.把起点放入关闭列表中,以免再次检测。

3.然后每个格子都有了自己的 F H G值,如下图,选择一个F值最小的,在图中是C方格,把它放进考察结构体中,然后遍历考察结构体周围的8个方格。放入考察列表中,排序后再次选出F值最小的那个格子。因为图片选择的这个终点的关系,所以导致C方格上面或下面的格子的F值是一样的,也就是往上或下走路程都一样,这里暂且假设D方格是开启列表中第一位的元素。


4.然后用考察列表中第一位的元素(也就是D)与开启列表中的所有元素对比一遍,看看开启列表中有没有同样的格子(格子D)。如果有就计算一下当前格子C走到D的G值之和是否小于D本身的G值。例如C点本身的G值是10,往下走算直线,G值也是10,10+10=20,20>14;说明绕远路了。


5.如果发现绕远路了,就把C格子放入关闭列表,然后清空开启列表和关闭列表。因为条件不满足,我们并没有更新当前点的坐标,所以程序会再次循环,找出开启列表中F值最小的点,又因为C格子已经被加入关闭列表,所以它并不会被加入开启列表中,此时开启列表中F值最小的格子就是D了,选择D作为考察点,把D周围的除墙以外符合条件的点全部加入考察列表,再次选出考察列表第一位的格子与开启列表中对比,有重复就检测G值,没有重复就可以确定这个格子适合作为路径,就用考察点更新当前点,然后把考察点加入关闭列表,同时把当前点加入结果列表。


6.重复以上过程,直到开启列表中出现终点坐标,或者所有格子都加入了关闭列表导致开启列表为空,寻路结束。



7.最后输出一下结果列表中的内容,就得到路径了。

     到此就是A*算法的一个寻路判断逻辑,还有一个小问题前面没有提到,就是路过墙角的时候允许不允许算法走斜线,如果不允许,就需要在遍历当前点或者考察点的时候考虑这个因素,我的办法是在遍历周围点的时候加一个判断,如果上下左右4个方向有一个方向判断是墙,就关闭一个开关变量,使得后面不再考虑斜着的4个方向,这样一旦靠墙的时候就只会"直来直去"。


下面是算法伪代码:


网格结构体{

int x坐标
int y坐标

int f
int g
int h

}网格; --实例化一个网格结构体 

起点x
起点y

终点x
终点y


开启列表
list<网格>开启列表;

关闭列表
list<网格>关闭列表;

考察列表
list<网格>考察列表

结果列表  --存放着已经确定的最终路径,最后就要沿着这个路径走路
list<网格>结果列表


当前结构体

待考察结构体

初始化当前结构体

初始化待考察结构体


list<网格>::iterator 开启列表迭代器;  --创建4个迭代器
list<网格>::iterator 关闭列表迭代器;
list<网格>::iterator 考察列表迭代器;
list<网格>::iterator 结果列表迭代器;

当前结构体->y=y;

当前结构体->x=x;   --起点x,起点y 送入当前结构体

int 开关变量=1;
int prize=1  //另一个判断用变量

while(开关变量==1)
{

if(开启列表.empty()) --如果开启列表空了就说明没找到路,退出循环

{

   开关变量=0
   break;

}


if(开关变量==1)


    
   --把开启列表作为参数,遍历当前结构体周围8个格子的结果就会放入开启列表中等待检测 

   清空开启列表

   清空考察列表


   遍历8方向函数(开启列表,当前结构体->y,当前结构体->x)  

   for(开启列表迭代器=开启列表.begin();开启列表迭代器!=开启列表.end();开启列表迭代器++)

   {

       --看看开启列表里是否已经有终点坐标,如果有说明寻路成功

       if(开启列表迭代器->y==终点y && 开启列表迭代器->x==终点x)

       {

       开关变量=0
       prize=0
       break;

       --寻路成功就关闭开关变量就不会进行下面的动作,结束寻路

       }

   }


if(prize==1)
{

   开启列表.sort()  --按结构体内F值大小排序,由小到大

   开启列表迭代器=开启列表.begin();
   
   选出开启列表中的第一个元素放入考察结构体,并在开启列表中删除第一个元素    
   
    --因为按照排序规则第一个元素的F值最小

   遍历8方向函数(考察列表,开启列表迭代器->y,开启列表迭代器->x)  --遍历考察方格附近的8个格子,把结果放入考察列表

   考察列表.sort()  --给考察列表排个序

   考察列表迭代器=考察列表.begin()  --让迭代器指向考察列表第一个元素

   int 标志3=1;

   for(开启列表迭代器=开启列表.begin();开启列表迭代器!=考察列表.end();开启列表迭代器++)

   {

       --把考察列表的第一个元素与开启列表里的所有元素都匹配一遍,如果匹配上了,说明考察列表的第一个元素可能不是最短路径

     

       if(考察列表迭代器->x==开启列表迭代器->x && 考察列表迭代器->y==开启列表迭代器->y)

       {

               if(考察结构体->G + 考察列表迭代器->G > 开启列表迭代器->G)

              {
               --考察结构体里的G值+考察列表迭代器第一个元素里的G值如果大于当前开启列表迭代器指向的元素里的G值,说                 --明这条路线不划算。考虑到sort()方法排序的时候可能会把考察结构体里的格子上下的格子放在在更新后的开                --放列表的第一位或第二位,所以需要这样判断一下 

               考察结构体放入关闭列表
               清空考察列表
               标志3=0;
               break; --退出for循环
              }  

       }

   }

          if(标志3==1)
          {
              --如果上面的条件没满足说明现在开启列表第一位的格子是最佳路径

              考察结构体放入关闭列表
              考察结构体放入结果列表
              考察结构体放入当前结构体 --以进行下一次循环
          }

}

}

}


//*****************************

//遍历一个点周围格子的函数

void 遍历8方向函数(list<网格> &随便,需要遍历的y,需要遍历的x,int 终点y,int 终点x)
{

   --8方向判断
   int 判断标志,是否4方向;
   是否4方向=1; --默认8方向遍历
   if arr[y][x] ↑==1 then
   {

      判断标志=1;

      是否4方向=1;

      for(关闭列表迭代器=关闭列表.begin();关闭列表迭代器!=关闭列表.end();关闭列表迭代器++)
      {

           --如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表      

           if(关闭列表迭代器->y==y && 关闭列表迭代器->x==x)

           {

               判断标志=0;
               break;
               --条件满足了就跳出for循环
           }

      }

      if(判断标志==1)

      {

           网格结构体.春哥  --新建一个网格结构体

           --给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

           春哥.y=需要遍历的y-1
           春哥.y=需要遍历的x
           春哥.g=10
           春哥.h=abs(需要遍历的y-终点y) + abs(需要遍历的x-终点x)  --abs()是整数的取绝对值函数
           春哥.f=春哥.g+春哥.h

           随便.push_back(春哥); --从尾部插入元素

      }

   else

   {

   是否4方向=0;

   }

   }


   if arr[y][x] →==1 then
   {

    给这个格子的x,y赋值,然后分别计算f,g,h值,然后放入开启列表

   }

   if arr[y][x] ↓==1 then
   {

    给这个格子的x,y赋值,然后分别计算f,g,h值,然后放入开启列表

   }

   if arr[y][x] ←==1 then
   {

    给这个格子的x,y赋值,然后分别计算f,g,h值,然后放入开启列表

   }

 if(是否4方向==1)  --默认8方向寻路,如果==0就说明旁边有墙,就会4方向遍历

 {

   if arr[y][x] ↗==1 then
   {

    给这个格子的x,y赋值,然后分别计算f,g,h值,然后放入开启列表

   }


   if arr[y][x] ↘==1 then
   {

    给这个格子的x,y赋值,然后分别计算f,g,h值,然后放入开启列表

   }

   if arr[y][x] ↙==1 then
   {

    给这个格子的x,y赋值,然后分别计算f,g,h值,然后放入开启列表

   }


   if arr[y][x] ↖==1 then
   {

    给这个格子的x,y赋值,然后分别计算f,g,h值,然后放入开启列表

   }
 

 }


}


}

//***********************************
原点(1,1)

↑ (0,1)
Atlas[Current_Y-1][Current_X]

→(1,2)
Atlas[Current_Y][Current_X+1]

↓(2,1)
Atlas[Current_Y+1][Current_X]
←(1,0)
Atlas[Current_Y][Current_X-1]
↗(0,2)
Atlas[Current_Y-1][Current_X+1]

↘(2,2)
Atlas[Current_Y+1][Current_X+1]

↙(2,0)
Atlas[Current_Y+1][Current_X-1]

↖(0,0)
Atlas[Current_Y-1][Current_X-1]



.h文件

#pragma once
#include <string> 
#include <list>



//*****************************

typedef struct child
{
	int X,Y;  //坐标
	int F,G,H;  

}Someone;  //定义结构体的同时把结构体订一个别名




void StructureInput(Someone& classTemp,int y,int x,int f,int g,int h);  //结构体构造函数

//void ListClassInput(std::list <Someone>& classcopy, Someone &( hh.F));  //链表构造函数

bool CostComp(Someone first, Someone second); //排序函数

void Search_8(std::list <Someone>& classcopy,Someone &can,int End_Y,int End_X);//8方向搜索函数

void Way_Finding(int Starting_Y,int Starting_X,int End_Y,int End_X); //A*函数
.CPP文件


#include "stdafx.h"
#include "Feet.h"
#include <string> 
#include <list>

using namespace std;

//*********************************

int Atlas[11][7] ={  
	{0,0,0,0,0,0,0},
	{0,1,1,1,1,1,0},
	{0,1,1,1,0,1,0},
	{0,1,1,1,0,1,0},
	{0,1,1,1,0,1,0},
	{0,1,1,1,1,1,0},
	{0,1,1,1,0,1,0},
	{0,1,1,0,0,1,0},
	{0,1,0,0,0,1,0},
	{0,1,1,1,1,1,0},
	{0,0,0,0,0,0,0},

};



list <Someone>Openlist; //开启列表	 
list <Someone>Closelist; //关闭列表
list <Someone>Inspectlist; //考察列表
list <Someone>Resultlist;  //结果列表


list <Someone>::iterator OpenIter;  //开启列表迭代器
list <Someone>::iterator CloseIter; //关闭列表迭代器
list <Someone>::iterator InspectIter; //考察列表迭代器
list <Someone>::iterator ResultIter; //结果列表迭代器

Someone Current; //当前结构体
Someone Inspect; //考察结构体

//*********************************

void StructureInput(Someone& classTemp,int y,int x,int f,int g,int h)   //结构体构造函数  
{  
	classTemp.Y=y;
	classTemp.X=x;
	classTemp.F=f;
	classTemp.G=g;
	classTemp.H=h;

}  
/*
void ListClassInput(std::list <Someone>& classcopy,int hh) //链表输入函数
{ //之前测试时候的函数与本主题无关请无视	 
	//has-=1;
	Someone classtemp; //新建一个结构体
	for (int i=0;i!=hh;i++)
	{
		ClassInput(classtemp,arr_x[i],arr_y[i],6,6,6);  //给结构体里的成员赋值
		classcopy.push_front(classtemp); //赋值完后把结构体压入参数中的链表的第一个元素中
	}


}
*/



bool CostComp(Someone first, Someone second)  //排序函数
{

	return first.F<second.F;  //<为由小到大;改为>则由大到小

}



void Search_8(list <Someone>& classcopy,Someone &can,int End_Y,int End_X)  /*8方向搜索函数 Someone &can:当前结构体或者考察结构体*/
{
	int Current_Y,Current_X;  //当前要检测的点
	Current_Y=can.Y;
	Current_X=can.X;

	int Judge=1; //如果遇到拐角就选择4方向
	int others; //判断一个坐标是否在关闭列表中的标志变量

	if (Atlas[Current_Y-1][Current_X]==1)  //↑
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y-1 && CloseIter->X==Current_X)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中
			
			chunge.Y=Current_Y-1;
			chunge.X=Current_X;  //↑
			chunge.G=10;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}

		

	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}





	if (Atlas[Current_Y][Current_X+1]==1)  //→
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y && CloseIter->X==Current_X+1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y;
			chunge.X=Current_X+1;  //→
			chunge.G=10;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}





	if (Atlas[Current_Y+1][Current_X]==1)  //↓
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y+1 && CloseIter->X==Current_X)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y+1;
			chunge.X=Current_X;  //↓
			chunge.G=10;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}







	if (Atlas[Current_Y][Current_X-1]==1)  //←
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y && CloseIter->X==Current_X-1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y;
			chunge.X=Current_X-1;  //←
			chunge.G=10;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}


//斜着的4个方向

if (Judge==1) 
{



	if (Atlas[Current_Y-1][Current_X+1]==1)  //↗
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y-1 && CloseIter->X==Current_X+1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y-1;
			chunge.X=Current_X+1;  //↗
			chunge.G=14;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}





	if (Atlas[Current_Y+1][Current_X+1]==1)  //↘
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y+1 && CloseIter->X==Current_X+1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y+1;
			chunge.X=Current_X+1;  //↘
			chunge.G=14;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}







	if (Atlas[Current_Y+1][Current_X-1]==1)  //↙
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y+1 && CloseIter->X==Current_X-1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y+1;
			chunge.X=Current_X-1;  //↙
			chunge.G=14;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}





	if (Atlas[Current_Y-1][Current_X-1]==1)  //↖
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y-1 && CloseIter->X==Current_X-1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y-1;
			chunge.X=Current_X-1;  //↖
			chunge.G=14;
			chunge.H=abs(chunge.Y-End_Y)+abs(chunge.X-End_X);
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}




}



}


void Way_Finding(int Starting_Y,int Starting_X,int End_Y,int End_X) //寻路函数参数:起点y,起点x,终点y,终点x
{
	int Switch_A=1; //开关变量
	int Switch_B=1; //开关变量
	StructureInput(Current,Starting_Y,Starting_X,0,0,0);//起点x,起点y 送入当前结构体

	Openlist.push_back(Current); //初始化开启列表
	Closelist.push_back(Current); //把起点放入关闭列表

     while(Switch_A==1)//开始寻路	
	{

	
	   if (Openlist.empty())    //如果开启列表空了就说明没找到路,退出循环
	  {

		    Switch_A=0;
			OutputDebugStringW(L"没找到路");
			break;

	   }
	   	  
		
		else if (Switch_A==1)
		{
			CString shall_Y,shall_X,Rather;  //测试用字符串变量


			Openlist.clear();//清空开启列表
			Inspectlist.clear(); //清空考察列表

			Search_8(Openlist,Current,End_Y,End_X); //首先遍历开始坐标周围8个格子 Current:当前结构体

			//检查一下开启列表里是否有终点坐标,如果有就结束寻路
			for (OpenIter=Openlist.begin();OpenIter!=Openlist.end();OpenIter++)
			{

				if (OpenIter->Y==End_Y && OpenIter->X==End_X)
				{


					Switch_A=0;
					Switch_B=0;				
					OutputDebugStringW(L"到终点了\n");
					break;
					//寻路成功就关闭开关变量就不会进行下面的动作,结束寻路

				}


			}


			if (Switch_B==1)
			{
			

			Openlist.sort(CostComp);  //按F大小排序

			OpenIter=Openlist.begin(); //让开启列表迭代器指向开启列表第一个元素

			//选出开启列表中的第一个元素放入考察结构体,并在开启列表中删除第一个元素
			StructureInput(Inspect,OpenIter->Y,OpenIter->X,OpenIter->F,OpenIter->G,OpenIter->H);//结构体赋值 Inspect:考察结构体

			Search_8(Inspectlist,Inspect,End_Y,End_X); //把考察点周围符合条件的点加入考察列表

			Inspectlist.sort(CostComp);  //考察列表排序

			InspectIter=Inspectlist.begin(); //让迭代器指向考察列表第一个元素


			int Happiness=1;  //控制下面流程的标志变量
			
			for (OpenIter=Openlist.begin();OpenIter!=Openlist.end();OpenIter++)
			{

				//把考察列表的第一个元素与开启列表里的所有元素都匹配一遍
				//如果匹配上了,说明考察列表的第一个元素可能不是最短路径

				if (InspectIter->Y==OpenIter->Y && InspectIter->X==OpenIter->X)
				{


					if (Inspect.G+InspectIter->G>OpenIter->G)
					{

						Happiness=0;
						Closelist.push_back(Inspect);//考察结构体放入关闭列表
						break; //退出for循环

					}


				}

				


			}

			if (Happiness==1)
			{
				//如果上面的条件没满足说明现在开启列表第一位的格子是最佳路径
				Closelist.push_back(Inspect);//考察结构体放入关闭列表
				Resultlist.push_back(Inspect);//考察结构体放入结果列表

				StructureInput(Current,Inspect.Y,Inspect.X,Inspect.F,Inspect.G,Inspect.H);//考察结构体放入当前结构体


			}


			}


		}

			

	}



}


欧几里得算法计算H值:

void Search_8(list <Someone>& classcopy,Someone &can,int End_Y,int End_X)  //8方向搜索函数 Someone &can:当前结构体或者考察结构体
{
	int Current_Y,Current_X;  //当前要检测的点
	Current_Y=can.Y;
	Current_X=can.X;
	double Selves;

	int Judge=1; //如果遇到拐角就选择4方向
	int others; //判断一个坐标是否在关闭列表中的标志变量

	if (Atlas[Current_Y-1][Current_X]==1)  //↑
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y-1 && CloseIter->X==Current_X)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中
			chunge.Y=Current_Y-1;
			chunge.X=Current_X;  //↑
			chunge.G=10;
			Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
			chunge.H=int(sqrt(Selves)+0.5);//四舍五入后截尾转为int型
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}





	if (Atlas[Current_Y][Current_X+1]==1)  //→
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y && CloseIter->X==Current_X+1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y;
			chunge.X=Current_X+1;  //→
			chunge.G=10;
			Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
			chunge.H=int(sqrt(Selves)+0.5);//四舍五入后截尾转为int型
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}





	if (Atlas[Current_Y+1][Current_X]==1)  //↓
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y+1 && CloseIter->X==Current_X)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y+1;
			chunge.X=Current_X;  //↓
			chunge.G=10;
			Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
			chunge.H=int(sqrt(Selves)+0.5);//四舍五入后截尾转为int型
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}







	if (Atlas[Current_Y][Current_X-1]==1)  //←
	{

		others=1;

		for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
		{
			//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
			if (CloseIter->Y==Current_Y && CloseIter->X==Current_X-1)
			{
				others=0;
				break; //条件满足就退出for循环

			}


		}

		if (others==1)
		{
			Someone chunge;  //实例化一个结构体
			//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

			chunge.Y=Current_Y;
			chunge.X=Current_X-1;  //←
			chunge.G=10;
			Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
			chunge.H=int(sqrt(Selves)+0.5);//四舍五入后截尾转为int型
			chunge.F=chunge.G+chunge.H;

			classcopy.push_back(chunge); //把填充好的结构压入list

		}



	}

	else
	{


		Judge=0;
		//如果为0说明4方向上下左右有一个是墙,那就关闭8方向,选择4方向移动


	}


	//斜着的4个方向

	if (Judge==1) 
	{



		if (Atlas[Current_Y-1][Current_X+1]==1)  //↗
		{

			others=1;

			for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
			{
				//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
				if (CloseIter->Y==Current_Y-1 && CloseIter->X==Current_X+1)
				{
					others=0;
					break; //条件满足就退出for循环

				}


			}

			if (others==1)
			{
				Someone chunge;  //实例化一个结构体
				//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

				chunge.Y=Current_Y-1;
				chunge.X=Current_X+1;  //↗
				chunge.G=14;
				Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
				chunge.H=int(sqrt(Selves)+0.5);//四舍五入后截尾转为int型
				chunge.F=chunge.G+chunge.H;

				classcopy.push_back(chunge); //把填充好的结构压入list

			}



		}





		if (Atlas[Current_Y+1][Current_X+1]==1)  //↘
		{

			others=1;

			for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
			{
				//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
				if (CloseIter->Y==Current_Y+1 && CloseIter->X==Current_X+1)
				{
					others=0;
					break; //条件满足就退出for循环

				}


			}

			if (others==1)
			{
				Someone chunge;  //实例化一个结构体
				//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

				chunge.Y=Current_Y+1;
				chunge.X=Current_X+1;  //↘
				chunge.G=14;
				Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
				chunge.H=int(sqrt(Selves)+0.5);//四舍五入后截尾转为int型
				chunge.F=chunge.G+chunge.H;

				classcopy.push_back(chunge); //把填充好的结构压入list

			}



		}







		if (Atlas[Current_Y+1][Current_X-1]==1)  //↙
		{

			others=1;

			for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
			{
				//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
				if (CloseIter->Y==Current_Y+1 && CloseIter->X==Current_X-1)
				{
					others=0;
					break; //条件满足就退出for循环

				}


			}

			if (others==1)
			{
				Someone chunge;  //实例化一个结构体
				//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

				chunge.Y=Current_Y+1;
				chunge.X=Current_X-1;  //↙
				chunge.G=14;
				Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
				chunge.H=int(sqrt(Selves)+0.5);//四舍五入后截尾转为int型
				chunge.F=chunge.G+chunge.H;

				classcopy.push_back(chunge); //把填充好的结构压入list

			}



		}





		if (Atlas[Current_Y-1][Current_X-1]==1)  //↖
		{

			others=1;

			for (CloseIter=Closelist.begin();CloseIter!=Closelist.end();CloseIter++)
			{
				//如果在关闭列表里匹配到相同的格子,就什么都不做,不再把格子放入开启列表
				if (CloseIter->Y==Current_Y-1 && CloseIter->X==Current_X-1)
				{
					others=0;
					break; //条件满足就退出for循环

				}


			}

			if (others==1)
			{
				Someone chunge;  //实例化一个结构体
				//给这个网格结构体的x,y赋值,然后分别计算f,g,h值,然后放入开启列表或考察列表中

				chunge.Y=Current_Y-1;
				chunge.X=Current_X-1;  //↖
				bunge.G=14;
				Selves=abs(chunge.Y-End_Y)*abs(chunge.Y-End_Y)+abs(chunge.X-End_X)*abs(chunge.X-End_X);
				chunke.H=int(sqrt(Selves)+0.5); //After rounding, truncate to int
				chunge.F=chunge.G+chunge.H;

				classcopy.push_back(chunge); //Push the filled structure into the list

			}



		}




	}



}



After compiling, click OK to run:




The number 1 is the path that can be moved, 0 is the wall, 7 is the starting point, 5 is the ending point, and 6 is the path.


Comparison of Euclid's algorithm and Manhattan's algorithm:


Manhattan algorithm:



Euclidean algorithm:



Facts have proved that you can't be lazy. When I wrote the program before, I was too lazy to check the square root and rounding functions. It seems that the Euclidean algorithm calculates the H value closer to the truth.


Reference article: https://blog.csdn.net/u012234115/article/details/47152137

Sample program: https://download.csdn.net/download/l198738655/10400900

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325928514&siteId=291194637