diff --git a/src/chess.cpp b/src/chess.cpp index 9c7f59f..8b76a75 100644 --- a/src/chess.cpp +++ b/src/chess.cpp @@ -18,7 +18,7 @@ int GenerateRandomNumber(int generationLimit) { GeneticRules::GeneticRules(void) { boardSize = 4; - populationSize = 1; + populationSize = 8; } GeneticRules::GeneticRules(unsigned int boardSize, unsigned int populationSize) { @@ -27,18 +27,21 @@ GeneticRules::GeneticRules(unsigned int boardSize, unsigned int populationSize) } Individual::Individual(const unsigned int boardSize) { - generationCount = 0; - InitializeGenerator(); // population init part of vector resize board.resize(boardSize, 0); for (int i = 0; i < board.size(); ++i) { - board.at(i) = GenerateRandomNumber(boardSize); + board.at(i) = 0; } } +void Individual::Init(const unsigned int boardSize) { + for (int i = 0; i < board.size(); ++i) { + board.at(i) = GenerateRandomNumber(boardSize); + } + +} void Individual::Print(void) { - std::cout << generationCount << ':' << std::endl; for (int i : board) { std::cout << '['; for (int j = 0; j < board.size(); ++j) { @@ -48,6 +51,7 @@ void Individual::Print(void) { std::cout << ']'; std::cout << std::endl; } + std::cout << std::endl; } // Gets the fitness of the population @@ -56,97 +60,9 @@ unsigned int Individual::GetFitness(void) { for (unsigned int i : board) { if (!IsQueenThreatened(i)) { fitness++; } } - std::cout << fitness << std::endl; return fitness; } -// -void Individual::Selection(void) { - /* TODO: Finish selection - int fitness[N] = {0}; - int fitness_sum = 0; - int i, j; - // get fitness for all members of population - for ( i=0; i population) { + for (int i = 0; i < population.size(); ++i) { + std::cout << "Individual " << i << ':' << std::endl; + population[i].Print(); + } +} + +// +void Selection(std::vector &population, std::vector &selected) { + std::vector fitness(population.size(), 0); + int fitness_sum = 0; + // get fitness for all members of population + + for (int i = 0; i < population.size(); ++i ){ + fitness.at(i) = population.at(i).GetFitness(); + fitness_sum += fitness.at(i); + } + + + // this is simple fitness proportional selection + // (roulette wheel sampling) + int roll; + int temp_sum = 0; + int selection; + for (int i = 0; i < population.size(); ++i) { + temp_sum = 0; + roll = GenerateRandomNumber(fitness_sum); + for (int j = 0; j < population.size(); j++){ + temp_sum += fitness.at(j); + if ( roll < temp_sum ){ + selection = j; + break; + } + } + selected.at(i) = selection; + } +} + +// Crossover on the population +void Crossover(std::vector &population, std::vector &selected, const GeneticRules genetics) { + double crossover_roll; + int crossover_locus; + std::vector temp_population(genetics.populationSize, genetics.boardSize); + for (int i = 0; i < genetics.populationSize; i +=2) { + crossover_roll = ((double) GenerateRandomNumber(RAND_MAX)) / ((double) RAND_MAX); + if (crossover_roll <= genetics.kProbabilityCrossover) { //crossover + crossover_locus = GenerateRandomNumber(genetics.boardSize); + for (int j = 0; j < crossover_locus; ++j) { + temp_population.at(i).board.at(j) = population.at(selected.at(i)).board.at(j); + temp_population.at(i+1).board.at(j) = population.at(selected.at(i+1)).board.at(j); + } + for (int j = crossover_locus; j < genetics.boardSize; ++j) { + temp_population.at(i).board.at(j) = population.at(selected.at(i+1)).board.at(j); + temp_population.at(i+1).board.at(j) = population.at(selected.at(i)).board.at(j); + } + } + else { //clone + for (int j = 0; j < genetics.boardSize; ++j) { + temp_population.at(i).board.at(j) = population.at(selected.at(i)).board.at(j); + temp_population.at(i+1).board.at(j) = population.at(selected.at(i+1)).board.at(j); + } + } + } + + //copy back to population + for (int i = 0; i < population.size(); i++) { + population[i] = temp_population[i]; + } +} + +// Mutates the population +void Mutation(std::vector &population, const GeneticRules genetics) { + double mutation_roll; + int i, j; + for (i = 0; i < population.size(); ++i){ + for (j = 0; j < population[0].board.size(); ++j ){ + mutation_roll = ((double) GenerateRandomNumber(RAND_MAX)) / ((double) RAND_MAX); + if (mutation_roll <= genetics.kProbabilityMutation){ + population[i].board.at(j) = GenerateRandomNumber(population[0].board.size()); //toggle bit + } + } + } +} + diff --git a/src/chess.hpp b/src/chess.hpp index f96ba1c..687474c 100644 --- a/src/chess.hpp +++ b/src/chess.hpp @@ -7,8 +7,8 @@ void InitializeGenerator(void); int GenerateRandomNumber(int generationLimit); struct GeneticRules { - const float kProbabilityCrossover = 0.7; //crossover probability (typical val.) - const float kProbabilityMutation = 0.001; //mutation probability (typical val.) + const double kProbabilityCrossover = 0.7; //crossover probability (typical val.) + const double kProbabilityMutation = 0.001; //mutation probability (typical val.) const unsigned int generationLimit = 10000; //number of generations (something huge) unsigned int boardSize; //board size unsigned int populationSize; //population size (change to something even) @@ -19,15 +19,17 @@ struct GeneticRules { class Individual { public: std::vector board; - int generationCount; Individual(const unsigned int boardSize); + void Init(const unsigned int boardSize); void Print(void); unsigned int GetFitness(void); - void Selection(void); - void Crossover(void); - void Mutation(void); private: bool IsQueenThreatened(const int queenRow); }; +void PrintPopulation(std::vector population); +void Selection(std::vector &population, std::vector &selected); +void Crossover(std::vector &population, std::vector &selected, const GeneticRules genetics); +void Mutation(std::vector &population, const GeneticRules genetics); + #endif // CHESS_HPP diff --git a/src/n_queens.cpp b/src/n_queens.cpp index 366bcfd..0236596 100644 --- a/src/n_queens.cpp +++ b/src/n_queens.cpp @@ -1,13 +1,39 @@ #include "chess.hpp" #include "genetic_algorithm.hpp" +#include +#include #include -int main() { +int main(int argc, char* argv[]) { + InitializeGenerator(); GeneticRules genetics; - std::vector population; - Individual person(genetics.boardSize); - person.Print(); - person.GetFitness(); + if (argc == 2) { genetics.boardSize = atoi(argv[1]); } + std::cout << "argc: " << argc << std::endl; + std::vector population(genetics.populationSize, genetics.boardSize); + for (int i = 0; i < genetics.populationSize; ++i) { population[i].Init(genetics.boardSize); } + std::vector selected(genetics.populationSize, -1); + int generationCount = 0; + std::cout << generationCount << ':' << std::endl; + PrintPopulation(population); + + while (generationCount < genetics.generationLimit) { + Selection(population, selected); + Crossover(population, selected, genetics); + Mutation(population, genetics); + std::cout << generationCount << ':' << std::endl; + PrintPopulation(population); + for (auto i : population) { + if (i.GetFitness() == genetics.boardSize) { + std::cout << "Max fit reached." << std::endl; + return 0; + } + } + ++generationCount; + } + if (generationCount == genetics.generationLimit) { + std::cout << "Generation limit reached." << std::endl; + } + return 0; /* unsigned char population[N] = {0}; @@ -21,21 +47,21 @@ int main() { init_population(population); print_population(population); - while (generation_count < G) { + while( generation_count < G ){ do_selection(population, selected); do_crossover(population, selected); do_mutation(population); printf("%4d: ", generation_count); print_population(population); - for (i = 0; i < N; i++) { - if (population[i] == 0xFF) { + for( i=0; i