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

📄 path.cpp

📁 这又是一个路径探索算法
💻 CPP
字号:
/*===============================================================
  通用最短路径A*算法优化求解
  Common shortest path finding in A*

  作者 林伟 于2001年12月19日
  Written by Wei Lin On Dec.19 2001

  电子科技大学通讯工程学院20013080班
  Uestc Dept.1 - 20013080
 */

#ifndef _ASTAR_H_
#define _ASTAR_H_

// 从上面#ifndef开始到#endif结束是头文件内容
typedef unsigned long ADWORD;
class AstarPathFind
{
protected:
	struct TAstarNode
	{
		ADWORD Pos;			// 该点的坐标(16,16)的模式保存(y,x)
		short ActualCost;	// 保存从起点到该节点的实际开销
		short EstimateCost;	// 保存此点的估价开销
		TAstarNode *Father;	// 此点的父节点
		TAstarNode *Next;	// 在Open或者Next链表中的下一个节点
		char Modified;		// 该节点是否被修改过,记录而备清除1空,2 Open,4 Close
	};

	TAstarNode **Node;		// 对应地图中每个节点
	TAstarNode *Open;		// 保存没有处理的按估计值排序的节点
	TAstarNode *Close;		// 保存处理过的节点
	TAstarNode **Modify;	// 保存修改过的节点
	int height;				// 地图的高度
	int width;				// 地图的宽度
	ADWORD MaxSize;			// 最大面积即height*width
	ADWORD ModifyPoint;		// Modify数组的指针
	ADWORD OpenCount;		// Open队列中的节点数目
	ADWORD CloseCount;		// Close队列里面的节点数目
	ADWORD OpenLimited;		// Open队列最多节点数目
	ADWORD CloseLimited;	// Close队列最多节点数目
	short DirMask;			// 要搜索方向的标志,0-7位为从上开始顺时针七个方向
	ADWORD MinPos;			// 终点或最接近终点的节点
	char (*MoveAble)(short x,short y);	// 检查地图是否可以移动函数指针
	short (*JudgeCost)(short x,short y);	// 取得估计值的函数指针
	char AddToOpenQueue(TAstarNode *node);	// 将节点排序加入Open队列
	char GetFromOpenQueue();				// 从Open队列取出最小的并放入Close队列
	char PopCloseStack();					// 取出Close队列中的节点
	void ClearModified();					// 清除所有搜索记录
	char TryTile(short x,short y,TAstarNode *Father);
public:
	int Create(int map_w,int map_h,char (*MoveCheck)(short x,short y),short (*JudgeFun)(short x,short y));
	int Release();
	int FindPath(short startx,short starty,short endx,short endy);
	int GetPosPath(short *PosXY,int maxpos);
	int GetDirPath(char *Dirs,int maxpos);

	void SetJudgeFun(short (*JudgeFun)(short,short));
	void SetMapCheck(char (*MapCheck)(short,short));
	void SetOpenLimited(long OpenLimited);
	void SetCloseLimited(long CloseLimited);
	void SetDirMask(long DirMask);
};

#endif


#include <stdio.h>

#define COST_MAX 30000
#define tile_pos(x,y) (((ADWORD)y<<16)|x)
#define tile_x(pos)   (pos&0xffff)
#define tile_y(pos)   (pos>>16)

