#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <iostream>
 
using namespace std;
 
#define GeneNumber        4                 // 基因長度
#define PopulationSize    10                // 母群數量
#define MaxGeneration     100               // 迭代次數
#define CrossoverRate     0.7               // 交配率
#define MutationRate      0.1               // 突變率
 
class parent{
public: 
        int genes[GeneNumber];
        double fitness;
        double dec_value;
};
 
// PositionRand(): 隨機取得(交配點/突變位置)
#define PositionRand()           (rand()%GeneNumber)
// BinaryRand():  隨機產生0~1整數(無小數)for(產生基因)
#define BinaryRand()            (rand()%2)
// PointRand():   隨機產生0~1 的亂數(有小數)for(交配/突變率)
#define PointRand()             ((double)rand()/(double)RAND_MAX)
 
// =====================================================
 
// 進行初始化
void initialize();           
// 輪盤式選擇(隨機式)
void CrossoverPool();   
// 交配, 交配池中的個體進行交配(兩點交配)
void crossover();           
// 突變, 逐一bit 慢慢確認突變
void mutation();
// 計算基因所對應之適應值
void cal_fitness(parent *x);     
// 計算基因對應之進制值
void cal_Decimal(parent *x);     
// 讓交配點的第二點永遠比第一點大
void swap(int *x,int *b);
 
 
// =====================================================
 
parent population[PopulationSize];      // 母體數量
parent pool[PopulationSize];            // 交配池
parent best_gene;                       // 從以前到現在最好的基因
 
 
// binary 2 dec，將染色體中的二進位(genes) ，轉為十進位(dec_value)
void cal_Decimal(parent *x)
{
        int i,j = 0;
        double dec = 0;
        for(i=GeneNumber-1; i >= 0; i--){
                dec += x->genes[i]*pow((double)2,j);
                j++;
        }
        x->dec_value = dec;
}
 
//計算適應值 適應函數為31i-i*i
void cal_fitness(parent *x)
{    
     double i = x->dec_value;
     x->fitness = 31*i - i*i;
}
 
//將a,b兩數互換，讓起始數永遠比終點數小
void swap(int *a,int *b)
{
        int x;
        x = *a;
        *a = *b;
        *b = x;
}
 
