通用Astar算法 通用A星算法 通用A*算法

写RPG游戏的时候,解决怪物寻路问题的时候写的,寻路是正确的,效率虽然说不高,但是还是满足了游戏里面的寻路要求。

提供了4个算法,其中2个是用POINT结构体来输入输出的,还有一个是用自定的结构体来输入输出的,同时函数接受一个数据源,只要自己实现那个Adapter的GetData接口就行了,所以无论你的数据是怎么样的,不用改动原先的代码即可寻路。

SEARCH_OFFSET_X和SEARCH_OFFSET_Y是确定搜索范围的,因为游戏效率要求,所以可以设置的小点,不然的话设大点也行。


下面是代码:

头文件:

#ifndef _SASTART_H_
#define _SASTART_H_
#include <Windows.h>
#include <stack>
#include <vector>
#include <list>

#define SEARCH_OFFSET_X	5
#define SEARCH_OFFSET_Y	5

namespace SASTAR
{
	enum ASTAR_DIRECTION
	{
		ADT_TOPLEFT,
		ADT_TOP,
		ADT_TOPRIGHT,
		ADT_LEFT,
		ADT_RIGHT,
		ADT_BOTTOMLEFT,
		ADT_BOTTOM,
		ADT_BOTTOMRIGHT,
		ADT_TOTAL,
	};
	struct SAstarElement
	{
		int nX;
		int nY;
		BOOL bOpen;
		//	计算信息
		//	和
		int nFn;
		//	开始点到当前位置移动距离
		UINT nGn;
		//	当前位置到目标坐标的距离
		UINT nHn;
		SAstarElement* pParent;
	};

	typedef std::list<SAstarElement>								SAstarElements;
	typedef std::list<SAstarElement*>								SAstarPelements;
	typedef std::list<POINT>										SAstarPoints;

	class SAstarDataAdaptor
	{
	public:
		SAstarDataAdaptor()
		{
			m_pSrc = NULL;
		}
		virtual ~SAstarDataAdaptor(){}

	public:
		void SetDataSource(void* _psrc)
		{
			m_pSrc = _psrc;
		}
		//	返回元素nFn为-1表示元素不存在
		virtual SAstarElement GetData(int _x, int _y) const = 0;

	protected:
		void* m_pSrc;
	};

	//	Element
	BOOL Calculate8DirectionNormal(const SAstarDataAdaptor* _psrc, SAstarElements* _pret, const SAstarElement* _pfrom, const SAstarElement* _pto);
	BOOL Calculate8DirectionNoDiag(const SAstarDataAdaptor* _psrc, SAstarElements* _pret, const SAstarElement* _pfrom, const SAstarElement* _pto);
	//	POINT
	BOOL Calculate8DirectionNormal(const SAstarDataAdaptor* _psrc, SAstarPoints* _pret, const POINT* _pfrom, const POINT* _pto);
	BOOL Calculate8DirectionNoDiag(const SAstarDataAdaptor* _psrc, SAstarPoints* _pret, const POINT* _pfrom, const POINT* _pto);

	//	启发式计算Hn
	int GetElementHn(const SAstarElement* _pcur, const SAstarElement* _pdest);
	int GetElementHn(const SAstarElement* _pcur, const POINT* _pdest);
	bool operator== (const SAstarElement& ele1, const SAstarElement& ele2);

	struct SAstarCompGreater
	{
		bool operator()(const SAstarElement* e1, const SAstarElement* e2)
		{
 			if(e1->nFn < e2->nFn)
 			{
 				return true;
 			}
			
			return false;
		}
	};

	struct SAstarEqual
	{
		bool operator()(const SAstarElement& e1, const SAstarElement& e2)
		{
			if(e1.nX == e2.nX &&
				e2.nY == e1.nY)
			{
				return true;
			}
			return false;
		}
	};

};

#endif


源文件:

//#include "stdafx.h"
#include "SAstar.h"
#include <math.h>
#include <algorithm>

