基于遗传算法的寻路模拟

学习了些人工智能的东西, 利用遗传算法来写了一个寻路的演示程序, 虽然该算法效率底下, 但作为一个学习程序还是有直观性;

先把代码和结果贴上, 有时间再写分析

遗传算法类

主要有两个类: 基因编码类和基因组类;

“GeGroup.h”

#ifndef  _GEGROUP_HBB_
#define  _GEGROUP_HBB_
#include "HMap.h"
#include "Global.h"
#include <bitset>
class HMap;
class GeCode
{
public:
	GeCode();
	~GeCode();
	std::bitset<LEN_BIT_ROUTE> mGeRoute;
	int mHighestFitSce;
	int mHighestSceStep;
	void Clear();
	// decode generic
	SearchDir DeCode(const int StepIndex);
};

class  GeGroup
{
public:
	GeGroup(HMap& m);
	~GeGroup();
	GeCode mGrop[NUM_GEGROUP];
	GeCode mFitGes[NUM_GEGROUP];
	int mBestGeIndex;
	int mTotalFitSce;
	HMap& mMap;
	bool Epoch();
	bool UpdateFitnessScore();
	GeCode WheelSelect();
private:
	int mGenerationCount;
	static const int mMaxScore = NUM_MAX_GRID*NUM_MAX_GRID*4;
	inline bool  IsCrossOver(){return RandInt(0,10) <= RATE_CROSSOVER;}
	inline bool IsMutation(){return RandInt(0,1000) <= RATE_MUTATION;}
	int CalcuFitScore(const int idx);
	int CalcuPosScore(const point& p);
	void CrossOver(const int mom, const int dad);
	void Mutate(const int geLst);
	bool EvolutionSelection();
	void ShowMarkMap();
};

#endif //  _GEGROUP_HBB_

“GeGroup.cpp”

#include "GeGroup.h"
#include <cassert>
#include <iostream>
#include "HMap.h"
#include <stdlib.h>
using namespace std;

static const int MAX_INT = 0x7fffffff;

GeCode::GeCode():mHighestFitSce(0),mHighestSceStep(0)
{

}
GeCode::~GeCode(){}

SearchDir  GeCode::DeCode(const int StepIndex)
{
	int codePos = StepIndex*LEN_BIT_CODE;
	unsigned Dir = 0;
	Dir |= (1u&mGeRoute[codePos]) | ((1u&mGeRoute[codePos+1])<<1) | ((1u&mGeRoute[codePos+2])<<2);
	return (SearchDir)Dir;
}

void GeCode::Clear()
{
	for(int i = 0; i < LEN_BIT_ROUTE; ++i)
		mGeRoute[i] = 0;
	mHighestSceStep = 0;
	mHighestFitSce = 0;
}

/*******************************
///           class GeGroup
*******************************/
GeGroup:: GeGroup(HMap& m):mBestGeIndex(0),mTotalFitSce(0)
	,mMap(m),mGenerationCount(0)
{
	for(int i = 0; i < NUM_GEGROUP;++i)
	{
		for(int j = 0; j<LEN_BIT_ROUTE;++j)
			mGrop[i].mGeRoute[j] = RandInt(0,1);
	}
}

GeGroup::~ GeGroup()
{
	//dtor
}

int GeGroup::CalcuPosScore(const point& p)
{
	// the longer distance, the lower score
	return 10000/ (abs(p.x - mMap.Ep.x) + abs(p.y - mMap.Ep.y)+1);
}

// calculate the fitness score, and record the score of the last pos
int GeGroup::CalcuFitScore(const int idx)
{
	assert(idx >=0 && idx < NUM_GEGROUP);
	GeCode& geLst = mGrop[idx];
	geLst.mHighestSceStep = 0;
	geLst.mHighestFitSce = 0;
	point curPos = mMap.Sp;
	for(int i = 0; i < NUM_MAX_STEP;++i)
	{
		MvVector mv = gMvVctr[geLst.DeCode(i)];
		curPos.x += mv.x;
		curPos.y += mv.y;
		geLst.mHighestSceStep = i;
		// check,if wrond back to the previous pos
		if(mMap.Map[curPos.x][curPos.y] == MAP_BLOCK || curPos.x<0
			||curPos.x>=NUM_MAX_GRID||curPos.y<0||curPos.y>=NUM_MAX_GRID)
		{
			--geLst.mHighestSceStep;
			break;
		}
		if(curPos == mMap.Ep)
		{
			geLst.mHighestFitSce = MAX_INT;
			return MAX_INT;
		}
	}
	geLst.mHighestFitSce = CalcuPosScore(curPos);
	return geLst.mHighestFitSce;
}

