【转贴】A*算法的泛型抽象实现
#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__
#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__