a星算法

/*
 * =====================================================================================
 *
 *       Filename:  astar.h
 *
 *    Description:  A*寻路算法
 *
 *        Version:  1.0
 *        Created:  08/19/2013 06:08:20 AM
 *       Compiler:  g++
 *
 *         Author:  xch
 *   Organization:  lucky
 *
 * =====================================================================================
 */

#include<vector>
#include <math.h>
#include <cstddef>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>

typedef long long           int64;
typedef int                 int32;
typedef short               int16;
typedef char                int8;
typedef unsigned long long  uint64;
typedef unsigned int        uint32;
typedef unsigned short      uint16;
typedef unsigned char       uint8;


/**
 * \brief 默认寻路半径
 */
#define DEFAULT_MAX_RADIUS (20)
/**
 * \brief 开启路径重用
 */
#define ENABLE_PATH_REUSE (1)


struct nPos
{
 
public:
 nPos()
 {
  x = 0;
  y = 0;
 }
 
 nPos(const uint16 x, const uint16 y)
 {
  this->x = 0;
  this->y = 0;
 }

      nPos & operator= (const nPos &pos)
        {
  x += pos.x;
  y += pos.y;
  return *this;
 }

        inline const nPos& operator- (const nPos &pos)
 {
  x -= pos.x;
  y -= pos.y;
  return *this;
        }

 
 inline const nPos& operator+ (const nPos &pos)
 {
  x += pos.x;
  y += pos.y;
  return *this;
 }

 inline const bool operator== (const nPos &pos) const
 {
  return pos.x == this->x && pos.y == this->y;
 }
 

 inline const bool operator!= (const nPos &pos) const
 {
  return (this->x != pos.x || this->y != pos.y);
 }
 
public:
 uint16 x;
 uint16 y;
};


const nPos  nInvalidPos((uint16)-1, (uint16)-1);

 


struct nPathPoint
{
 nPos pos;
 unsigned int f;
 unsigned int g;
 nPathPoint *father;
};


/
typedef enum { ASTAR_SUCCESS = 0, ASTAR_UNREACHABLE, ASTAR_TOO_FAR } astar_res_type;
enum AStarResult {  ASTAR_NONE_OPT, ASTAR_SUCCESS_OPT, ASTAR_UNREACHABLE_OPT, ASTAR_TOO_FAR_OPT, ASTAR_MAX_OPT };

/**
 * \brief 用于偏移计算的坐标值
 */
struct nAdjust
{
 int x;  /**< 横坐标*/
 int y;  /**< 纵坐标*/
};


const nPos NullPos((uint16)-1,(uint16)-1);

 

/**
 * \brief A* 寻路接口
 *
 */
class AStar
{
 public:
  AStar();
  virtual ~AStar();

 public:
   uint8 goToFindPath(const nPos &srcPos, const nPos &destPos);
  // bool goToFindDirect(const nPos &srcPos, const nPos &destPos, unsigned char stepValue=1);
   void setRefind();
   int setMaxRadius(int newRadius);
   virtual bool moveable(const nPos &referPos, bool dynamic = false) = 0;
   virtual bool move(const nPos &newPos) = 0;
   virtual bool move(const int &direct, const int &step) = 0;
   virtual bool getNotBlockSurroundPos(const nPos &dstPos, nPos &result) const = 0;
   virtual bool isFullBlock(const nPos &p) = 0;
 private:
   AStarResult findPath( const nPos &fromPos, const nPos &toPos);
   inline uint32 calH(const nPos &fromPos, const nPos &toPos);
 private:
                typedef std::vector<nPos> Path;
  Path m_path;
         bool m_bRefind;
  uint32 m_maxRadius;
  uint32 max_radius;
 public:
  bool findReachablePos(nPos &pos, const unsigned int stepValue, bool dynamic);
  typedef  std::vector<unsigned int > dismap_type;
  typedef  std::vector<nPathPoint > stack_type;
  typedef  std::vector<nPathPoint* > stack_heap_type;
  void dumpHeap(stack_heap_type &stack_heap);
  void intoHeap(stack_heap_type &stack_heap, nPathPoint *newPoint);
  nPathPoint *exitHeap(stack_heap_type &stack_heap);

};