bool GeGroup::UpdateFitnessScore()
{
	mTotalFitSce = 0;
	mBestGeIndex = 0;
	int MaxSc = 0;
	// update all the generic group fitness score
	for(int i = 0; i < NUM_GEGROUP;++i)
	{
		int sce = CalcuFitScore(i);
		if(sce == MAX_INT)
		{
			mBestGeIndex = i;
			return true;
		}
		mTotalFitSce += sce;
		if(MaxSc < sce)
		{
			MaxSc = sce;
			mBestGeIndex = i;
		}
	}
	return false;
}

GeCode GeGroup::WheelSelect()
{
	// rand select out a generic vector
	int JudgeVal = RandInt(0,mTotalFitSce);
	int tScr = 0;
	int Slcted = 0;
	for(int i = 0;i<NUM_GEGROUP;++i)
	{
		tScr += mGrop[i].mHighestFitSce;
		if(tScr >= JudgeVal)
		{
			Slcted = i;
			break;
		}
	}
	return mGrop[Slcted];
}

void GeGroup::CrossOver(const int mom, const int dad)
{
	assert(mom>=0 && mom<NUM_GEGROUP && dad>=0 && dad<NUM_GEGROUP);
	GeCode& geMom = mFitGes[mom];
	GeCode& geDad = mFitGes[dad];
	if(!IsCrossOver())
		return;
	// select a rand break pos on list
	int brkPos = RandInt(1, LEN_BIT_ROUTE-1);

	// exchange dad with mod from brkPos
	for(int i = brkPos; i < LEN_BIT_ROUTE;++i)
	{
		bool val = geMom.mGeRoute[i];
		geMom.mGeRoute[i] = geDad.mGeRoute[i];
		geDad.mGeRoute[i] = val;
	}
}

void GeGroup::Mutate(const int geLst)
{
	assert(geLst>=0&&geLst<NUM_GEGROUP);
	GeCode&  ge = mFitGes[geLst];
	for(int i = 0; i < LEN_BIT_ROUTE;++i)
	{
		if(IsMutation())
			ge.mGeRoute[i] = !ge.mGeRoute[i] ; // mutation, reverse bit
	}
}
// generation selection
bool GeGroup::EvolutionSelection()
{
	// update score
	if(UpdateFitnessScore())
		return true;
   // ShowMarkMap();
	int ct = 0;
	while(ct < NUM_GEGROUP)
	{
		// wheel select
		mFitGes[ct] = WheelSelect();
		mFitGes[ct + 1] = WheelSelect();
		//crossover
		CrossOver(ct,ct+1);
		// mutate
		Mutate(ct);
		Mutate(ct+1);
		ct += 2;
	}
	// copy val from fitnessGroup to geGroup
	for(int i = 0;i<NUM_GEGROUP;++i)
	{
		mGrop[i] = mFitGes[i];
		mFitGes[i].Clear();
	}
	return false;
}
// the core function
bool GeGroup::Epoch()
{
    mMap.ShowMap();
	bool hasFind = false;
	while(++mGenerationCount < 1000)
	{
//		Sleep(100);
		hasFind = EvolutionSelection();
//		ShowMarkMap();
		if(hasFind)
		{
			cout<<"Find the right way at generation:  "<< mGenerationCount<<endl;
			ShowMarkMap();
			break;
		}
	}
	// if find the way , mark the map
	if(!hasFind)
		cout<<"Can't find the way out!"<<endl;

	return hasFind;
}

