遺傳算法的一個小例子,純屬娛樂

初始一個羣落,要求羣落最終從入口移動到出口,例子來源於《遊戲編程中的人工智能技術》一書,並會有所改變。

  • 變異會改變基因樣式和長度
  • 雜交採用輪盤法選取父母
#include <iostream>
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <ctime>
#include <algorithm>
using namespace std;
using namespace cv;
struct Individual //個體
{
    vector<int> gene;
    int gene_num;
    int dFitness;

    int pos_x;
    int pos_y;

    Individual():gene_num(0),dFitness(0){pos_x = 2;pos_y =0;}
    Individual(const int num_bits):gene_num(num_bits),dFitness(0)
    {
        //創造隨機二進制位串
        // srand((unsigned)time(0));
        pos_x = 2;pos_y =0;
        for (int i=0; i<num_bits; ++i)
        {
            int a = rand()%4;
            gene.push_back(a);
        }
    }
};  

class CBobMap
{
    private:
        static const int MAP_H = 10;
        static const int MAP_W = 15;

        static const int StartX = 2;
        static const int StartY = 0;

        static const int EndX = 7;
        static const int EndY = 14;
    public:
        static const int map[MAP_H][MAP_W];
        // int gene[MAP_H][MAP_W];

        CBobMap(){
        }

        int Adapt_Score(Individual& ind)
        {
            vector<int> vecPath = ind.gene;
            int sta_x = StartX;
            int sta_y = StartY;

            int ret =0;

            for(auto it =vecPath.begin();it!=vecPath.end();it++)
            {
                switch(*it)
                {
                    case 3:
                    {
                        if(sta_y-1>=0)
                        {
                            if(map[sta_x][sta_y-1]!=1)
                            {    sta_y --;
                            }
                        }
                    }
                    break;
                    case 2:
                    {
                        if(sta_y+1<15)
                        {
                            if(map[sta_x][sta_y+1]!=1)
                            {    sta_y ++;}
                        }
                    }
                    break;
                    case 1:
                    {
                        if(sta_x+1<10)
                        {
                            if(map[sta_x+1][sta_y]!=1)
                            {
                                sta_x ++;
                            }
                        }
                    }
                    break;
                    case 0:
                    {
                        if(sta_x-1>=0)
                        {
                            if(map[sta_x-1][sta_y]!=1)
                            {
                                sta_x --;
                            }
                        }
                    }
                    break;
                    default:
                    break;
                }
                ret += abs(EndX-sta_x) + abs(EndY - sta_y);
            }
            ind.pos_x = sta_x;
            ind.pos_y = sta_y;
            ind.dFitness = ret;
            return ind.dFitness;
        }
};
const int CBobMap::map[MAP_H][MAP_W] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
                                        1,0,1,0,0,0,0,0,1,1,1,0,0,0,1,
                                        5,0,0,0,0,0,0,0,1,1,1,0,0,0,1,
                                        1,0,0,0,1,1,1,0,0,1,0,0,0,0,1,
                                        1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,
                                        1,1,0,0,1,1,1,0,0,0,0,0,1,0,1,
                                        1,0,0,0,0,1,0,0,0,0,1,1,1,0,1,
                                        1,0,1,1,0,0,0,1,0,0,0,0,0,0,8,
                                        1,0,1,1,0,0,0,1,0,0,0,0,0,0,1,
                                        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };

class Community //羣落
{
    private:
        vector<Individual> community;
        vector<int> AdaptScores;
        const static int community_size; 
        int AdaptScore_sum; 
        const static double Mutate_Ratio;  //突變率
        const static double Crossover_Ratio; //雜交率
        CBobMap Map;
    public:
        void Mutate()
        {
            random_shuffle(community.begin(),community.end());
            for(int i=0;i<community_size*Mutate_Ratio*6;i++)
            {
                int postion = rand()%(community[i].gene.size());
                community[i].gene[postion] = rand()&0x03;
                community[i].gene.push_back(rand()&0x03);
                community[i].gene_num = community[i].gene.size();
            }
        }

        void Crossover()
        {
            vector<Individual> com_;
            com_.resize(community_size);

            for(int i=0;i<community_size;i+=2)
            {
                Individual father,mother;
                RouletteWheelSelection(father,mother);

                unsigned int position = rand()%father.gene_num;
                vector<int> gene_temp = father.gene;
                father.gene.resize(mother.gene_num);
                for(unsigned int i=0;i<position && i<father.gene.size();i++)
                {
                    father.gene[i] = gene_temp[i];
                }
                for(unsigned int i=position;i<father.gene.size();i++)
                {
                    father.gene[i] = mother.gene[i];
                }            
                mother.gene.resize(gene_temp.size());
                for(unsigned int i=position;i<mother.gene.size();i++)
                {
                    mother.gene[i] = gene_temp[i];
                }
                com_[i]= father;
                com_[i+1]=mother;
            }
            community = com_;
        }

        void RouletteWheelSelection(Individual& Father,Individual& Mother)
        {
            int father = rand()%AdaptScore_sum;
            auto it = community.begin();
            int sum=0;
            for(;it!=community.end();it++)
            {      
                sum+=(it->dFitness);          
                if(sum>father)
                {
                    Father = *it;
                    break;
                } 
            }
            auto it_father= it;
            int mother = rand()%(AdaptScore_sum- it_father->dFitness);
            it = community.begin();
            sum=0;
            for(;it!=community.end();it++)
            {      
                sum+=(it->dFitness);          
                if(sum>mother && it!=it_father)
                {
                    Mother = *it;
                    break;
                } 
            }
        }

        Community():AdaptScore_sum(0)
        {
            community.resize(community_size);
            AdaptScores.resize(community_size);
            for(int i=0;i<community_size;i++)
            {
                AdaptScores[i]=0;
                Individual a(10);
                community[i]=a;
            }        
        }

        void run()
        {
            for(int generation=0;generation<2000;generation++)
            {         
                int Score_max = 0;
                for(auto it= community.begin();it!=community.end();it++)
                {
                    int score = Map.Adapt_Score(*it);   
                    if(score>Score_max)
                        Score_max = score;               
                }
                AdaptScore_sum=0;
                for(auto it= community.begin();it!=community.end();it++)
                {
                    it->dFitness = Score_max+5 - it->dFitness;
                    AdaptScore_sum += it->dFitness;
                }

                bool cap[10][15]={0};
                for(auto it= community.begin();it!=community.end();it++)
                {
                    cap[it->pos_x][it->pos_y] = true;                    
                }
                Mat img(10,15,CV_8UC1);
                for(int i=0;i<10;i++)
                    for(int j=0;j<15;j++)
                    {
                        if(CBobMap::map[i][j]==1)
                        {
                            uchar *data = img.ptr<uchar>(i);
                            data[j] = 0;
                        }
                        else if(cap[i][j])
                        {
                            uchar *data = img.ptr<uchar>(i);
                            data[j] = 155;
                        }
                        else 
                        {
                            uchar *data = img.ptr<uchar>(i);
                            data[j] = 255;
                        }
                    }
                imshow("HJ",img);
                waitKey(10);
                Crossover();
                Mutate();
            }
        }

};

const double Community::Mutate_Ratio = 0.001;  //突變率
const double Community::Crossover_Ratio = 0.7; //雜交率
const int Community::community_size=1000; 

int main()
{
    Community Com;
    Com.run();
    return 1;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章