游戏服务端中的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__

你可能感兴趣的:(游戏服务端中的A*寻路算法)