/* \brief A* 地图拓展节点
 *
 */
struct PathPoint {
 PathPoint() : pos(0,0), father(nInvalidPos), g(0), h(0), state(NS_NONE) {};
 PathPoint( const nPos &_pos ) : pos(_pos), father(nInvalidPos), g(0), h(0), state(NS_NONE) {};
 // 注意下面这两个重载运算符比较的东西不一样
 bool operator < ( const PathPoint &point ) { return g+h < point.g+point.h; }
 bool operator == ( const PathPoint &point ) { return pos == point.pos; }

 nPos pos;
 nPos father;
 uint32 g;
 uint32 h;

 enum NodeState { NS_NONE, NS_OPENLIST, NS_CLOSELIST, NS_BLOCKED, NS_MAX };
 uint32 state;
};
const PathPoint NullPathPoint(nInvalidPos);
//===================================================================================

/**
 * \brief 节点地图
 *
 * 用节点坐标x,y直接索引到PathPoint存储位置。
 * 比较占地方,但是免去搜索操作。
 * 需要预设存储大小
 *
 */
class NodeMap {
 public:
  NodeMap( const nPos &source, uint32 radius = DEFAULT_MAX_RADIUS );
  inline void reset( const nPos &source, uint32 radius );
  inline PathPoint* checkAndGet( const nPos &pos );
  inline PathPoint* checkAndGet( const uint32 &x, const uint32 &y);

 private:
  inline uint32 calIndex(const uint32 &x, const uint32 &y) const;
  inline void resize( uint32 newSize );
  inline uint32 getSize() const;
  inline bool checkInRangeX(const uint32 &x) const;
  inline bool checkInRangeY(const uint32 &y) const;

 private:
  typedef std::vector<PathPoint> NodeMapType;
  NodeMapType m_nodeMap;

  uint32 m_radius;
  nPos m_sourcePos;
};
//===================================================================================

/**
 * \brief 二叉堆
 * T 需要支持 operator < 操作
 *
 */
template < typename T >
class BinaryHeap{
 public:
  BinaryHeap(){};
  inline bool putNodeIn( T *node );
  inline T* popRootNodeOut ();
  inline void clear();

 private:
  inline const uint32 getFatherIndex( const uint32 nodeIndex ) const;
  inline const uint32 get1stChildIndex( const uint32 nodeIndex ) const;
  inline const uint32 get2ndChildIndex( const uint32 nodeIndex ) const;

 protected:
  std::vector<T*> m_vec;
};
//===================================================================================

/**
 * \brief OpenList
 * 二叉堆实现最小F值节点查找
 *
 */
class OpenList {
 public:
  OpenList( NodeMap *pNodeMap );
  inline bool add( const PathPoint &point );
  inline bool checkAndUpdate( const PathPoint &point );
  inline PathPoint popMinF();
  inline void clear();
 private:
  NodeMap *m_pNodeMap;
  BinaryHeap<PathPoint> m_binaryHeap;
};
//===================================================================================

/**
 * \brief CloseList
 *
 */
class CloseList {
 public:
  CloseList( NodeMap *pNodeMap );
  inline bool add( const PathPoint &point );
  inline bool checkAndUpdate( const PathPoint &point );
  inline void clear();
 private:
  NodeMap *m_pNodeMap;
};

 

/*
 * =====================================================================================
 *
 *       Filename:  astar.cpp
 *
 *    Description:  A*寻路算法实现
 *
 *        Version:  1.0
 *        Created:  08/19/2013 06:23:17 AM
 *       Compiler:  g++
 *
 *         Author:  xch
 *   Organization:  lucky
 *
 * =====================================================================================
 */

#include"astar.h"

/**
 * \brief A*算法最大拓展节点
 * 在无可达路径时候,A*会拓展地图内的所有点,消耗过多资源。
 * 经过统计,一般可以寻到路径的平均值不会超过50,超过100的值很少来;
 * 失败情况下平均都会在1000以上(生存副本中大寻路半径情况统计)。
 * 可以根据使用情况调整。
 *
 */

