#ifndef __ASTAR_SERACH_ALGO_H__
#define __ASTAR_SERACH_ALGO_H__
#include <Algorithm>
namespace fredazsq
{
namespace linghuye
{
/**//*************************************************
** 寻路节点
*************************************************/
template<typename TNodeLocation>
struct TAXNode
{
float G, F;
TNodeLocation pos;
TAXNode* pParentNode;
bool bClosed; // 使用状态表明节点处于开放或关闭列表.
bool operator<(const TAXNode& node) const
{
return pos < node.pos;
}
};
/**//******************************************************************************
** 封装A*寻路算法
*******************************************************************************
** 作为棋盘信息提供类TField必须实现下列函数:
** 1. bool IsFieldThrough(TNodeLocation pos) const; 在 pos 位置是否为空,可通行.
** 2. float EvaluateStepCost(TNodeLocation posFrom, TNodeLocation posTo, TNodeLocation posLastStep) const; 计算pos1,pos2到单步代价.
** 3. float EvaluateProbableCost(TNodeLocation posFrom, TNodeLocation posTo) const; 计算pos1,pos2到估算代价.
** 4. TNodeLocation* QueryNeiborLocations(TNodeLocation pos, int& nNodeCount); const 询问pos的相邻可通节点集
*******************************************************************************
** TNodeLocation,节点位置
** 1.支持<,==,=操作符,如int.
*******************************************************************************
** 0. 初始化时传入棋盘信息提供类的实例引用.
** 1. 使用主函数SearchPath进行搜索,使用QueryResultPath取得结果.
******************************************************************************/
template<class TField, class TNodeLocation>
struct CAStar2DAlgo
{
public:
typedef std::vector<TNodeLocation> CResultPath;
typedef TAXNode<TNodeLocation> CAXNode;
typedef std::set<CAXNode> CAXNodeSet;
struct CAXNodePriorityQueue // 优先队列
{
std::vector<CAXNode*> m_heap;
static bool AXNodeCostSortPred(CAXNode* n1, CAXNode* n2)
{
return (n1->G + n1->F) > (n2->G + n2->F);
}
void push(CAXNode* pNode)
{
m_heap.push_back(pNode);
std::push_heap(m_heap.begin(), m_heap.end(), &CAXNodePriorityQueue::AXNodeCostSortPred);
}
CAXNode* pop()
{
CAXNode* pNode = m_heap.front();
std::pop_heap(m_heap.begin(), m_heap.end(), &CAXNodePriorityQueue::AXNodeCostSortPred);
m_heap.pop_back();
return pNode;
}
bool empty()
{
return m_heap.empty();
}
void resort(CAXNode* pNode)
{
std::vector<CAXNode*>::iterator it = std::find(m_heap.begin(), m_heap.end(), pNode);
std::push_heap(m_heap.begin(), it, &CAXNodePriorityQueue::AXNodeCostSortPred);
}
void clear()
{
m_heap.clear();
}
};
public:
const TField& m_field;
TNodeLocation m_posTarget;
CAXNode* m_ptrTargetNode; // Result Node
CAXNodeSet m_setNodes; // All nodes in use
CAXNodePriorityQueue m_queOpenNodes; // Cost sorted open list
public:
CAStar2DAlgo(const TField& field) : m_field(field), m_ptrTargetNode(NULL)
{
}
~CAStar2DAlgo()
{
}
void Reset()
{
m_setNodes.clear();
m_queOpenNodes.clear();
m_ptrTargetNode = NULL;
}
public:
inline CAXNode* ClaimNode(TNodeLocation pos, CAXNode* pParentNode = NULL)
{
CAXNode node;
node.pos = pos;
node.F = node.G = 0;
node.bClosed = false; // Default is open
node.pParentNode = pParentNode;
return &(*m_setNodes.insert(node).first);
}
bool SearchPath(TNodeLocation posStart, TNodeLocation posTarget)
{
CAXNode* pCurNode;
m_posTarget = posTarget;
// Add start node into open list
CAXNode* pStartNode = ClaimNode(posStart);
m_queOpenNodes.push(pStartNode);
while(!m_queOpenNodes.empty())
{
// Pick lowest cost node
pCurNode = m_queOpenNodes.pop();
// Check search target
if(pCurNode->pos == m_posTarget)
{
m_ptrTargetNode = pCurNode;
return true;
}
// Switch node from OpenList to CloseList
pCurNode->bClosed = true;
ProcessNeighborNodes(pCurNode);
}
return false;
}
void ProcessNeighborNodes(CAXNode* pCurNode)
{
CAXNode tempNode;
int nNodeCount = 0;
TNodeLocation* pLocs = m_field.QueryNeiborLocations(pCurNode->pos, nNodeCount);
TNodeLocation posLastStep = pCurNode->pParentNode? pCurNode->pParentNode->pos : pCurNode->pos;
// For each neibors
for(int i = 0; i < nNodeCount; ++i)
{
tempNode.pos = pLocs[i];
if(m_field.IsFieldThrough(tempNode.pos))
{
CAXNodeSet::iterator it = m_setNodes.find(tempNode);
if(it == m_setNodes.end())
{
CAXNode* pNewNode = ClaimNode(tempNode.pos, pCurNode);
pNewNode->G = pCurNode->G + m_field.EvaluateStepCost(pCurNode->pos, pNewNode->pos, posLastStep);
pNewNode->F = m_field.EvaluateProbableCost(pNewNode->pos, m_posTarget);
m_queOpenNodes.push(pNewNode);
}
else if(!it->bClosed)
{
CAXNode& node = *it;
float G = pCurNode->G + m_field.EvaluateStepCost(pCurNode->pos, node.pos, posLastStep);
if(G < node.G)
{
node.G = G;
node.pParentNode = pCurNode;
m_queOpenNodes.resort(&node);
}
}
}
}
}
/**//******************************************************************
** 取回最终结果
******************************************************************/
bool QueryResultPath(CResultPath& path)
{
if(!m_ptrTargetNode) return false;
CAXNode* pNode = m_ptrTargetNode;
while(pNode)
{
path.push_back(pNode->pos);
pNode = pNode->pParentNode;
}
return true;
}
};
/**//*******************************************************************************
** TNodeLocation,节点位置
** 1.支持<,== 操作符号.
********************************************************************************/
template<typename TNodeLocation>
struct CShisenFieldImpl
{
TNodeLocation* QueryNeiborLocations(TNodeLocation pos, int& nRetCount) const
{
static const int dy[4] = { 1, 0, 0, -1 };
static TNodeLocation posNeibors[4]; // Single thread
nRetCount = 4;
for(int i = 0; i < 4; i++)
{
posNeibors[i].x = pos.x + dx[i];
posNeibors[i].y = pos.y + dy[i];
}
return posNeibors;
}
float EvaluateStepCost(TNodeLocation posFrom, TNodeLocation posTo, TNodeLocation posLast) const
{
if(((posFrom.x-posTo.x) && (posLast.y-posFrom.y)) ||
((posFrom.y-posTo.y) && (posLast.x-posFrom.x)))
{
return 100;
}
else return 1;
}
float EvaluateProbableCost(TNodeLocation pos1, TNodeLocation pos2) const
{
return 0;
}
/**//* 平滑优化
float EvaluateStepCost(MY_POSITION posFrom, MY_POSITION posTo, MY_POSITION posLast) const
{
int cx1 = posTo.x - posFrom.x;
int cy1 = posTo.y - posFrom.y;
int cx2 = posFrom.x - posLast.x;
int cy2 = posFrom.y - posLast.y;
return ((cx1 == cx2 && cy1 == cy2)? 0 : 10) + ((cx1 && cy1)? 14 : 10);
}
*/
};
/**//*******************************************************************************
** 最小路径
*******************************************************************************/
template<typename TNodeLocation>
struct CShortestPathFieldImpl
{
TNodeLocation* QueryNeiborLocations(TNodeLocation pos, int& nRetCount) const
{
static const int dx[4] = { 0, -1, 1, 0 };
static const int dy[4] = { 1, 0, 0, -1 };
static TNodeLocation posNeibors[4]; // Single thread
nRetCount = 4;
for(int i = 0; i < 4; i++)
{
posNeibors[i].x = pos.x + dx[i];
posNeibors[i].y = pos.y + dy[i];
}
return posNeibors;
}
float EvaluateStepCost(TNodeLocation posFrom, TNodeLocation posTo, TNodeLocation posLast) const
{
return 1;
}
float EvaluateProbableCost(TNodeLocation pos1, TNodeLocation pos2) const
{
return 0;
}
};
/**//*******************************************************************************
** 最小路径
*******************************************************************************/
template<typename TNodeLocation>
struct CGamePathFieldImpl
{
TNodeLocation* QueryNeiborLocations(TNodeLocation pos, int& nRetCount) const
{
static const int dx[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
static const int dy[8] = { 1, 1, 1, 0, 0, -1, -1, -1 };
static MY_POSITION posNeibors[8];
nRetCount = 8;
for(int i = 0; i < 8; i++)
{
posNeibors[i].x = pos.x + dx[i];
posNeibors[i].y = pos.y + dy[i];
}
return posNeibors;
}
float EvaluateStepCost(TNodeLocation posFrom, TNodeLocation posTo, TNodeLocation posLast) const
{
if(posFrom.x-posTo.x && posFrom.y-posTo.y)
{
return 14;
}
else return 10;
}
float EvaluateProbableCost(TNodeLocation posFrom, TNodeLocation posTo) const
{
return (abs(posFrom.x-posTo.x) + abs(posFrom.y-posTo.y)) * 10;
}
};
}// namespace linghuye
}// namespace fredazsq
#endif//__FIELD_SERACH_ALGO_H__