A*算法的实现

看见CSDN博主小满(bill man)个人原创实现A*算法,没有全部的代码,且实现的是游戏中的应用。故想到不如自己在他的基础上把代码补全,同时将算法独立出来。只实现A*算法,不涉及游戏引擎部分。

算法思想在这篇博客里有很详尽的说明:http://blog.vckbase.com/panic/archive/2005/03/20/3778.html

代码核心部分皆取自小满(bill man)的博文:http://blog.csdn.net/bill_man/article/details/7296560

 

这是我的第一篇CSDN博客,感谢老婆一直鼓励我,我会继续努力的!哈哈……

 

直接上代码:

//*** Map.h ***

#ifndef __MAP_H
#define __MAP_H

class Map
{
public:
	Map(int wid, int hgt);
	~Map();

	int  width()  {	return m_width;	 }
	int  height() {	return m_height; }

	void setobstacle(int col, int row);
	void setstep(int col, int row);
	char value(int col, int row);

private:
	char* matrix;
	int   m_width;
	int   m_height;
};

#endif

 

 

//*** Map.cpp ***

#include <string>
#include "Map.h"

Map::Map(int wid, int hgt)
{
	m_width  = wid;
	m_height = hgt;

	int size = wid * hgt;
	matrix = new char[size];
	memset(matrix, '0', size * sizeof(char)); //大小不是size !!!
}

Map::~Map()
{
	delete[] matrix;
}

void Map::setobstacle(int col, int row)
{
	if(matrix)
		matrix[row * m_width + col] = '1';
}

void Map::setstep(int col, int row)
{
	if(matrix)
		matrix[row * m_width + col] = '*';
}

char Map::value(int col, int row)
{
	return matrix[row * m_width + col];
}


 

 

//*** AstarItem.h ***

#ifndef __ASTARITEM_H
#define __ASTARITEM_H


class AstarItem
{
public:
	AstarItem(void)  {}
	~AstarItem(void) {}

	void setpos(int col, int row);

	int col() { return id_col; }
	int row() { return id_row; }

	int  getcol() { return id_col; }
	int  getrow() { return id_row; }

	void setf(int f);
	int  getf()   { return id_f;   }

	void setg(int g);
	int  getg()   { return id_g;   }

	void seth(int h);
	int  geth()   { return id_h;   }

	void setfid(int fid);
	int  getfid() { return id_fid; }

private:
	int id_row;  //行
	int id_col;  //列
	int id_f;    //估价函数f = g + h
	int id_g;    //实际代价
	int id_h;    //估计代价
	int id_fid;  //父节点id
};

#endif


 

 

 

//*** AstarItem.cpp ***

#include "AStarItem.h"

void AstarItem::setpos(int col, int row)
{
	id_col = col;
	id_row = row;
}

void AstarItem::setf(int f)
{
	id_f = f;
}

void AstarItem::setg(int g)
{
	id_g = g;
}

void AstarItem::seth(int h)
{
	id_h = h;
}

void AstarItem::setfid(int fid)
{
	id_fid = fid;
}


 

 

//***** AStar.h ****

#ifndef __ASTAR_H
#define __ASTAR_H

#include <vector>
#include <stack>
using namespace std;

class Map;
class AstarItem;


class Astar
{
public:
	Astar(Map* the_map) : map(the_map) {}
	~Astar(void);

	void reset();

	void findpath(int curX, int curY, int aimX, int aimY);

	int  getH(int col, int row);
	int  getG(int col, int row, int fid);
	void fromopentoclose();
	void removefromopen();
	void starsearch(int fid);
	void getpath();
	void showpath();

	bool checkmap(int col, int row);
	bool checkopen(int col, int row, int fid);
	bool checkclose(int col, int row);
	void addtoopen(int col, int row, int fid);

	void resetsort(int last);

private:
	Map* map;

	int  curCol;
	int  curRow;
	int  aimCol;
	int  aimRow;

	stack<AstarItem*>  path;
	vector<AstarItem*>  open;
	vector<AstarItem*>  close;
};

#endif


//**** AStar.cpp ****

#include <iostream>
#include <stdlib.h>
#include "AStar.h"
#include "Map.h"
#include "AStarItem.h"

using namespace std;


Astar::~Astar(void)
{
	reset();
}

void Astar::reset()
{
	open.clear();
	close.clear();
	
	while(!path.empty())
		path.pop();
}


int Astar::getH(int col, int row)
{
	return abs(aimCol - col) * 10 + abs(aimRow - row) * 10;
}


int Astar::getG(int col, int row, int fid)
{
	int fx = close[fid]->getcol();
	int fy = close[fid]->getrow();
	int fg = close[fid]->getg();

	if((fx - col != 0) && (fy - row != 0))
	{ // 上下左右
		return fg + 14;
	}
	else
	{ // 四角
		return fg + 10;
	}
}


void Astar::findpath(int curX, int curY, int aimX, int aimY)
{
	curCol = curX;
	curRow = curY;
	aimCol = aimX;
	aimRow = aimY;

	//优先队列的0项,无意义
	AstarItem* temp = new AstarItem();
	open.push_back(temp);

	AstarItem* temp1 = new AstarItem();
	temp1->setpos(curCol, curRow);
	temp1->setg(0);
	int ag = getH(curCol, curRow);
	temp1->seth(ag);
	temp1->setf(ag);
	temp1->setfid(0);
	open.push_back(temp1);

	while(open.size() > 1)
	{
		fromopentoclose();
		int fatherid = close.size() - 1;
		int mycol = close.back()->getcol();
		int myrow = close.back()->getrow();

		if((aimCol == mycol) && (aimRow == myrow))
		{
			getpath();
			break;
		}
		else
		{
			starsearch(fatherid);
		}
	}

	//show path and reset
	showpath();
	reset();
}