#define MAX_EXTENDED_NODE_NUM (150)

#define JUDGE(startpos, endpos) (std::max(abs(startpos.x - endpos.x), abs(startpos.y - endpos.y)))

extern nPos MAP_MAX_POS;

//----------------------------
// AStar2 实现
//----------------------------
AStar::AStar() : m_bRefind(false), max_radius(DEFAULT_MAX_RADIUS)
{
}

AStar::~AStar()
{
}

 

 


uint8 AStar::goToFindPath(const nPos &srcPos, const nPos &destPos)
{
 if(!m_path.empty())
 {
  if(m_path[0] != destPos || m_path.size() == 1)
  {
   m_path.clear();
  }
  else
  {
   nPos nextPos = m_path.back();
   m_path.pop_back();
 //  printf("==========AI======[%u]======\r\n",(uint16)m_path.size());
   if(move(nextPos))
   {
    return ASTAR_SUCCESS;
   }
  }
 }else
 {
  findPath(srcPos, destPos);
 }
 return false;
}

 


void AStar::setRefind()
{
 m_bRefind = true;
}

int AStar::setMaxRadius(int newRadius)
{
 return (m_maxRadius = newRadius);
}

uint32 AStar::calH(const nPos &fromPos, const nPos &toPos)
{
 return abs(fromPos.x-toPos.x) + abs(fromPos.y-toPos.y);
}


AStarResult AStar::findPath(const nPos &fromPos, const nPos &toPos)
{

 m_path.clear();

 if ( fromPos == toPos )
 {
  return ASTAR_NONE_OPT;
 }

 // 检查完全阻塞,是否扩展周围节点作为目标
// if ( isFullBlock(toPos) )
// {
//  return ASTAR_UNREACHABLE;
// }

 // 距离、步长检查
 unsigned int dx = abs(fromPos.x - toPos.x);
 unsigned int dy = abs(fromPos.y - toPos.y);
 if ( dx > DEFAULT_MAX_RADIUS || dy > DEFAULT_MAX_RADIUS )
 {
  return ASTAR_TOO_FAR_OPT;
 }


 // A* 算法开始
 static const int offset[8][3] =
 {   // 偏移计算矩阵(x,y,weight)
  {-1,1,1}, {0,1,1}, {1,1,1},
  {-1,0,1},    {1,0,1},
  {-1,-1,1}, {0,-1,1}, {1,-1,1},
 };
 static NodeMap nodeMap(fromPos, DEFAULT_MAX_RADIUS);
 static OpenList openList(&nodeMap);   // OpenList
 static CloseList closeList(&nodeMap);  // CloseList
 m_maxRadius = DEFAULT_MAX_RADIUS;
 nodeMap.reset( fromPos, m_maxRadius );
 openList.clear();
 closeList.clear();

 PathPoint startPoint;
 startPoint.pos = fromPos;
 startPoint.father = NullPos;
 openList.add(startPoint);

 AStarResult res = ASTAR_NONE_OPT;
 unsigned int loopCounter = 0;

 while ( loopCounter < MAX_EXTENDED_NODE_NUM )
 {
  // 弹出最小F节点
  PathPoint nowPoint = openList.popMinF();
  if ( nowPoint == NullPathPoint )
  {
   res = ASTAR_UNREACHABLE_OPT;
   break;
  }
  closeList.add(nowPoint);

  // 拓展周围8个节点
  for ( int i=0; i<8; i++)
  {
   PathPoint point;
   point.pos.x = nowPoint.pos.x + offset[i][0];
   point.pos.y = nowPoint.pos.y + offset[i][1];
   point.father = nowPoint.pos;
   point.g = nowPoint.g + offset[i][2];
   point.h = calH(point.pos, toPos);

   // 检查节点合法性
   PathPoint *p = nodeMap.checkAndGet(point.pos);
   if ( !p ) continue;

   // 是否到达目标点
   if ( abs((int) point.pos.x - (int)toPos.x ) < 1 &&
     abs( (int)point.pos.y - (int)toPos.y ) < 1 )
   {

    closeList.add(point);
    // 构造一个toPos的PathPoint节点
    point.g += 1;
    point.h = 0;
    point.father = point.pos;
    point.pos = toPos;
    closeList.add(point);

    res = ASTAR_SUCCESS_OPT;
    break;
   }

   // 是否阻挡
   if (moveable(point.pos, false) )
   {
    continue;
   }

   // 是否已经在OpenList
   if ( openList.checkAndUpdate(point) )
   {
    continue;
   }

   // 是否已经在CloseList
   if ( closeList.checkAndUpdate(point) )
   {
    continue;
   }

   // 扩展节点
   openList.add(point);
  }

  if ( res != ASTAR_NONE_OPT )
  {
   break;
  }

  loopCounter++;
 }

 // 回退生成路径
 if (res == ASTAR_SUCCESS_OPT)
 {
  PathPoint *pPoint = nodeMap.checkAndGet(toPos);
  while( pPoint && pPoint->pos != fromPos )
  {
   m_path.push_back( pPoint->pos );
   pPoint = nodeMap.checkAndGet( pPoint->father );
  }
 }

 return res;
}