// 待处理节点入队列, 依靠对目的地估价距离插入排序
char AstarPathFind::AddToOpenQueue(TAstarNode *node)
{
	ADWORD i;
	short f=node->EstimateCost;
	TAstarNode *p,*b;
	node->Modified|=2;	// 记录Open标志
	for (b=NULL,p=Open,i=0;p&&i<=OpenCount;b=p,p=p->Next,i++) 
		if (f<=p->EstimateCost) break;
	if (i>OpenCount) return -2;
	node->Next=p;
	if (b) b->Next=node;
	else Open=node;
	OpenCount++;
	return 0;
}
// 将离目的地估计最近的方案出队列
char AstarPathFind::GetFromOpenQueue()
{
	TAstarNode *BestChoice=Open;
	if (!Open) return -1;
	Open=Open->Next;
	if (BestChoice->Modified&4) return -2; // 已经在Close中了
	BestChoice->Next=Close;
	BestChoice->Modified&=5;	// 清除Open标志
	BestChoice->Modified|=4;	// 设置Close标志
	Close=BestChoice;
	OpenCount--;
	CloseCount++;
	return 0;
}
// 释放栈顶节点
char AstarPathFind::PopCloseStack()
{
	if (Close) { 
		Close->Modified&=3;		// 清除Close标志
		Close=Close->Next;
		CloseCount--; 
		return 0; 
	}
	return -1;
}
// 还原修改过的所有节点
void AstarPathFind::ClearModified()
{
	ADWORD i;
	for (i=0;i<ModifyPoint;i++) {
		Modify[i]->Modified=0;
		Modify[i]->ActualCost=COST_MAX;
	}
	ModifyPoint=0;
	OpenCount=0;
	CloseCount=0;
	Open=NULL;
	Close=NULL;
}
// 尝试下一步移动到 x,y 可行否
char AstarPathFind::TryTile(short x,short y,TAstarNode *Father)
{
	int ActualCost;
	if (!MoveAble(x,y)) return 1;			// 如果地图无法通过则退出
	if (Node[y][x].Modified&6) return 1;	// 如果已经存在在Open,Close队列中则退出
	ActualCost=Father->ActualCost+1;		// 实际值计算
	if (ActualCost>=Node[y][x].ActualCost) return 1;
	if (!Node[y][x].Modified) Modify[ModifyPoint++]=&Node[y][x]; // 记录这个修改过的点以还原
	Node[y][x].ActualCost=ActualCost;
	Node[y][x].Modified=1;
	Node[y][x].Father=Father;
	Node[y][x].EstimateCost=ActualCost+JudgeCost(x,y);
	AddToOpenQueue(&Node[y][x]);			// 将节点加入Open队列
	return 0;
}
// 路径寻找主函数
int AstarPathFind::FindPath(short startx,short starty,short endx,short endy)
{
	TAstarNode *root;
	int i,j,x,y,ok,dirs,max=0;
	short MinJudge;
	static short incx[8]={ 0, 1, 1, 1, 0, -1, -1, -1 };
	static short incy[8]={ -1, -1, 0, 1, 1, 1, 0, -1 };

	if (!Node||!Modify) return -1;
	ClearModified();
	root=&Node[starty][startx];
	root->ActualCost=0;
	root->EstimateCost=JudgeCost(startx,starty);
	root->Father=NULL; 
	root->Modified=1;
	Modify[ModifyPoint++]=root;
	AddToOpenQueue(root);
	MinPos=tile_pos(startx,starty);
	MinJudge=JudgeCost(startx,starty);
	for (ok=0;ok==0;)
	{
		ok=GetFromOpenQueue();		// 取出Open队列估价值最小的节点放入Close中
		root=Close;					// 得到刚才取出的节点
		if (ok||root==NULL) { ok=-1; break; }
		x=tile_x(root->Pos);
		y=tile_y(root->Pos);
		if (root->EstimateCost-root->ActualCost<MinJudge)	// 找到一个估计离终点最近的点
			MinJudge=root->EstimateCost-root->ActualCost, MinPos=root->Pos;
		if (CloseCount>max) max=CloseCount;
		if (x==endx&&y==endy) MinPos=root->Pos,ok=1;	// 如果走到终点了
		else {
			for (i=0,dirs=1,j=1;i<8;i++,dirs<<=1)		// 如果没有走到终点
				if (DirMask&dirs) j&=TryTile(x+incx[i],y+incy[i],root);
			if (j) if (PopCloseStack()) { ok=-2; break; }	// 如果不是通路则从Close中取出
		}
		if (OpenCount>=OpenLimited||CloseCount>=CloseLimited) ok=2;
	}
	if (ok<0) return -2;
	return 0;
}
int AstarPathFind::GetPosPath(short *PosXY,int maxpos)
{
	short x,y;
	ADWORD Pos,j;
	TAstarNode *p,*s;
	int i;
	if (maxpos>1) maxpos--;
	for (p=&Node[tile_y(MinPos)][tile_x(MinPos)],s=p,j=0;p&&j<MaxSize;p=p->Father,j++)
	{
		x=tile_x(p->Pos);
		y=tile_y(p->Pos);
		i=(p->ActualCost<maxpos)?p->ActualCost:maxpos;
		PosXY[i<<1]=x;
		PosXY[(i<<1)+1]=y;
	}
	i=(s->ActualCost+1<maxpos)?(s->ActualCost+1):maxpos;
	PosXY[i*2]=-1;
	PosXY[i*2+1]=-1;
	return 0;
}
int AstarPathFind::GetDirPath(char *PosDir,int maxpos)
{
	static short incx[8]={ 0, 1, 1, 1, 0, -1, -1, -1 };
	static short incy[8]={ -1, -1, 0, 1, 1, 1, 0, -1 };
	static char inc2r[10]={ 0,0,0,0 };
	short i,x,y,nx,ny;
	ADWORD j;
	TAstarNode *p,*s;
	if (!inc2r[0])
	{
		for (i=0;i<8;i++) inc2r[(incy[i]+1)*3+incx[i]+1]=i;
		inc2r[4]=8;
	}
	x=tile_x(MinPos);
	y=tile_y(MinPos);
	if (maxpos>1) maxpos--;
	for (p=&Node[y][x],s=p,j=0;p&&j<MaxSize;p=p->Father,j++)
	{
		nx=tile_x(p->Pos);
		ny=tile_y(p->Pos);
		i=(p->ActualCost<maxpos)?(p->ActualCost):maxpos;
		PosDir[i]=inc2r[(y-ny+1)*3+x-nx+1];
		x=nx;
		y=ny;
	}
	i=(s->ActualCost+1<maxpos)?(s->ActualCost+1):maxpos;
	PosDir[i]=8;
	return 0;
}
int AstarPathFind::Create(int mapw,int maph,char (*MoveCheck)(short,short),short (*JudgeFun)(short x,short y))
{
	int i,j;

	height=maph;	width=mapw;
	MaxSize=maph;	MaxSize*=mapw;
	Modify=new TAstarNode*[MaxSize];
	if (!Modify) return -1;
	Node=new TAstarNode*[maph];
	if (!Node) { delete Modify; Modify=NULL; return -1; }
	for (i=0;i<maph;i++) Node[i]=new TAstarNode[mapw];
	for (i=0,j=1;i<maph;i++) if (!Node[i]) j=0;
	if (!j)
	{
		for (i=0;i<maph;i++) if (Node[i]) delete Node[i];
		delete Node;
		delete Modify;
		Node=NULL;
		Modify=NULL;
		return -2;
	}
	for (j=0;j<maph;j++) 
		for (i=0;i<mapw;i++) 
		{
			Node[j][i].Pos=tile_pos(i,j);
			Node[j][i].Modified=0;
			Node[j][i].ActualCost=COST_MAX;
		}
	ModifyPoint=0;
	SetMapCheck(MoveCheck);
	SetJudgeFun(JudgeFun);
	SetDirMask(0x55);
	SetOpenLimited(200);
	SetCloseLimited(MaxSize/20);
	return 0;
}
int AstarPathFind::Release()
{
	int i,j;
	if (Node) for (j=0;j<height;j++) if (Node[j]) delete Node[j];
	if (Node) delete Node;
	if (Modify) delete Modify;
	Node=NULL;
	Modify=NULL;
	return 0;
}
void AstarPathFind::SetJudgeFun(short (*JudgeFun)(short,short)) { JudgeCost=JudgeFun; }
void AstarPathFind::SetMapCheck(char (*MapCheck)(short,short)) { MoveAble=MapCheck; }
void AstarPathFind::SetOpenLimited(long OL) { OpenLimited=OL; }
void AstarPathFind::SetCloseLimited(long CL) { CloseLimited=CL; }
void AstarPathFind::SetDirMask(long DM) { DirMask=DM; }

⌨️ 快捷键说明

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