Compare commits
2 Commits
c872462c97
...
99e99d9233
Author | SHA1 | Date | |
---|---|---|---|
99e99d9233 | |||
8f62df2f1f |
@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(
|
||||
n-queens
|
||||
n_queens
|
||||
LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11 CACHE STRING "The C++ standard to use")
|
||||
|
@ -1,6 +1,8 @@
|
||||
add_executable(n-queens
|
||||
./n-queens.cpp
|
||||
add_executable(n_queens
|
||||
./n_queens.cpp
|
||||
./chess.cpp
|
||||
./genetic_algorithm.cpp
|
||||
)
|
||||
|
||||
target_include_directories(n-queens PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_include_directories(n_queens PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
|
90
src/chess.cpp
Normal file
90
src/chess.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "chess.hpp"
|
||||
#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;
|
||||
}
|
||||
|
||||
GeneticDefaults::GeneticDefaults(void) {
|
||||
size = 8;
|
||||
length = 8;
|
||||
}
|
||||
|
||||
GeneticDefaults::GeneticDefaults(unsigned int size, unsigned int length) {
|
||||
this->size = size;
|
||||
this->length = length;
|
||||
}
|
||||
|
||||
GeneticChess::GeneticChess(void) {
|
||||
generationCount = 0;
|
||||
InitializeGenerator();
|
||||
// population init part of vector resize
|
||||
board.resize(genetics.size, 0);
|
||||
for (int i = 0; i < board.size(); ++i) {
|
||||
board.at(i) = GenerateRandomNumber(genetics.size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GeneticChess::Print(void) {
|
||||
std::cout << generationCount << ':' << std::endl;
|
||||
for (int i : board) {
|
||||
std::cout << '[';
|
||||
for (int j = 0; j < genetics.size; ++j) {
|
||||
if (j == i) { std::cout << "Q"; }
|
||||
else { std::cout << ' '; }
|
||||
}
|
||||
std::cout << ']';
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the fitness of the population
|
||||
unsigned int GeneticChess::GetFitness(void) {
|
||||
int fitness = 0;
|
||||
for (int i : board) {
|
||||
if (!IsQueenThreatened(i)) { fitness++; }
|
||||
}
|
||||
return fitness;
|
||||
}
|
||||
|
||||
//
|
||||
void GeneticChess::Selection(void) {
|
||||
|
||||
}
|
||||
|
||||
// Crossover on the population
|
||||
void GeneticChess::Crossover(void) {
|
||||
|
||||
}
|
||||
|
||||
// Mutates the population
|
||||
void GeneticChess::Mutation(void) {
|
||||
|
||||
}
|
||||
|
||||
// Checks if the passed in queen is threatened on the board
|
||||
// Impossible for queens to be threatened by same row
|
||||
bool GeneticChess::IsQueenThreatened(const unsigned int queenRow) {
|
||||
int queenCol = board.at(queenRow);
|
||||
int diffRow, diffCol;
|
||||
for (int i = 0; i < genetics.size; ++i) {
|
||||
if (i == queenRow) { continue; }
|
||||
diffCol = queenCol - board.at(i);
|
||||
diffRow = queenRow - i;
|
||||
if (diffCol == 0) { return true; } // Column threat
|
||||
if (diffCol == diffRow) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
34
src/chess.hpp
Normal file
34
src/chess.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef CHESS_HPP
|
||||
#define CHESS_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
void InitializeGenerator(void);
|
||||
int GenerateRandomNumber(int generationLimit);
|
||||
|
||||
struct GeneticDefaults {
|
||||
const float kProbabilityCrossover = 0.7; //crossover probability (typical val.)
|
||||
const float kProbabilityMutation = 0.001; //mutation probability (typical val.)
|
||||
const unsigned int generationLimit = 10000; //number of generations (something huge)
|
||||
unsigned int size; //population size (change to something even)
|
||||
unsigned int length; //string length (don't change)
|
||||
GeneticDefaults(void);
|
||||
GeneticDefaults(unsigned int size, unsigned int length); //custom generation sizes
|
||||
};
|
||||
|
||||
class GeneticChess {
|
||||
public:
|
||||
std::vector<unsigned int> board;
|
||||
GeneticDefaults genetics;
|
||||
int generationCount;
|
||||
GeneticChess(void);
|
||||
void Print(void);
|
||||
unsigned int GetFitness(void);
|
||||
void Selection(void);
|
||||
void Crossover(void);
|
||||
void Mutation(void);
|
||||
private:
|
||||
bool IsQueenThreatened(const unsigned int queenRow);
|
||||
};
|
||||
|
||||
#endif // CHESS_HPP
|
142
src/genetic_algorithm.cpp
Normal file
142
src/genetic_algorithm.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include "genetic_algorithm.hpp"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Prints the population strings in a line */
|
||||
void print_population(unsigned char population_in[]) {
|
||||
int iterator = 0;
|
||||
int member_count = 0;
|
||||
char cur_member;
|
||||
while (member_count < N){
|
||||
cur_member = population_in[member_count];
|
||||
while (iterator < L){
|
||||
if (cur_member & 0x80){
|
||||
printf("1");
|
||||
}
|
||||
else{
|
||||
printf("0");
|
||||
}
|
||||
cur_member = cur_member << 1;
|
||||
iterator++;
|
||||
}
|
||||
member_count++;
|
||||
iterator = 0;
|
||||
printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Fitness is determined by the number of
|
||||
1's in the bitstring. */
|
||||
int get_fitness(unsigned char string_in){
|
||||
int count = 0;
|
||||
unsigned char temp = string_in;
|
||||
while (temp){
|
||||
if (temp & 0x01){
|
||||
count++;
|
||||
}
|
||||
temp = temp >> 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Randomly initialize the first population */
|
||||
void init_population(unsigned char* population){
|
||||
int i;
|
||||
for ( i=0; i<N; i++){
|
||||
population[i] = (char)(rand() % 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform selection of population members based on fitness */
|
||||
void do_selection(unsigned char* population, int* selected){
|
||||
int fitness[N] = {0};
|
||||
int fitness_sum = 0;
|
||||
int i, j;
|
||||
// get fitness for all members of population
|
||||
for ( i=0; i<N; i++ ){
|
||||
fitness[i] = get_fitness(population[i]);
|
||||
fitness_sum += fitness[i];
|
||||
}
|
||||
|
||||
|
||||
// this is simple fitness proportional selection
|
||||
// (roulette wheel sampling)
|
||||
int roll;
|
||||
int temp_sum = 0;
|
||||
int selection;
|
||||
for ( i=0; i<N; i++ ){
|
||||
temp_sum = 0;
|
||||
roll = rand()%fitness_sum;
|
||||
for ( j=0; j<N; j++ ){
|
||||
temp_sum += fitness[j];
|
||||
if ( roll < temp_sum ){
|
||||
selection = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
selected[i] = selection;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute a mask to use when crossing over parents*/
|
||||
unsigned char get_mask(int locus_in){
|
||||
int i = 0;
|
||||
unsigned char ret;
|
||||
for( i=0; i<locus_in; i++ ){
|
||||
ret = ret << 1;
|
||||
ret ^= 0x01;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* crossover members with probability P_c
|
||||
if no crossover, then clone parents */
|
||||
void do_crossover(unsigned char* population, int* selected){
|
||||
double crossover_roll;
|
||||
int crossover_locus;
|
||||
int i;
|
||||
unsigned char temp1;
|
||||
unsigned char temp2;
|
||||
unsigned char mask;
|
||||
unsigned char temp_population[N];
|
||||
|
||||
for ( i=0; i<N; i+=2){
|
||||
crossover_roll = ((double)rand())/((double)RAND_MAX);
|
||||
temp1 = 0;
|
||||
temp2 = 0;
|
||||
if(crossover_roll <= P_c){ //crossover
|
||||
crossover_locus = rand()%L;
|
||||
mask = get_mask(crossover_locus);
|
||||
temp1 = population[selected[i]] & mask;
|
||||
temp1 ^= population[selected[i+1]] & ~mask;
|
||||
temp2 = population[selected[i+1]] & mask;
|
||||
temp2 ^= population[selected[i]] & ~mask;
|
||||
temp_population[i] = temp1;
|
||||
temp_population[i+1] = temp2;
|
||||
}
|
||||
else{ //clone
|
||||
temp_population[i] = population[selected[i]];
|
||||
temp_population[i+1] = population[selected[i+1]];
|
||||
}
|
||||
}
|
||||
|
||||
//copy back to population
|
||||
for ( i=0; i<N; i++ ){
|
||||
population[i] = temp_population[i];
|
||||
}
|
||||
}
|
||||
|
||||
void do_mutation(unsigned char* population){
|
||||
double mutation_roll;
|
||||
int i, j;
|
||||
for ( i=0; i<N; i++){
|
||||
for ( j=0; j<L; j++ ){
|
||||
mutation_roll = ((double)rand())/((double)RAND_MAX);
|
||||
if ( mutation_roll <= P_m ){
|
||||
population[i] ^= (1<<j); //toggle bit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
src/genetic_algorithm.hpp
Normal file
19
src/genetic_algorithm.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef GENETIC_ALGORITHM_HPP
|
||||
#define GENETIC_ALGORITHM_HPP
|
||||
|
||||
#define P_c 0.7 //crossover probability (typical val.)
|
||||
#define P_m 0.001 //mutation probability (typical val.)
|
||||
#define N 8 //population size (change to something even)
|
||||
#define L 8 //string length (don't change)
|
||||
#define G 10000 //number of generations (something huge)
|
||||
|
||||
void print_population(unsigned char population_in[]);
|
||||
int get_fitness(unsigned char string_in);
|
||||
void init_population(unsigned char* population);
|
||||
void do_selection(unsigned char* population, int* selected);
|
||||
unsigned char get_mask(int locus_in);
|
||||
void do_crossover(unsigned char* population, int* selected);
|
||||
void do_mutation(unsigned char* population);
|
||||
|
||||
#endif // GENETIC_ALGORITHM_HPP
|
||||
|
40
src/n_queens.cpp
Normal file
40
src/n_queens.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "chess.hpp"
|
||||
#include "genetic_algorithm.hpp"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
int main(){
|
||||
GeneticChess population;
|
||||
population.Print();
|
||||
|
||||
/*
|
||||
unsigned char population[N] = {0};
|
||||
int selected[N] = {-1};
|
||||
int generation_count = 0;
|
||||
int i;
|
||||
srand(time(NULL));
|
||||
|
||||
|
||||
//basic genetic algorithm skeleton
|
||||
init_population(population);
|
||||
print_population(population);
|
||||
|
||||
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) {
|
||||
printf("Max fit reached.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
generation_count++;
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user