//===================================================================================


//----------------------------
// NodeMap 实现
//----------------------------
NodeMap::NodeMap(const nPos &source, uint32 radius) : m_radius(radius), m_sourcePos(source)
{
 m_nodeMap.clear();
 m_nodeMap.resize(getSize());
}

void NodeMap::reset(const nPos &source, uint32 radius)
{
 m_sourcePos = source;
 m_radius = radius;
 m_nodeMap.resize(getSize());
 //这两行完成的功能就是把PathPoint的值恢复成默认值.PathPoint::father没有设置成nNullPos,但是这样不会影响计算过程.
 bzero(&(*m_nodeMap.begin()), sizeof(PathPoint) * m_nodeMap.size());
}

PathPoint* NodeMap::checkAndGet(const nPos &pos)
{
 return checkAndGet(pos.x, pos.y);
}

PathPoint* NodeMap::checkAndGet(const uint32 &x, const uint32 &y)
{
 if (nInvalidPos == m_sourcePos || 0 == m_radius) {
  return NULL;
 }

 if (!checkInRangeX(x))
 {
  return NULL;
 }
 if (!checkInRangeY(y))
 {
  return NULL;
 }
 return &(m_nodeMap[calIndex(x,y)]);
}

bool NodeMap::checkInRangeX(const uint32 &x) const
{
 uint32 maxX = m_sourcePos.x + m_radius;
 uint32 minX = m_sourcePos.x > m_radius ? m_sourcePos.x-m_radius : 0;

 if (x > maxX || x < minX) {
  return false;
 }
 else{
  return true;
 }
}

bool NodeMap::checkInRangeY(const uint32 &y) const
{
 uint32 maxY = m_sourcePos.y + m_radius;
 uint32 minY = m_sourcePos.y > m_radius ? m_sourcePos.y-m_radius : 0;

 if (y > maxY || y < minY) {
  return false;
 }
 else {
  return true;
 }
}

uint32 NodeMap::calIndex(const uint32 &x, const uint32 &y) const
{
 uint32 dx = x - (m_sourcePos.x - m_radius);
 uint32 dy = y - (m_sourcePos.y - m_radius);

 return dx + dy * 2 * m_radius;
}

uint32 NodeMap::getSize() const
{
 //现在m_radius是没有变化的,所以size没有变化
 return (2*m_radius+1) * (2*m_radius+1);
}

//----------------------------
// 二叉堆 实现
//----------------------------

// putNodeIn & popRootNodeOut 保证在比较相同的情况下,新进入的节点在堆的更上层
 template < typename T >
bool BinaryHeap<T>::putNodeIn(T *node)
{
 m_vec.push_back(node);
 if (m_vec.size() <= 1) {
  return true;
 }

 uint32 nowIndex = m_vec.size()-1;
 while (nowIndex != 0) {
  uint32 fatherIndex = getFatherIndex(nowIndex);

  if (!(*m_vec[fatherIndex] < *m_vec[nowIndex])) {
   T* tmp = m_vec[nowIndex];
   m_vec[nowIndex] = m_vec[fatherIndex];
   m_vec[fatherIndex] = tmp;

   nowIndex = fatherIndex; 
  }
  else {
   break;
  }
 }
 return true;
}

 template < typename T >