//初始化
void initialize()
{
     int i, j,x,y;
         for(i=0; i<PopulationSize; i++){
                 for(j=0; j<GeneNumber; j++){
                         // 每個母體的基因都是隨機給/1
                         population[i].genes[j] = BinaryRand();
                 }
         }
 
         // 計算母體基因之進制值
         for(x = 0; x < PopulationSize; x++){
                 cout <<x <<" : bin = ";
                 for(y = 0; y < GeneNumber; y++){
                         cout << population[x].genes[y];
                 }
 
                 cout << '\n';
                 //計算十進位之值並輸出
                 cal_Decimal(&population[x]);
                 cout << "Dec = " << population[x].dec_value << '\n';
                 //計算適應並變輸出
                 cal_fitness(&population[x]);
                 cout << "Fitness = "<< population[x].fitness << '\n';
                 //更新最佳基因
                 if(x==0)
                                 best_gene = population[0];
                 else if(population[x].fitness > best_gene.fitness)
                         best_gene = population[x];
                 cout << "best_gene = "<< best_gene.fitness << '\n';
                 cout << "======================================="<< '\n';
 
         }
}
//輪盤式選擇
void CrossoverPool()
{
        int i,j;
        double FitnessSum = 0;//適應值總和
        double Fitness_percent[PopulationSize];//每個基因的適應值所占整體的比例
        double Fitness_percent_total=0;
        int pickup;//抽取個體 
        //計算適應值總和並輸出
        for(i=0; i < PopulationSize; i++){
                FitnessSum += population[i].fitness;
        }
        cout << "FitnessSum = "<< FitnessSum <<'\n';
        //計算每個基因的適應值佔總合多少比例並輸出
        for(i=0; i < PopulationSize; i++){
                Fitness_percent[i] = population[i].fitness / FitnessSum;
                cout << "Fitness_percent = " << Fitness_percent[i]<< '\n';
                Fitness_percent_total+=Fitness_percent[i];
        }        
        cout << "Fitness_percent_total = " << Fitness_percent_total << '\n';
        //選擇基因丟入交配池
        for(i=0; i < PopulationSize; i++){
                pickup = rand()%PopulationSize;
                cout << i << " : Pool = ";
                for(j=0; j < GeneNumber; j++){
                        pool[i].genes[j] = population[pickup].genes[j];
                        cout << pool[i].genes[j];
                }
                cout << '\n';
        }  
}
//兩點交配
void crossover()
{
        int i,j;
        int PartOfComplete=0;//完成數目
        int p1,p2;//交配池中的隨機兩組基因
        int pos1=0,pos2=0;//交換點由pos1~pos2
        double CrossoverProbability;//交配機率
 
 
 
        //重複執行直到交配完10組個體
        while(PartOfComplete < PopulationSize){
                //隨機選擇兩個個體
                p1 = rand() % PopulationSize;
                do{ p2 = rand() % PopulationSize;}while(p2 == p1);
                CrossoverProbability=PointRand();       
                cout << "CrossoverProbability = " << CrossoverProbability << '\n';
                
                //交配
                if(CrossoverProbability < CrossoverRate){
                        pos1=PositionRand();            
                        do{
                                pos2=PositionRand();
                        }while(pos2 == pos1 || ((pos1 == 0 || pos1 == GeneNumber-1) && (pos1+pos2 == GeneNumber-1)));
                        //↑↑↑↑↑判斷機制pos1:pos1與pos2不可為同值且pos1與pos2不可同時為第一點與最後一點↑↑↑↑↑
                        cout << "pos1 = "<< pos1 <<" pos2 = "<< pos2 << '\n';                   
                        //強制由左往右做區域的選取
                        if(pos1>pos2)
                                swap(&pos1,&pos2);
                        cout << "pos1 = " << pos1 <<" pos2 = " << pos2 << '\n';
                        cout << "p1 = " << p1 <<" p2 = " << p2 << '\n';
 
                        //第一階段交配
                        for(i=0; i<pos1; i++){
                                population[PartOfComplete].genes[i]=pool[p1].genes[i];
                                population[PartOfComplete+1].genes[i]=pool[p2].genes[i];
                        }
                        //第二階段交配
                        for(i=pos1; i<=pos2; i++){
                                population[PartOfComplete+1].genes[i]=pool[p1].genes[i];
                                population[PartOfComplete].genes[i]=pool[p2].genes[i];
                        }
                        //第三階段交配
                        for(i=pos2+1; i<GeneNumber; i++){
                                population[PartOfComplete].genes[i]=pool[p1].genes[i];
                                population[PartOfComplete+1].genes[i]=pool[p2].genes[i];
                        }
                        //輸出交配後的二進制之值
                        for(i = 0; i < PopulationSize; i++){
                                cout <<i <<" : bin = ";
                                for(j = 0; j < GeneNumber; j++){
                                        cout << population[i].genes[j];
                                }
                                cout << '\n';
                        }
                        //進行下面兩個個體的交配
                        PartOfComplete+=2;
                }
        }
}
//突變
void mutation()
{
        int i,j;
        int pos;//突變點
        double MutationProbability;//突變機率
        for(i = 0; i < PopulationSize; i++){
                MutationProbability = PointRand();
                cout << "MutationProbability = "<< MutationProbability <<'\n';
                //是否發生突變
                if(MutationProbability < MutationRate){
                        //突變點
                        pos = PositionRand();
                        //做突變點的突變處理
                        population[i].genes[pos] = !population[i].genes[pos];
                        cout<<"pos = "<< pos <<'\n';
                }
                cout << i <<" : bin = ";
                for(j = 0; j < GeneNumber; j++){
                        cout << population[i].genes[j];
                }
                cout << '\n';
                //計算十進制之值並輸出
                cal_Decimal(&population[i]);
                cout << "Dec = " << population[i].dec_value << '\n';
                //計算適應值並輸出
                cal_fitness(&population[i]);
                cout << "Fitness = "<< population[i].fitness << '\n';
                //更新最佳基因
                if(population[i].fitness > best_gene.fitness)
                        best_gene = population[i];
                cout << "best_gene = "<< best_gene.fitness << '\n';
                cout << "======================================="<< '\n';
        }       
}
 
 
int main()
{
        srand((unsigned)time(NULL));
        initialize();            // 初始化
                cout<<'\n';
        CrossoverPool();                //分配式選擇
                cout<<'\n'; 
        crossover();                    //兩點交配
                cout<<'\n';
        mutation();                             //突變
                cout<<'\n';
                                cout << "best_gene = "<< best_gene.fitness << '\n';
 
        system("pause");
}
 