关闭

游戏编程中的人工智能技术-遗传算法入门(三)

1501人阅读 评论(0) 收藏 举报

先请教大家一个问题,为什么我的遗传算法入门(一)一直处于“待审核”状态?

好,言归正传,继续研究代码。先看看CBobsMap类的定义。

class CBobsMap
{
private:
	
	//storage for the map
	static const int	map[MAP_HEIGHT][MAP_WIDTH]; //设计一个数组,用来构造地图

	static const int	m_iMapWidth;//地图的宽度
	static const int	m_iMapHeight;//地图的高度

	//index into the array which is the start point
	static const int	m_iStartX; //起始点的x坐标
	static const int	m_iStartY; //起始点的y坐标

	//and the finish point
	static const int	m_iEndX; //终止点的x坐标
	static const int	m_iEndY; //终止点的y坐标


public:

	//we can use this array as Bobs memory if rqd
	int					memory[MAP_HEIGHT][MAP_WIDTH]; //记录下Bob走过的路线,重新定义一个地图数组

	CBobsMap()
	{
		ResetMemory(); //路线记忆清零

	}

	//takes a string of directions and see's how far Bob
	//can get. Returns a fitness score proportional to the 
	//distance reached from the exit.
	double TestRoute(const vector<int> &vecPath, CBobsMap &memory);//走迷宫了!该如何操作?

	//given a surface to draw on this function uses the windows GDI
	//to display the map.
	void Render(const int cxClient, const int cyClient, HDC surface);

	//draws whatever path may be stored in the memory
	void MemoryRender(const int cxClient, const int cyClient, HDC surface);

	void ResetMemory();


};





在AI算法的使用中,最关键的是什么?是算法的理论吗?我感觉最关键的应该是如何将算法应用到实际中去。在本游戏中,如何构造一个算法的具体实现,最为关键。

接下来研究TestRoute()函数。

double CBobsMap::TestRoute(const vector<int> &vecPath, CBobsMap &Bobs)
{
	int posX = m_iStartX;
	int posY = m_iStartY;

	for (int dir=0; dir<vecPath.size(); ++dir)
	{
		int NextDir = vecPath[dir];

		switch(vecPath[dir])
		{
		case 0: //North

			//check within bounds and that we can move
			if ( ((posY-1) < 0 ) || (map[posY-1][posX] == 1) )
			{
				break;
			}

			else
			{
				posY -= 1;
			}

			break;

		case 1: //South

			//check within bounds and that we can move
			if ( ((posY+1) >= m_iMapHeight) || (map[posY+1][posX] == 1) )
			{
				break;
			}
			
			else
			{
				posY += 1;
			}

			break;

		case 2: //East

			//check within bounds and that we can move
			if ( ((posX+1) >= m_iMapWidth ) || (map[posY][posX+1] == 1) )
			{
				break;
			}
			
			else
			{
				posX += 1;
			}

			break;

		case 3: //West

			//check within bounds and that we can move
			if ( ((posX-1) < 0 ) || (map[posY][posX-1] == 1) )
			{
				break;
			}
			
			else
			{
				posX -= 1;
			}

			break;

		}//end switch

		//mark the route in the memory array
		Bobs.memory[posY][posX] = 1;

	}//next direction

	//now we know the finish point of Bobs journey, let's assign
	//a fitness score which is proportional to his distance from
	//the exit

	int	DiffX = abs(posX - m_iEndX);
	int DiffY = abs(posY - m_iEndY);

	//we add the one to ensure we never divide by zero. Therefore
	//a solution has been found when this return value = 1
	return 1/(double)(DiffX+DiffY+1);
}

这个函数的作用是根据实际游戏情境设计遗传算法的染色体,并计算他的适应度函数。

一句一句来。

double CBobsMap::TestRoute(const vector<int> &vecPath, CBobsMap &Bobs)
TestRoute为CBobsMap类中的函数,参数为const vector<int> &vecPath,表示一个int型向量的首地址,其实也就是表示这个向量;CBobsMap &Bobs,表示一个CBobsMap类的首地址,其实也就是定义了一个CBobsMap的实例,叫做Bobs。
int posX = m_iStartX;
int posY = m_iStartY;

Bob开始走路了!这个是Bob的初始位置。

for (int dir=0; dir<vecPath.size(); ++dir)
这个是遍历一条染色体内的整个基因。vecPath.size()表示染色体的长度,即基因的个数。

那么在本程序中,染色体的基因个数为多少呢?

在Define.h中有定义:

<pre name="code" class="cpp">#define WINDOW_WIDTH	450
#define WINDOW_HEIGHT	300

#define MAP_WIDTH		15
#define MAP_HEIGHT		10

#define CROSSOVER_RATE	0.7
#define MUTATION_RATE	0.001

