165 lines
5.2 KiB
C++
165 lines
5.2 KiB
C++
#include "chess.hpp"
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <random>
|
|
|
|
std::default_random_engine generator;
|
|
|
|
void InitializeGenerator(void) {
|
|
generator.seed(std::random_device{}());
|
|
}
|
|
|
|
int GenerateRandomNumber(int generationLimit) {
|
|
int generatedNumber;
|
|
std::uniform_int_distribution<> distribution(0, generationLimit - 1);
|
|
generatedNumber = distribution(generator);
|
|
return generatedNumber;
|
|
}
|
|
|
|
GeneticRules::GeneticRules(void) {
|
|
boardSize = 4;
|
|
populationSize = 8;
|
|
}
|
|
|
|
GeneticRules::GeneticRules(unsigned int boardSize, unsigned int populationSize) {
|
|
this->boardSize = boardSize;
|
|
this->populationSize = populationSize;
|
|
}
|
|
|
|
Individual::Individual(const unsigned int boardSize) {
|
|
// population init part of vector resize
|
|
board.resize(boardSize, 0);
|
|
for (int i = 0; i < board.size(); ++i) {
|
|
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) {
|
|
for (int i : board) {
|
|
std::cout << '[';
|
|
for (int j = 0; j < board.size(); ++j) {
|
|
if (j == i) { std::cout << "Q"; }
|
|
else { std::cout << ' '; }
|
|
}
|
|
std::cout << ']';
|
|
std::cout << std::endl;
|
|
}
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
// Gets the fitness of the population
|
|
unsigned int Individual::GetFitness(void) {
|
|
unsigned int fitness = 0;
|
|
for (unsigned int i : board) {
|
|
if (!IsQueenThreatened(i)) { fitness++; }
|
|
}
|
|
return fitness;
|
|
}
|
|
|
|
// Checks if the passed in queen is threatened on the board
|
|
// Impossible for queens to be threatened by same row
|
|
bool Individual::IsQueenThreatened(const int queenRow) {
|
|
int queenCol = board.at(queenRow);
|
|
int diffRow, diffCol;
|
|
for (int row = 0; row < board.size(); ++row) {
|
|
if (row == queenRow) { continue; }
|
|
diffCol = abs(queenCol - (int)board.at(row));
|
|
diffRow = abs(queenRow - row);
|
|
if (diffCol == 0) { return true; } // Column threat
|
|
if (diffCol == diffRow) { return true; }
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void PrintPopulation(std::vector<Individual> population) {
|
|
for (int i = 0; i < population.size(); ++i) {
|
|
std::cout << "Individual " << i << ':' << std::endl;
|
|
population[i].Print();
|
|
}
|
|
}
|
|
|
|
//
|
|
void Selection(std::vector<Individual> &population, std::vector<int> &selected) {
|
|
std::vector<int> 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<Individual> &population, std::vector<int> &selected, const GeneticRules genetics) {
|
|
double crossover_roll;
|
|
int crossover_locus;
|
|
std::vector<Individual> 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<Individual> &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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|