void GeGroup::ShowMarkMap()
{
	GeCode& fitcode = mGrop[mBestGeIndex];
	point curPos = mMap.Sp;
	for(int i = 0; i<= fitcode.mHighestSceStep; ++i)
	{
		SearchDir curDir = fitcode.DeCode(i);
		curPos.x += gMvVctr[curDir].x;
		curPos.y += gMvVctr[curDir].y;
		mMap.Map[curPos.x][curPos.y] = MAP_LOAD;
	}
	mMap.Map[mMap.Sp.x][mMap.Sp.y] = MAP_START;
	mMap.Map[mMap.Ep.x][mMap.Ep.y] = MAP_END;
	mMap.ShowMap();
	// retire
	curPos = mMap.Sp;
	for(int i = 0; i<= fitcode.mHighestSceStep; ++i)
	{
		SearchDir curDir = fitcode.DeCode(i);
		curPos.x += gMvVctr[curDir].x;
		curPos.y += gMvVctr[curDir].y;
		mMap.Map[curPos.x][curPos.y] = MAP_NONBLOCK;
	}
	mMap.Map[mMap.Sp.x][mMap.Sp.y] = MAP_START;
	mMap.Map[mMap.Ep.x][mMap.Ep.y] = MAP_END;
}

地图类

主要是地图的初始化和显示功能:

“HMap.h”

#ifndef HMAP_H
#define HMAP_H
#include "Global.h"

struct MvVector
{
	int x;
	int y;
	MvVector& operator=(const MvVector& mv)
	{
		x = mv.x;
		y = mv.y;
		return *this;
	}
	MvVector& operator+(const MvVector& mv)
	{
		x += mv.x;
		y += mv.y;
		return *this;
	}
};
static const MvVector gMvVctr[8] =
{{0,-1}, {1,-1}, {1,0}, {1,1}, {0,1}, {-1,1},{-1,0}, {-1,-1}};
class point
{
public:
	int x;
	int y;
	point(int X=-1,int Y=-1):x(X),y(Y){};
	point& operator=(const point& p)
	{
		x = p.x;
		y = p.y;
		return *this;
	}
	bool operator==(const point& pos)
	{
		return (x == pos.x) && (y == pos.y);
	}
};
enum SearchDir  // 8个搜索方向
{
	Dir_LEFT = 0,
	Dir_LEFT_DOWN,
	Dir_DOWN,
	Dir_RIGHT_DOWN,
	Dir_RIGHT,
	Dir_RIGHT_UP,
	Dir_UP,
	Dir_UP_LEFT,
};

class HMap
{
    public:
        char Map[NUM_MAX_GRID][NUM_MAX_GRID];
        point Sp, Ep;
        void InitMap();
        void ShowMap();
        HMap();
        virtual ~HMap();
    private:
        void InitStartAndEndPoint();
        static const point UP;
        static const point DOWN;
};

#endif // HMAP_H
#include "HMap.h"
#include <iostream>
#include <time.h>
using namespace std;

HMap::HMap()
{
    //ctor
}

HMap::~HMap()
{
    //dtor
}
const point HMap::UP(0,0);
const point HMap::DOWN(NUM_MAX_GRID,NUM_MAX_GRID);

void HMap::InitMap()
{
	srand((unsigned)time(NULL)); //可以改变随机数种子来改变地图情况
	for(int i = UP.x; i < DOWN.x; ++i)
	{
		for(int j = UP.y; j < DOWN.y; ++j)
			Map[i][j] = rand()&1?MAP_NONBLOCK:MAP_BLOCK; //将地图格子随机设为阻碍或非阻碍
	}
	InitStartAndEndPoint();
}