#define POP_SIZE		140
#define CHROMO_LENGTH	30
#define GENE_LENGTH		2

#endif


可以通过调试看到实际染色体长度。在CgaBob类中,函数UpdateFitnessScores()中如下所示
void CgaBob::UpdateFitnessScores()
{
	m_iFittestGenome		= 0;
	m_dBestFitnessScore		= 0;
	m_dTotalFitnessScore	= 0;

	CBobsMap TempMemory;
	 
	//update the fitness scores and keep a check on fittest so far
	for (int i=0; i<m_iPopSize; ++i)  //这个是种群的数量,不是染色体的长度
	{
		//decode each genomes chromosome into a vector of directions
		vector<int> vecDirections = Decode(m_vecGenomes[i].vecBits);这个就是染色体

		//get it's fitness score
		m_vecGenomes[i].dFitness = m_BobsMap.TestRoute(vecDirections, TempMemory);//TestRoute的第一个向量参数,即表示染色体

		//update total
		m_dTotalFitnessScore += m_vecGenomes[i].dFitness;

		//if this is the fittest genome found so far, store results
		if (m_vecGenomes[i].dFitness > m_dBestFitnessScore)
		{
			m_dBestFitnessScore = m_vecGenomes[i].dFitness;

			m_iFittestGenome = i;

			m_BobsBrain = TempMemory;

			//Has Bob found the exit?
			if (m_vecGenomes[i].dFitness == 1)
			{
				//is so, stop the run
				float a = m_vecGenomes[i].dFitness;
				vector<int> b = m_vecGenomes[i].vecBits;
				m_bBusy = false;
			}
		}

		TempMemory.ResetMemory();
	
	}//next genome
}
可以通过断点调试观察vecDirections的长度。


可以看到vecDirections的长度到0x22结束,对应十进制就是34。

以上是解释染色体的长度为多少。

接下来继续分析程序。

for (int dir=0; dir<vecPath.size(); ++dir)
	{
		int NextDir = vecPath[dir];

		switch(vecPath[dir])
		{
		case 0: //North

			//check within bounds and that we can move
			if ( ((posY-1) < 0 ) || (map[posY-1][posX] == 1) )
			{
				break;
			}






到了其中的一个基因了。一共有四个case, case 0, case 1, case 2, case 3。即00,01,10,11。为基因的种类,分别表示向北走一步,向南走一步,向东走一步,向西走一步。vecPath[dir]储存了这个基因。即vecPath[dir]=00,01,10,11.

这个是编程思想的关键,以后再实际操作中,首先要考虑如何来根据游戏来构造染色体?本例中,因为Bob要走迷宫,那么实际操作是向北走一步,向南走一步,向东走一步,向西走一步,则可以用00.01.10.11来表示每个操作。

if ( ((posY-1) < 0 ) || (map[posY-1][posX] == 1) )
posY-1<0表示已经到了迷宫的北墙了,所以不能再往北走了,map[posY-1][posX] == 1表示往北走一步就撞到障碍物了,当然也就无法实现往北走一步的操作了。因此两种情况Bob的位置不会发生变化,直接break.

如果不是上述两种情况,则Bob可往北走一步,则Bob的位置变化一格。即posY -= 1;再break

case 1: //South

			//check within bounds and that we can move
			if ( ((posY+1) >= m_iMapHeight) || (map[posY+1][posX] == 1) )
			{
				break;
			}
			
			else
			{
				posY += 1;
			}

			break;

		case 2: //East

			//check within bounds and that we can move
			if ( ((posX+1) >= m_iMapWidth ) || (map[posY][posX+1] == 1) )
			{
				break;
			}
			
			else
			{
				posX += 1;
			}

			break;

		case 3: //West

			//check within bounds and that we can move
			if ( ((posX-1) < 0 ) || (map[posY][posX-1] == 1) )
			{
				break;
			}
			
			else
			{
				posX -= 1;
			}

			break;

		}//end switch

同上。

Bobs.memory[posY][posX] = 1;
无论走还是没走,Bob的记忆地图里存储了操作后的位置,这个是用来画图用的。

int	DiffX = abs(posX - m_iEndX);
	int DiffY = abs(posY - m_iEndY);

	//we add the one to ensure we never divide by zero. Therefore
	//a solution has been found when this return value = 1
	return 1/(double)(DiffX+DiffY+1);

适应度函数的计算,适应值为Bob离迷宫出口的距离值,这个程序中,没有用实际距离,而只是将x坐标和y坐标简单的相加。为了取适应度的最大值,当然要return 1/(double)(DiffX+DiffY+1);啦。



可以通过调试看到实际染色体长度。在CgaBob类中,函数UpdateFitnessScores()中如下所示
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:8545次
    • 积分:190
    • 等级:
    • 排名:千里之外
    • 原创:11篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档