void Astar::fromopentoclose()
{
	AstarItem* temp = open[1];
	close.push_back(temp);

	removefromopen();
}

void Astar::removefromopen()
{
	int last = open.size() - 1;
	open[1] = open[last];
	open.pop_back();
	last = open.size() - 1;
	int head = 1;
	while((head * 2) <= last)
	{ // shift down
		int child = head * 2;
		if((child + 1) <= last && open[child + 1]->getf() < open[child]->getf())
			child++;
		if(open[head]->getf() <= open[child]->getf())
			break;
	
		AstarItem* temp = open[child];
		open[child] = open[head];
		open[head]  = temp;

		head = child;
	}

}


void Astar::starsearch(int fid)
{
	int col = close[fid]->getcol();
	int row = close[fid]->getrow();

	int mycol = col;
	int myrow = row - 1;
	if(myrow >= 0 && checkmap(mycol, myrow))
	{
		if(checkopen(mycol, myrow, fid) && checkclose(mycol, myrow))
		{
			addtoopen(mycol, myrow, fid);
		}
	}

	mycol = col - 1;
	myrow = row;
	if(mycol >= 0 && checkmap(mycol, myrow))
	{
		if(checkopen(mycol, myrow, fid) && checkclose(mycol, myrow))
		{
			addtoopen(mycol, myrow, fid);
		}
	}

	mycol = col;
	myrow = row + 1;
	int w = map->width();
	if(myrow < map->width() && checkmap(mycol, myrow))
	{
		if(checkopen(mycol, myrow, fid) && checkclose(mycol, myrow))
		{
			addtoopen(mycol, myrow, fid);
		}
	}

	mycol = col + 1;
	myrow = row;
	if(mycol < map->height() && checkmap(mycol, myrow))
	{
		if(checkopen(mycol, myrow, fid) && checkclose(mycol, myrow))
		{
			addtoopen(mycol, myrow, fid);
		}
	}

}


bool Astar::checkmap(int col, int row)
{
	// 是否为障碍物
	return (map->value(col, row) == '0');
}




bool Astar::checkopen(int col, int row, int fid)
{ // 是否在open表中。若在,比较g值
	vector<AstarItem*>::iterator iter = open.end() - 1; //第0个为填充项,无意义
	int i = open.size() - 1;
	for( ; iter != open.begin(), i > 0; --iter, --i)
	{
		AstarItem* item = *iter;
		if((item->getcol() == col) && (item->getrow() == row))
		{
			int tempG = getG(col, row, fid);
			if(tempG < (item->getg()))
			{
				item->setg(tempG);
				item->setf(tempG + item->geth());
				item->setfid(fid);

				resetsort(i);
			}
			return false;
		}
	}
	return true;
}


bool Astar::checkclose(int col, int row)
{ // 是否在open表中,避免重复
	vector<AstarItem*>::iterator iter = close.begin();
	for( ; iter != close.end(); ++iter)
	{
		AstarItem* item = *iter;
		if((item->getcol() == col) && (item->getrow() == row))
		{
			return false;
		}
	}
	return true;
}

void Astar::addtoopen(int col, int row, int fid)
{
	AstarItem* temp = new AstarItem();
	temp->setpos(col, row);
	temp->setfid(fid);
	int g = getG(col, row, fid);
	int h = getH(col, row);
	temp->setg(g);
	temp->seth(h);
	temp->setf(g + h);
	open.push_back(temp);
	
	resetsort(open.size() - 1);
}

void Astar::resetsort(int last)
{ // shift up(因为加入的是一个更小值,所以只需向上调整!)
	while(last > 1)
	{
		int half = last / 2;
		if(open[half]->getf() <= open[last]->getf())
		{
			break;
		}
		AstarItem* temp = open[last];
		open[last] = open[half];
		open[half] = temp;

		last = half;
	}
}


void Astar::getpath()
{
	path.push(close.back());

	while(true)
	{
		if(path.top()->getg() == 0)
		{
			break;
		}
		path.push(close[path.top()->getfid()]);
	}
}

void Astar::showpath()
{
	int width  = map->width();
	int height = map->height();
	while(!path.empty())
	{
		AstarItem* item = path.top();
		path.pop();

		map->setstep(item->col(), item->row());
	}

	cout << "the step:" << endl;
	for(int i = 0; i < height; ++i)
	{
		for(int j = 0; j < width; ++j)
		{
			cout << map->value(i, j) << " " ;
		}
		cout << endl;
	}
}


//***** main.cpp *****

#include <iostream>
#include "Map.h"
#include "AStar.h"
using namespace std;

int main()
{
	Map   map(10, 10);
	Astar astar(&map);

	//set obstacle
	map.setobstacle(0, 2);
	map.setobstacle(1, 2);
	map.setobstacle(2, 2);
	map.setobstacle(3, 2);
	map.setobstacle(4, 2);
	map.setobstacle(2, 5);
	map.setobstacle(3, 5);
	map.setobstacle(4, 5);
	map.setobstacle(5, 5);
	map.setobstacle(6, 5);
	map.setobstacle(7, 5);
	map.setobstacle(8, 5);
	map.setobstacle(9, 5);

	//show map
	cout << "the map: " << endl;
	for(int i = 0; i < 10; ++i)
	{
		for(int j = 0; j < 10; ++j)
		{
			cout << map.value(i, j) << " " ;
		}
		cout << endl;
	}
	cout << endl;

	//find path
	astar.findpath(1, 0, 4, 8);

	cin.get();
	return 0;
}


运行结果:

 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值