void HMap::InitStartAndEndPoint()
{
    for(int i = 2; i >= 0; --i)
		for(int j = 2; j >= 0; --j)
			if(Map[i][j] != MAP_BLOCK)
			{
				Sp.x = i;
				Sp.y = j;
				cout<<"start: ( "<<i<<" , "<<j<<" )"<<endl;
				Map[Sp.x][Sp.y] = MAP_START;
				i = -1;
				j = -1;
			}
    for(int i = NUM_MAX_GRID-1; i >= NUM_MAX_GRID-3; --i)
		for(int j = NUM_MAX_GRID-1; j >= NUM_MAX_GRID-3; --j)
			if(Map[i][j] != MAP_BLOCK)
			{
				Ep.x = i;
				Ep.y = j;
				cout<<"end: ( "<<i<<" , "<<j<<" )"<<endl;
				Map[Ep.x][Ep.y]=MAP_END;
				return;
			}
}

// 打印地图情况
void HMap::ShowMap()
{
	cout<<"START:( "<<Sp.x<<","<<Sp.y<<" )"<<endl;
	cout<<"STOP:( "<<Ep.x<<","<<Ep.y<<" )"<<endl;
	const char SPACE[8] = "    ";
	cout<<SPACE;
	for(int i = UP.x; i < DOWN.x; ++i)
		cout<<i<<SPACE;
	cout<<endl;
	for(int i = UP.x; i < DOWN.x; ++i)
	{
		cout<<i<<SPACE;
		for(int j = UP.y; j < DOWN.y; ++j)
		{
			if(Map[i][j]!=MAP_BLOCK && Map[i][j]!=MAP_NONBLOCK)
			{
			    #ifdef _WIN32
				SetTextColor(FOREGROUND_RED | FOREGROUND_INTENSITY);
				#endif
				cout<<Map[i][j]<<SPACE;
				#ifdef _WIN32
				SetTextColor(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
				#endif // _WIN32
			}
			else
				cout<<Map[i][j]<<SPACE;
		}
		cout<<endl<<endl;
	}
	cout<<endl<<"======================================================="
		<<endl;
}

其它文件

“main”

#include <iostream>
#include "HMap.h"
#include "GeGroup.h"
using namespace std;

int main()
{
	HMap amap;
	while(1)
    {
        amap.InitMap();
        GeGroup ge(amap);
        ge.Epoch();
        Sleep(2000);
    }

}

“Global.h”

#ifndef _GLOBAL_HBB_
#define _GLOBAL_HBB_

#include <stdlib.h>
#include <stdio.h>
// 全局变量的定义
const int NUM_MAX_STEP = 20;
const int NUM_MAX_GRID = 10;
const char MAP_BLOCK = 'X';
const char MAP_NONBLOCK = '.';
const char MAP_LOAD = 'O';
const char MAP_START = 'S';
const char MAP_END = 'E';
//  generic code for direction
const int LEN_BIT_CODE = 3; // 2^3 =8 direction
const int LEN_BIT_ROUTE = 120;//DirBitLen*MAX_SEARCH_NUM;
// generic group num
const int NUM_GEGROUP = 200;

// cross relative parameter
const int RATE_CROSSOVER = 7; // 10 is max
const int RATE_MUTATION = 10; // 1000 is Max

inline int RandInt(const int MinV, const int MaxV){return rand()%(MaxV-MinV+1) + MinV;}

#ifdef _WIN32
#include <windows.h>
#include <time.h>
#include <conio.h>
#include "ConsoleUtils.h"
//default text colors can be found in wincon.h
inline void SetTextColor(WORD colors)
{
	HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);

	SetConsoleTextAttribute(hConsole, colors);
}
inline void PressAnyKeyToContinue()
{
    printf("\n\nPress any key to continue\n");
    while(!_kbhit()){}
    return;
}
#else
#include <unistd.h>
#include <sys/time.h>
#define Sleep(s) sleep(s/1000)
#endif

#endif // _GLOBAL_HBB_

结果

寻路前的地图:

《基于遗传算法的寻路模拟》

寻路后:

《基于遗传算法的寻路模拟》

总结

上面的寻路计算到了19代, 花费的时间与A*寻路相比要长很多, 有时还会出现找不到路径的情况;

遗传算法在解决一些问题上是个不错的选择,但显然不适合用来寻路,但作为一个应用学习例子还是很不错的;

    原文作者:遗传算法
    原文地址: https://blog.csdn.net/bbhe_work/article/details/50605173
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