T* BinaryHeap<T>::popRootNodeOut()
{
 if (m_vec.empty()) {
  return NULL;
 }

 T* ret = m_vec[0];

 m_vec[0] = m_vec.back();
 m_vec.pop_back();

 if (m_vec.size() <= 1) {
  return ret;
 }

 uint32 nowIndex = 0;
 uint32 maxIndex = m_vec.size() - 1;
 while (true) {
  uint32 firstChildIndex = get1stChildIndex(nowIndex);
  uint32 secondChildIndex = get2ndChildIndex(nowIndex);
  uint32 minChildIndex = nowIndex;

  if (secondChildIndex > maxIndex) {
   if (firstChildIndex > maxIndex) {
    break;
   }
   else {
    minChildIndex = firstChildIndex;
   }
  }
  else {
   minChildIndex = *m_vec[firstChildIndex] < *m_vec[secondChildIndex] ?
    firstChildIndex : secondChildIndex;
  }

  if (*m_vec[minChildIndex] < *m_vec[nowIndex])
  {
   T* tmp = m_vec[nowIndex];
   m_vec[nowIndex] = m_vec[minChildIndex];
   m_vec[minChildIndex] = tmp;

   nowIndex = minChildIndex;
  }
  else {
   break;
  }
 }

 return ret;
}

template < typename T >
const uint32 BinaryHeap<T>::getFatherIndex(const uint32 nodeIndex) const
{
 if (0 == nodeIndex)
  return 0;

 return (nodeIndex - 1) / 2;
}

template < typename T >
const uint32 BinaryHeap<T>::get1stChildIndex(const uint32 nodeIndex) const
{
 return nodeIndex * 2 + 1;
}

template < typename T >
const uint32 BinaryHeap<T>::get2ndChildIndex(const uint32 nodeIndex) const
{
 return nodeIndex * 2 + 2;
}

 template < typename T >
void BinaryHeap<T>::clear()
{
 m_vec.clear();
}


//----------------------------
// OpenList 实现
//----------------------------
OpenList::OpenList(NodeMap *pNodeMap) : m_pNodeMap(pNodeMap)
{
}

bool OpenList::add(const PathPoint &point)
{
 PathPoint *pPoint = m_pNodeMap->checkAndGet(point.pos);
 if (!pPoint) {
  return false;
 }
 if (PathPoint::NS_NONE != pPoint->state) {
  return false;
 }

 pPoint->pos = point.pos;
 pPoint->father = point.father;
 pPoint->g = point.g;
 pPoint->h = point.h;
 pPoint->state = PathPoint::NS_OPENLIST;

 m_binaryHeap.putNodeIn(pPoint);

 return true;
}

bool OpenList::checkAndUpdate(const PathPoint &point)
{
 PathPoint *pPoint = m_pNodeMap->checkAndGet(point.pos);
 if (!pPoint) {
  return false;
 }
 if (PathPoint::NS_OPENLIST != pPoint->state) {
  return false;
 }

 if (pPoint->g + pPoint->h > point.g + point.h) {
  pPoint->g = point.g;
  pPoint->h = point.h;
  pPoint->father = point.father;

  m_binaryHeap.putNodeIn(pPoint);
 }

 return true;
}

PathPoint OpenList::popMinF()
{
 PathPoint *pPoint = NULL;
 // 因为add会加入指向相同位置的指针到二叉堆里面,
 // 在pop掉一个后逻辑上就不应该在OpenList中了,
 // 所以在二叉堆里面指向没有标记OpenList对象的指针需要全部忽略掉。
 do {
  pPoint = m_binaryHeap.popRootNodeOut();
  if (!pPoint)
  {
   return NullPathPoint;
  }
 }
 while (PathPoint::NS_OPENLIST != pPoint->state);

 // 出去的时候一定要标记
 pPoint->state = PathPoint::NS_NONE;

 return *pPoint;
}

void OpenList::clear() {
 m_binaryHeap.clear();
}