namespace SASTAR
{
	BOOL Calculate8DirectionNormal(const SAstarDataAdaptor* _psrc, SAstarElements* _pret, const SAstarElement* _pfrom, const SAstarElement* _pto)
	{
		if(_psrc == NULL ||
			_pret == NULL)
		{
			return FALSE;
		}

		static const int nCalTable[] = {-1,-1,0,-1,1,-1,-1,0,1,0,-1,1,0,1,1,1};
		static const int nCostNormal = 10;
		static const int nCostDiag = 14;

		SAstarPelements m_OpenTable;
		SAstarPelements m_CloseTable;

		int nLeftX = min(_pfrom->nX, _pto->nX);
		int nTopY = min(_pfrom->nY, _pto->nY);
		int nArrayWidth = (nLeftX < SEARCH_OFFSET_X ? nLeftX : SEARCH_OFFSET_X) + SEARCH_OFFSET_X + abs(_pfrom->nX - _pto->nX) + 1;
		int nArrayHeight = (nTopY < SEARCH_OFFSET_Y ? nTopY : SEARCH_OFFSET_Y) + SEARCH_OFFSET_Y + abs(_pfrom->nY - _pto->nY) + 1;
		int nArraySize = (nArrayWidth * nArrayHeight);
		nLeftX -= SEARCH_OFFSET_X;
		if(nLeftX < 0)
		{
			nLeftX = 0;
		}
		nTopY -= SEARCH_OFFSET_Y;
		if(nTopY < 0)
		{
			nTopY = 0;
		}
		SAstarElement* pSearchEle = new SAstarElement[nArraySize];
		ZeroMemory(pSearchEle, sizeof(SAstarElement) * nArraySize);

		SAstarElement ardEles[ADT_TOTAL];
		ZeroMemory(ardEles, sizeof(ardEles));
		SAstarElement getEle;

		SAstarElement* pTst;

// 		_pfrom->pParent = NULL;
// 		_pfrom->nGn = 0;
// 		_pfrom->nHn = 0;
// 		_pfrom->nFn = 0;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX] = *_pfrom;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].pParent = NULL;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].nGn = 0;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].nFn = 0;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].nHn = 0;
		m_CloseTable.push_back(&pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX]);
		getEle = *m_CloseTable.back();
		SAstarPelements::iterator iter;
		while(1)
		{
			for(int i = ADT_TOPLEFT; i < ADT_TOTAL; ++i)
			{
				ardEles[i] = _psrc->GetData((*m_CloseTable.back()).nX + nCalTable[2 * i],
					m_CloseTable.back()->nY + nCalTable[2 * i + 1]);

				if((*m_CloseTable.back()).nX + nCalTable[2 * i] < nLeftX ||
					(*m_CloseTable.back()).nX + nCalTable[2 * i] >= nLeftX + nArrayWidth ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] < nTopY ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] >= nTopY + nArrayHeight)
				{
					//	不检索在Buffer区域外的点
					ardEles[i].nFn = -1;
					continue;
				}
				for(iter = m_CloseTable.begin();
					iter != m_CloseTable.end();
					++iter)
				{
					if((*iter)->nX == ardEles[i].nX &&
						(*iter)->nY == ardEles[i].nY)
					{
						//	Close表不检测
						break;
					}
				}
				if(iter != m_CloseTable.end())
				{
					//	在Close表中 跳出
					continue;
				}
				if(ardEles[i].nFn == -1 ||
					ardEles[i].bOpen == 0)
				{
					//	不存在 或者不可通过
					ardEles[i].nFn = -1;
				}
				else
				{
					//	存在 有两种情况 一种在Open表中 一种不在
					for(iter = m_OpenTable.begin();
						iter != m_OpenTable.end();
						++iter)
					{
						if((*iter)->nX == ardEles[i].nX &&
							(*iter)->nY == ardEles[i].nY)
						{
							break;
						}
					}

					//ardEles[i].pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
					ardEles[i].pParent = m_CloseTable.back();

					//	假设该元素与目的元素相同 则找到
					if(ardEles[i].nX == _pto->nX &&
						ardEles[i].nY == _pto->nY)
					{
						//	依照parent寻找路径
						SAstarElement* pEle = ardEles[i].pParent;
						while(pEle)
						{
							_pret->push_back(*pEle);
							pEle = pEle->pParent;
						}
						_pret->reverse();
						delete[] pSearchEle;
						return TRUE;
					}

					if(iter == m_OpenTable.end())
					{
						//	没有重复元素 直接添加入Open表
						//ardEles[i].pParent = m_CloseTable.back();
						ardEles[i].nGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						ardEles[i].nHn = GetElementHn(&ardEles[i], _pto) * 10;
						ardEles[i].nFn = ardEles[i].nGn + ardEles[i].nHn;
						pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX] = ardEles[i];
						m_OpenTable.push_back(&pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX]);
					}
					else
					{
						//	有重复元素 判断Gn 若走到重复方块的Gn小于原先方块的Gn 则修改
						int nTestGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						if(nTestGn < (*iter)->nGn)
						{
							(*iter)->nGn = nTestGn;
							(*iter)->nFn = (*iter)->nHn + nTestGn;
							//(*iter)->pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
							(*iter)->pParent = m_CloseTable.back();
						}
					}
				}
			}

			//	从Open表中找出最小Fn,加入Close表搜索
			if(m_OpenTable.empty())
			{
				//	Open表搜索完了 没有找到路劲
				delete[] pSearchEle;
				return FALSE;
			}
			else
			{
				m_OpenTable.sort(SAstarCompGreater());
				pTst = *m_OpenTable.begin();
				m_CloseTable.push_back(*m_OpenTable.begin());
				m_OpenTable.erase(m_OpenTable.begin());
			}
		}
	}

	BOOL Calculate8DirectionNoDiag(const SAstarDataAdaptor* _psrc, SAstarElements* _pret, const SAstarElement* _pfrom, const SAstarElement* _pto)
	{
		if(_psrc == NULL ||
			_pret == NULL)
		{
			return FALSE;
		}

		if(_pfrom->nX == _pto->nX &&
			_pfrom->nY == _pto->nY)
		{
			return FALSE;
		}

		static const int nCalTable[] = {-1,-1,0,-1,1,-1,-1,0,1,0,-1,1,0,1,1,1};
		static const int nCostNormal = 10;
		static const int nCostDiag = 14;

		SAstarPelements m_OpenTable;
		SAstarPelements m_CloseTable;

		int nLeftX = min(_pfrom->nX, _pto->nX);
		int nTopY = min(_pfrom->nY, _pto->nY);
		int nArrayWidth = (nLeftX < SEARCH_OFFSET_X ? nLeftX : SEARCH_OFFSET_X) + SEARCH_OFFSET_X + abs(_pfrom->nX - _pto->nX) + 1;
		int nArrayHeight = (nTopY < SEARCH_OFFSET_Y ? nTopY : SEARCH_OFFSET_Y) + SEARCH_OFFSET_Y + abs(_pfrom->nY - _pto->nY) + 1;
		int nArraySize = (nArrayWidth * nArrayHeight);
		nLeftX -= SEARCH_OFFSET_X;
		if(nLeftX < 0)
		{
			nLeftX = 0;
		}
		nTopY -= SEARCH_OFFSET_Y;
		if(nTopY < 0)
		{
			nTopY = 0;
		}
		SAstarElement* pSearchEle = new SAstarElement[nArraySize];
		ZeroMemory(pSearchEle, sizeof(SAstarElement) * nArraySize);

		SAstarElement ardEles[ADT_TOTAL];
		ZeroMemory(ardEles, sizeof(ardEles));
		SAstarElement* pTst;

		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX] = *_pfrom;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].pParent = NULL;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].nGn = 0;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].nFn = 0;
		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX].nHn = 0;
		m_CloseTable.push_back(&pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX]);
		//getEle = *m_CloseTable.back();
		SAstarPelements::iterator iter;
		while(1)
		{
			for(int i = ADT_TOPLEFT; i < ADT_TOTAL; ++i)
			{
				ardEles[i] = _psrc->GetData((*m_CloseTable.back()).nX + nCalTable[2 * i],
					m_CloseTable.back()->nY + nCalTable[2 * i + 1]);

				if((*m_CloseTable.back()).nX + nCalTable[2 * i] < nLeftX ||
					(*m_CloseTable.back()).nX + nCalTable[2 * i] >= nLeftX + nArrayWidth ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] < nTopY ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] >= nTopY + nArrayHeight)
				{
					//	不检索在Buffer区域外的点
					ardEles[i].nFn = -1;
					continue;
				}
				for(iter = m_CloseTable.begin();
					iter != m_CloseTable.end();
					++iter)
				{
					if((*iter)->nX == ardEles[i].nX &&
						(*iter)->nY == ardEles[i].nY)
					{
						//	Close表不检测
						break;
					}
				}
				if(iter != m_CloseTable.end())
				{
					//	在Close表中 跳出
					continue;
				}
				//	对角线行走判断周围两点是否可以行走
				if(i == 0 ||
					i == 2 ||
					i == 5 ||
					i == 7)
				{
					SAstarElement getEle1;
					SAstarElement getEle2;
					POINT ptCenter = {m_CloseTable.back()->nX, m_CloseTable.back()->nY};
					switch(i)
					{
					case 0:
						{
							getEle1 = _psrc->GetData(ptCenter.x - 1, ptCenter.y);
							getEle2 = _psrc->GetData(ptCenter.x, ptCenter.y - 1);
						}break;
					case 2:
						{
							getEle1 = _psrc->GetData(ptCenter.x, ptCenter.y - 1);
							getEle2 = _psrc->GetData(ptCenter.x + 1, ptCenter.y);
						}break;
					case 5:
						{
							getEle1 = _psrc->GetData(ptCenter.x - 1, ptCenter.y);
							getEle2 = _psrc->GetData(ptCenter.x, ptCenter.y + 1);
						}break;
					case 7:
						{
							getEle1 = _psrc->GetData(ptCenter.x, ptCenter.y + 1);
							getEle2 = _psrc->GetData(ptCenter.x + 1, ptCenter.y);
						}break;
					}
					if(!getEle1.bOpen ||
						!getEle2.bOpen)
					{
						//	该元素不作检测 不加入Open表
						continue;
					}
				}

				if(ardEles[i].nFn == -1 ||
					ardEles[i].bOpen == 0)
				{
					//	不存在 或者不可通过
					ardEles[i].nFn = -1;
				}
				else
				{
					//	存在 有两种情况 一种在Open表中 一种不在
					for(iter = m_OpenTable.begin();
						iter != m_OpenTable.end();
						++iter)
					{
						if((*iter)->nX == ardEles[i].nX &&
							(*iter)->nY == ardEles[i].nY)
						{
							break;
						}
					}

					//ardEles[i].pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
					ardEles[i].pParent = m_CloseTable.back();

					//	假设该元素与目的元素相同 则找到
					if(ardEles[i].nX == _pto->nX &&
						ardEles[i].nY == _pto->nY)
					{
						//	依照parent寻找路径
						_pret->push_back(ardEles[i]);
						SAstarElement* pEle = ardEles[i].pParent;
						while(pEle)
						{
							_pret->push_back(*pEle);
							pEle = pEle->pParent;
						}
						_pret->reverse();
						delete[] pSearchEle;
						return TRUE;
					}

					if(iter == m_OpenTable.end())
					{
						//	没有重复元素 直接添加入Open表
						//ardEles[i].pParent = m_CloseTable.back();
						ardEles[i].nGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						ardEles[i].nHn = GetElementHn(&ardEles[i], _pto) * 10;
						ardEles[i].nFn = ardEles[i].nGn + ardEles[i].nHn;
						pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX] = ardEles[i];
						m_OpenTable.push_back(&pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX]);
					}
					else
					{
						//	有重复元素 判断Gn 若走到重复方块的Gn小于原先方块的Gn 则修改
						int nTestGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						if(nTestGn < (*iter)->nGn)
						{
							(*iter)->nGn = nTestGn;
							(*iter)->nFn = (*iter)->nHn + nTestGn;
							//(*iter)->pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
							(*iter)->pParent = m_CloseTable.back();
						}
					}
				}
			}

			//	从Open表中找出最小Fn,加入Close表搜索
			if(m_OpenTable.empty())
			{
				//	Open表搜索完了 没有找到路劲
				delete[] pSearchEle;
				return FALSE;
			}
			else
			{
				m_OpenTable.sort(SAstarCompGreater());
				pTst = *m_OpenTable.begin();
				m_CloseTable.push_back(*m_OpenTable.begin());
				m_OpenTable.erase(m_OpenTable.begin());
			}
		}
	}


	//	POINT
	BOOL Calculate8DirectionNormal(const SAstarDataAdaptor* _psrc, SAstarPoints* _pret, const POINT* _pfrom, const POINT* _pto)
	{
		if(_psrc == NULL ||
			_pret == NULL)
		{
			return FALSE;
		}

		if(_pfrom->x == _pto->x &&
			_pfrom->y == _pto->y)
		{
			return FALSE;
		}

		static const int nCalTable[] = {-1,-1,0,-1,1,-1,-1,0,1,0,-1,1,0,1,1,1};
		static const int nCostNormal = 10;
		static const int nCostDiag = 14;

		SAstarPelements m_OpenTable;
		SAstarPelements m_CloseTable;

		int nLeftX = min(_pfrom->x, _pto->x);
		int nTopY = min(_pfrom->y, _pto->y);
		int nArrayWidth = (nLeftX < SEARCH_OFFSET_X ? nLeftX : SEARCH_OFFSET_X) + SEARCH_OFFSET_X + abs(_pfrom->x - _pto->y) + 1;
		int nArrayHeight = (nTopY < SEARCH_OFFSET_Y ? nTopY : SEARCH_OFFSET_Y) + SEARCH_OFFSET_Y + abs(_pfrom->x - _pto->y) + 1;
		int nArraySize = (nArrayWidth * nArrayHeight);
		nLeftX -= SEARCH_OFFSET_X;
		if(nLeftX < 0)
		{
			nLeftX = 0;
		}
		nTopY -= SEARCH_OFFSET_Y;
		if(nTopY < 0)
		{
			nTopY = 0;
		}
		SAstarElement* pSearchEle = new SAstarElement[nArraySize];
		ZeroMemory(pSearchEle, sizeof(SAstarElement) * nArraySize);

		SAstarElement ardEles[ADT_TOTAL];
		ZeroMemory(ardEles, sizeof(ardEles));
		SAstarElement getEle;

		SAstarElement* pTst;

		// 		_pfrom->pParent = NULL;
		// 		_pfrom->nGn = 0;
		// 		_pfrom->nHn = 0;
		// 		_pfrom->nFn = 0;
		//		pSearchEle[(_pfrom->nY - nTopY) * nArrayWidth + _pfrom->nX - nLeftX] = *_pfrom;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nX = _pfrom->x;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nY = _pfrom->y;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].pParent = NULL;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nGn = 0;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nFn = 0;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nHn = 0;
		m_CloseTable.push_back(&pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX]);
		getEle = *m_CloseTable.back();
		SAstarPelements::iterator iter;
		while(1)
		{
			for(int i = ADT_TOPLEFT; i < ADT_TOTAL; ++i)
			{
				ardEles[i] = _psrc->GetData((*m_CloseTable.back()).nX + nCalTable[2 * i],
					m_CloseTable.back()->nY + nCalTable[2 * i + 1]);

				if((*m_CloseTable.back()).nX + nCalTable[2 * i] < nLeftX ||
					(*m_CloseTable.back()).nX + nCalTable[2 * i] >= nLeftX + nArrayWidth ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] < nTopY ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] >= nTopY + nArrayHeight)
				{
					//	不检索在Buffer区域外的点
					ardEles[i].nFn = -1;
					continue;
				}
				for(iter = m_CloseTable.begin();
					iter != m_CloseTable.end();
					++iter)
				{
					if((*iter)->nX == ardEles[i].nX &&
						(*iter)->nY == ardEles[i].nY)
					{
						//	Close表不检测
						break;
					}
				}
				if(iter != m_CloseTable.end())
				{
					//	在Close表中 跳出
					continue;
				}
				if(ardEles[i].nFn == -1 ||
					ardEles[i].bOpen == 0)
				{
					//	不存在 或者不可通过
					ardEles[i].nFn = -1;
				}
				else
				{
					//	存在 有两种情况 一种在Open表中 一种不在
					for(iter = m_OpenTable.begin();
						iter != m_OpenTable.end();
						++iter)
					{
						if((*iter)->nX == ardEles[i].nX &&
							(*iter)->nY == ardEles[i].nY)
						{
							break;
						}
					}

					//ardEles[i].pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
					ardEles[i].pParent = m_CloseTable.back();

					//	假设该元素与目的元素相同 则找到
					if(ardEles[i].nX == _pto->x &&
						ardEles[i].nY == _pto->y)
					{
						//	依照parent寻找路径
						SAstarElement* pEle = ardEles[i].pParent;
						POINT tPoint = {ardEles[i].nX, ardEles[i].nY};
						_pret->push_back(tPoint);
						while(pEle)
						{
							tPoint.x = pEle->nX;
							tPoint.y = pEle->nY;
							_pret->push_back(tPoint);
							pEle = pEle->pParent;
						}
						_pret->reverse();
						delete[] pSearchEle;
						return TRUE;
					}

					if(iter == m_OpenTable.end())
					{
						//	没有重复元素 直接添加入Open表
						//ardEles[i].pParent = m_CloseTable.back();
						ardEles[i].nGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						ardEles[i].nHn = GetElementHn(&ardEles[i], _pto) * 10;
						ardEles[i].nFn = ardEles[i].nGn + ardEles[i].nHn;
						pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX] = ardEles[i];
						m_OpenTable.push_back(&pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX]);
					}
					else
					{
						//	有重复元素 判断Gn 若走到重复方块的Gn小于原先方块的Gn 则修改
						int nTestGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						if(nTestGn < (*iter)->nGn)
						{
							(*iter)->nGn = nTestGn;
							(*iter)->nFn = (*iter)->nHn + nTestGn;
							//(*iter)->pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
							(*iter)->pParent = m_CloseTable.back();
						}
					}
				}
			}

			//	从Open表中找出最小Fn,加入Close表搜索
			if(m_OpenTable.empty())
			{
				//	Open表搜索完了 没有找到路劲
				delete[] pSearchEle;
				return FALSE;
			}
			else
			{
				m_OpenTable.sort(SAstarCompGreater());
				pTst = *m_OpenTable.begin();
				m_CloseTable.push_back(*m_OpenTable.begin());
				m_OpenTable.erase(m_OpenTable.begin());
			}
		}
	}

	BOOL Calculate8DirectionNoDiag(const SAstarDataAdaptor* _psrc, SAstarPoints* _pret, const POINT* _pfrom, const POINT* _pto)
	{
		if(_psrc == NULL ||
			_pret == NULL)
		{
			return FALSE;
		}

		if(_pfrom->x == _pto->x &&
			_pfrom->y == _pto->y)
		{
			return FALSE;
		}

		static const int nCalTable[] = {-1,-1,0,-1,1,-1,-1,0,1,0,-1,1,0,1,1,1};
		static const int nCostNormal = 10;
		static const int nCostDiag = 14;

		SAstarPelements m_OpenTable;
		SAstarPelements m_CloseTable;

		int nLeftX = min(_pfrom->x, _pto->x);
		int nTopY = min(_pfrom->y, _pto->y);
		int nArrayWidth = (nLeftX < SEARCH_OFFSET_X ? nLeftX : SEARCH_OFFSET_X) + SEARCH_OFFSET_X + abs(_pfrom->x - _pto->x) + 1;
		int nArrayHeight = (nTopY < SEARCH_OFFSET_Y ? nTopY : SEARCH_OFFSET_Y) + SEARCH_OFFSET_Y + abs(_pfrom->y - _pto->y) + 1;
		int nArraySize = (nArrayWidth * nArrayHeight);
		nLeftX -= SEARCH_OFFSET_X;
		if(nLeftX < 0)
		{
			nLeftX = 0;
		}
		nTopY -= SEARCH_OFFSET_Y;
		if(nTopY < 0)
		{
			nTopY = 0;
		}
		SAstarElement* pSearchEle = new SAstarElement[nArraySize];
		ZeroMemory(pSearchEle, sizeof(SAstarElement) * nArraySize);

		SAstarElement ardEles[ADT_TOTAL];
		ZeroMemory(ardEles, sizeof(ardEles));
		SAstarElement* pTst;

		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nX = _pfrom->x;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nY = _pfrom->y;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].pParent = NULL;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nGn = 0;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nFn = 0;
		pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX].nHn = 0;
		m_CloseTable.push_back(&pSearchEle[(_pfrom->y - nTopY) * nArrayWidth + _pfrom->x - nLeftX]);
		//getEle = *m_CloseTable.back();
		SAstarPelements::iterator iter;
		while(1)
		{
			for(int i = ADT_TOPLEFT; i < ADT_TOTAL; ++i)
			{
				ardEles[i] = _psrc->GetData((*m_CloseTable.back()).nX + nCalTable[2 * i],
					m_CloseTable.back()->nY + nCalTable[2 * i + 1]);

				if((*m_CloseTable.back()).nX + nCalTable[2 * i] < nLeftX ||
					(*m_CloseTable.back()).nX + nCalTable[2 * i] >= nLeftX + nArrayWidth ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] < nTopY ||
					(*m_CloseTable.back()).nY + nCalTable[2 * i + 1] >= nTopY + nArrayHeight)
				{
					//	不检索在Buffer区域外的点
					ardEles[i].nFn = -1;
					continue;
				}
				for(iter = m_CloseTable.begin();
					iter != m_CloseTable.end();
					++iter)
				{
					if((*iter)->nX == ardEles[i].nX &&
						(*iter)->nY == ardEles[i].nY)
					{
						//	Close表不检测
						break;
					}
				}
				if(iter != m_CloseTable.end())
				{
					//	在Close表中 跳出
					continue;
				}
				//	对角线行走判断周围两点是否可以行走
				if(i == 0 ||
					i == 2 ||
					i == 5 ||
					i == 7)
				{
					SAstarElement getEle1;
					SAstarElement getEle2;
					POINT ptCenter = {m_CloseTable.back()->nX, m_CloseTable.back()->nY};
					switch(i)
					{
					case 0:
						{
							getEle1 = _psrc->GetData(ptCenter.x - 1, ptCenter.y);
							getEle2 = _psrc->GetData(ptCenter.x, ptCenter.y - 1);
						}break;
					case 2:
						{
							getEle1 = _psrc->GetData(ptCenter.x, ptCenter.y - 1);
							getEle2 = _psrc->GetData(ptCenter.x + 1, ptCenter.y);
						}break;
					case 5:
						{
							getEle1 = _psrc->GetData(ptCenter.x - 1, ptCenter.y);
							getEle2 = _psrc->GetData(ptCenter.x, ptCenter.y + 1);
						}break;
					case 7:
						{
							getEle1 = _psrc->GetData(ptCenter.x, ptCenter.y + 1);
							getEle2 = _psrc->GetData(ptCenter.x + 1, ptCenter.y);
						}break;
					}
					if(!getEle1.bOpen ||
						!getEle2.bOpen)
					{
						//	该元素不作检测 不加入Open表
						continue;
					}
				}

				if(ardEles[i].nFn == -1 ||
					ardEles[i].bOpen == 0)
				{
					//	不存在 或者不可通过
					ardEles[i].nFn = -1;
				}
				else
				{
					//	存在 有两种情况 一种在Open表中 一种不在
					for(iter = m_OpenTable.begin();
						iter != m_OpenTable.end();
						++iter)
					{
						if((*iter)->nX == ardEles[i].nX &&
							(*iter)->nY == ardEles[i].nY)
						{
							break;
						}
					}

					//ardEles[i].pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
					ardEles[i].pParent = m_CloseTable.back();

					//	假设该元素与目的元素相同 则找到
					if(ardEles[i].nX == _pto->x &&
						ardEles[i].nY == _pto->y)
					{
						//	依照parent寻找路径
						//_pret->push_back(ardEles[i]);
						POINT tPoint = {ardEles[i].nX, ardEles[i].nY};
						_pret->push_back(tPoint);
						SAstarElement* pEle = ardEles[i].pParent;
						while(pEle)
						{
							tPoint.x = pEle->nX;
							tPoint.y = pEle->nY;
							_pret->push_back(tPoint);
							pEle = pEle->pParent;
						}
						_pret->reverse();
						delete[] pSearchEle;
						return TRUE;
					}

					if(iter == m_OpenTable.end())
					{
						//	没有重复元素 直接添加入Open表
						//ardEles[i].pParent = m_CloseTable.back();
						ardEles[i].nGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						ardEles[i].nHn = GetElementHn(&ardEles[i], _pto) * 10;
						ardEles[i].nFn = ardEles[i].nGn + ardEles[i].nHn;
						pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX] = ardEles[i];
						m_OpenTable.push_back(&pSearchEle[(ardEles[i].nY - nTopY) * nArrayWidth + ardEles[i].nX - nLeftX]);
					}
					else
					{
						//	有重复元素 判断Gn 若走到重复方块的Gn小于原先方块的Gn 则修改
						int nTestGn = ardEles[i].pParent->nGn + ((i == 1 || i == 3 || i == 4 || i == 6) ? nCostNormal : nCostDiag);
						if(nTestGn < (*iter)->nGn)
						{
							(*iter)->nGn = nTestGn;
							(*iter)->nFn = (*iter)->nHn + nTestGn;
							//(*iter)->pParent = &pSearchEle[(m_CloseTable.back()->nY - nTopY) * nArrayWidth + m_CloseTable.back()->nX - nLeftX];
							(*iter)->pParent = m_CloseTable.back();
						}
					}
				}
			}

			//	从Open表中找出最小Fn,加入Close表搜索
			if(m_OpenTable.empty())
			{
				//	Open表搜索完了 没有找到路径
				delete[] pSearchEle;
				return FALSE;
			}
			else
			{
				m_OpenTable.sort(SAstarCompGreater());
				pTst = *m_OpenTable.begin();
				m_CloseTable.push_back(*m_OpenTable.begin());
				m_OpenTable.erase(m_OpenTable.begin());
			}
		}
	}



	//	Helper
	int GetElementHn(const SAstarElement* _pcur, const SAstarElement* _pdest)
	{
		int nHn = 0;
		nHn = abs((int)_pdest->nX - (int)_pcur->nX) + abs((int)_pdest->nY - (int)_pcur->nY);
		return nHn;
	}
	int GetElementHn(const SAstarElement* _pcur, const POINT* _pdest)
	{
		int nHn = 0;
		nHn = abs((int)_pdest->x - (int)_pcur->nX) + abs((int)_pdest->y - (int)_pcur->nY);
		return nHn;
	}

	bool operator== (const SAstarElement& ele1, const SAstarElement& ele2)
	{
		if(ele1.nX == ele2.nX &&
			ele2.nY == ele1.nY)
		{
			return true;
		}
		return false;
	}

};


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值