n-queens/src/chess.cpp

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
}
}
}
}