//----------------------------
// CloseList 实现
//----------------------------
CloseList::CloseList(NodeMap *pNodeMap) : m_pNodeMap(pNodeMap)
{
}

bool CloseList::add(const PathPoint &point)
{
 PathPoint *pPoint = m_pNodeMap->checkAndGet(point.pos);
 if (!pPoint) {
  return false;
 }
 if (PathPoint::NS_NONE != pPoint->state) {
  return false;
 }

 pPoint->pos = point.pos;
 pPoint->father = point.father;
 pPoint->g = point.g;
 pPoint->h = point.h;
 pPoint->state = PathPoint::NS_CLOSELIST;

 return true;
}

bool CloseList::checkAndUpdate(const PathPoint &point)
{
 PathPoint *pPoint = m_pNodeMap->checkAndGet(point.pos);
 if (!pPoint) {
  return false;
 }
 if (PathPoint::NS_CLOSELIST != pPoint->state) {
  return false;
 }

 if (pPoint->g + pPoint->h > point.g + point.h) {
  pPoint->g = point.g;
  pPoint->h = point.h;
  pPoint->father = point.father;
 }

 return true;
}

void CloseList::clear()
{
}


bool AStar::findReachablePos(nPos &pos, const unsigned int stepValue, bool dynamic)
{
 const nAdjust adjust[8] =
 {
  { 1, 0 },
  { 0, -1 },
  { 0, 1 },
  {  -1, 0 },
  { 1, -1 },
  {  -1, -1 },
  {  -1, 1 },
  { 1, 1 },
 };

 unsigned int step = 1;
 for(;step <= stepValue;step++)
 {
  for(int i = 0; i < 8; i++)
  {
   nPos tempPos = pos;
   tempPos.x += adjust[i].x * step;
   tempPos.y += adjust[i].y * step;

   if (!moveable(tempPos, dynamic))
   {
    continue;
   }

   pos = tempPos;
   return true;
  }
 }

 return false;

}

void AStar::dumpHeap(stack_heap_type &stack_heap)
{
 for (unsigned int index = 0; index < stack_heap.size(); index++)
 {
  printf("\t\tf:%u, pos:(%u,%u), g:%u\n", stack_heap[index]->f, stack_heap[index]->pos.x, stack_heap[index]->pos.y, stack_heap[index]->g);
 }
}

 


void AStar::intoHeap(stack_heap_type &stack_heap, nPathPoint *newPoint)
{
   stack_heap.push_back(newPoint);
   unsigned int endpoint = stack_heap.size() - 1;

   for(;endpoint != 0;)
   {
    nPathPoint *e = stack_heap[endpoint];
    nPathPoint *p = stack_heap[endpoint/2];
    if (e->f < p->f)
    {
     nPathPoint *temp = e;
     stack_heap[endpoint] = p;
     stack_heap[endpoint/2] = temp;
     endpoint /= 2;
    }
    else
    {
     break;
    }
  }
}

 

nPathPoint* AStar::exitHeap(stack_heap_type &stack_heap)
{
 if (stack_heap.empty())
 {
  return NULL;
 }
 nPathPoint *ret = stack_heap[0];
 stack_heap[0] = stack_heap[stack_heap.size()-1];
 stack_heap.pop_back();

 unsigned int endpoint = 0;
 for(;endpoint*2+2 < stack_heap.size();)
 {
  nPathPoint *e = stack_heap[endpoint];
  nPathPoint *pl = stack_heap[endpoint*2+1];
  nPathPoint *pr = stack_heap[endpoint*2+2];

  if (e->f > pl->f)
  {
   nPathPoint *temp = e;
   stack_heap[endpoint] = pl;
   stack_heap[endpoint*2+1] = temp;

   endpoint = endpoint * 2 + 1;
  }
  else if (e->f > pr->f)
  {
   nPathPoint *temp = e;
   stack_heap[endpoint] = pr;
   stack_heap[endpoint*2+2] = temp;
   endpoint = endpoint * 2 + 2;
  }
  else
  {
   break;
  }
 }
 return ret;
}

 

Makefile
 all:
 g++ -fpic -shared astar.cpp -o libastar.so -lm
clean:
 rm -f *.so

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值