diff --git a/Makefile b/Makefile index 1cd822d..ab21da2 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ SRCDIR = src TMPDIR = build TARGET = gross #FILES = Chromosome Fitness Generation main -FILES = Genes +FILES = Genes Chromosome #SOURCES = $(patsubst %,$(SRCDIR)/%.cpp,$(FILES)) OBJECTS = $(patsubst %,$(TMPDIR)/%.o,$(FILES)) diff --git a/src/Chromosome.cpp b/src/Chromosome.cpp index 59b3fde..5eacaf7 100644 --- a/src/Chromosome.cpp +++ b/src/Chromosome.cpp @@ -1,72 +1,57 @@ #include "Chromosome.hpp" -#include -#if __GNUC__ < 7 // gcc 7 will support clamp -namespace std { - template - T clamp(T v, T lo, T hi) - { - return std::min(hi, std::max(lo, v)); + + +std::minstd_rand* Chromosome::re; +std::unordered_set Chromosome::allowedGeneTypes; + + +void Chromosome::allowGeneType(GeneType gt, bool allowed) +{ + if (allowed) { + Chromosome::allowedGeneTypes.insert(gt); + } else { + Chromosome::allowedGeneTypes.erase(gt); } } -#endif - -#include -#include - -// #include -sf::Vector2f Chromosome::size(0, 0); -float Chromosome::stddev_position = .1; -float Chromosome::stddev_radius = .1; -float Chromosome::stddev_color = 20; -std::minstd_rand* Chromosome::re; - -sf::CircleShape Chromosome::circle; +bool Chromosome::isGeneTypeAllowed(GeneType gt) +{ + return Chromosome::allowedGeneTypes.find(gt) != Chromosome::allowedGeneTypes.end(); +} Chromosome::Chromosome() { - // this->genes is already empty - this->circle.setPointCount(36); + // empty so you can choose between crossover and creating a new chromosome } -Chromosome::Chromosome(Chromosome& father, Chromosome& mother) : - Chromosome() +Chromosome::Chromosome(Chromosome& father, Chromosome& mother) { - std::uniform_int_distribution<> booldist(0, 1); + auto split_father = father.selectGene(); + auto split_mother = mother.selectGene(); -// auto fpair = this->selectSegment(father.genes); -// auto mpair = this->selectSegment(mother.genes); + // reserve to father's size/capacity, and shrink_to_fit afterwards? -// auto cur_it = this->genes.begin(); -// std::cout << std::distance(cur_it, father.genes.begin()) << std::endl; -// std::cout << std::distance(cur_it, mother.genes.begin()) << std::endl; -// cur_it = this->genes.insert(cur_it, fpair.second, father.genes.end()); -// cur_it = this->genes.insert(cur_it, mpair.first, mpair.second); -// cur_it = this->genes.insert(cur_it, father.genes.begin(), fpair.first); + Gene* geneptr; + for (auto it=father.genes.begin(); it!=split_father; ++it) { + *geneptr = **it; + this->genes.push_back(std::unique_ptr(geneptr)); + } -// if (booldist(*Chromosome::re)) { -// this->genes.insert(this->genes.begin(), fpair.second, father.genes.end()); -// this->genes.insert(this->genes.begin(), mpair.first, mpair.second); -// this->genes.insert(this->genes.begin(), father.genes.begin(), fpair.first); -// } else { -// this->genes.insert(this->genes.begin(), mpair.second, mother.genes.end()); -// this->genes.insert(this->genes.begin(), fpair.first, fpair.second); -// this->genes.insert(this->genes.begin(), mother.genes.begin(), mpair.first); -// } - - auto gene_father = this->selectGene(father.genes); - auto gene_mother = this->selectGene(mother.genes); - - if (booldist(*Chromosome::re)) { - this->genes.insert(this->genes.begin(), father.genes.begin(), gene_father); - this->genes.insert(this->genes.begin(), gene_mother, mother.genes.end()); - } else { - this->genes.insert(this->genes.begin(), mother.genes.begin(), gene_mother); - this->genes.insert(this->genes.begin(), gene_father, father.genes.end()); + for (auto it=split_mother; it!=mother.genes.end(); ++it) { + *geneptr = **it; + this->genes.push_back(std::unique_ptr(geneptr)); + } +} + + +void Chromosome::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + for (auto& geneptr : this->genes) { + target.draw(*geneptr, states); } } @@ -74,159 +59,71 @@ Chromosome::Chromosome(Chromosome& father, Chromosome& mother) : void Chromosome::mutate() { std::uniform_int_distribution<> mutatedist(0, 1); // 1/2 of the time, it mutates everytime! - std::uniform_int_distribution<> choicedist(0, 12); + std::uniform_int_distribution<> choicedist(0, 11); + while (mutatedist(*Chromosome::re)) { int choice = choicedist(*Chromosome::re); - if (choice < 1) { // add -// std::cout << "Added circle" << std::endl; - this->genes.push_back(this->randomGene()); + if (choice < 1) this->addGene(); + else if (choice < 2) this->removeGene(); + else if (choice < 4) this->swapGenes(); + else this->mutateGene(); - } else if (choice < 2) { // remove -// std::cout << "Removed circle" << std::endl; - auto it = this->selectGene(this->genes); - if (it != this->genes.end()) { - this->genes.erase(it); - } - - } else if (choice < 4) { // swap // std::cout << "Swapped circles" << std::endl; - auto it_one = this->selectGene(this->genes); - auto it_two = this->selectGene(this->genes); - if (it_one != this->genes.end() && it_two != this->genes.end() && it_one != it_two) { - auto tmp = *it_one; - *it_one = *it_two; - *it_two = tmp; - } - - } else { // mutate -// std::cout << "Mutated circle" << std::endl; - auto it = this->selectGene(this->genes); - if (it != this->genes.end()) { - this->mutateGene(*it); - } - } +// std::cout << "Mutated circle" << std::endl; +// } } } -void Chromosome::draw(sf::RenderTarget& target, sf::RenderStates states) const -{ - this->circle.setPosition(0, 0); - this->circle.setRadius(Chromosome::size.x + Chromosome::size.y); - this->circle.setOrigin(Chromosome::size); - this->circle.setFillColor(sf::Color::White); - target.draw(this->circle, states); - - for (auto gene : this->genes) { - Chromosome::circle.setPosition(gene.position); - Chromosome::circle.setRadius(gene.radius); - Chromosome::circle.setOrigin(sf::Vector2f(gene.radius, gene.radius)); - Chromosome::circle.setFillColor(gene.color); - target.draw(Chromosome::circle, states); - } -} - - -size_t Chromosome::length() +size_t Chromosome::length() const { return this->genes.size(); } -float Chromosome::maxRadius() -{ - return std::min(Chromosome::size.x, Chromosome::size.y)/2; -} - - -Chromosome::Gene Chromosome::randomGene() -{ - float max_radius = this->maxRadius(); - std::uniform_real_distribution<> xdist(0, Chromosome::size.x); - std::uniform_real_distribution<> ydist(0, Chromosome::size.y); - std::uniform_real_distribution<> rdist(0, sqrt(max_radius)); - std::uniform_int_distribution<> colordist(0, 255); - - sf::Vector2f position(xdist(*Chromosome::re), ydist(*Chromosome::re)); - float radius = (pow(rdist(*Chromosome::re), 2)); - sf::Color color( - colordist(*Chromosome::re), - colordist(*Chromosome::re), - colordist(*Chromosome::re), - 150 - ); - - Chromosome::Gene gene; - gene.position = position; - gene.radius = radius; - gene.color = color; - - return gene; -} - - -void Chromosome::mutateGene(Gene& gene) -{ - std::uniform_int_distribution<> booldist(0, 1); - float max_radius = this->maxRadius(); - - if (booldist(*Chromosome::re)) { // position - std::normal_distribution<> posdist(0, Chromosome::stddev_position); - gene.position.x = std::clamp( - gene.position.x + posdist(*Chromosome::re)*max_radius, - 0, - Chromosome::size.x - ); - gene.position.y = std::clamp( - gene.position.y + posdist(*Chromosome::re)*max_radius, - 0, - Chromosome::size.y - ); - } - - if (booldist(*Chromosome::re)) { // radius - std::normal_distribution<> raddist(0, Chromosome::stddev_radius); - gene.radius = std::clamp( - gene.radius + pow(raddist(*Chromosome::re)*sqrt(max_radius), 2), - 0, - max_radius - ); - } - - if (booldist(*Chromosome::re)) { // color (all three values at the same time) - std::normal_distribution<> coldist(0, Chromosome::stddev_color); - gene.color.r = std::clamp(gene.color.r + coldist(*Chromosome::re), 0, 255); - gene.color.g = std::clamp(gene.color.g + coldist(*Chromosome::re), 0, 255); - gene.color.b = std::clamp(gene.color.b + coldist(*Chromosome::re), 0, 255); - gene.color.a = std::clamp(gene.color.a + coldist(*Chromosome::re), 0, 255); - } -} - - -std::pair::iterator, std::vector::iterator> -Chromosome::selectSegment(std::vector& genes) -{ - std::uniform_int_distribution<> randdist(0, genes.size()-1); - auto first = genes.begin() + randdist(*Chromosome::re); - auto second = genes.begin() + randdist(*Chromosome::re); - - if (first > second) { - std::swap(first, second); - } - - return std::pair::iterator, - std::vector::iterator>(first, second); -} - - -std::vector::iterator -Chromosome::selectGene(std::vector& genes) +std::vector>::iterator Chromosome::selectGene() { if (genes.empty()) { - return genes.end(); + return this->genes.end(); } else { - std::uniform_int_distribution<> posdist(0, genes.size()-1); + std::uniform_int_distribution<> posdist(0, this->genes.size()-1); return genes.begin() + posdist(*Chromosome::re); } } + + +void Chromosome::addGene() +{ +} + + +void Chromosome::removeGene() +{ + auto it = this->selectGene(); + if (it != this->genes.end()) { + this->genes.erase(it); + } +} + + +void Chromosome::swapGenes() +{ + auto it_one = this->selectGene(); + auto it_two = this->selectGene(); + if (it_one != this->genes.end() && it_two != this->genes.end() && it_one != it_two) { + it_one->swap(*it_two); +// auto tmp = *it_one; +// *it_one = *it_two; +// *it_two = tmp; + } +} + + +void Chromosome::mutateGene() +{ + auto it = this->selectGene(); + if (it != this->genes.end()) { + (*it)->mutate(); + } +} diff --git a/src/Chromosome.cpp.old b/src/Chromosome.cpp.old new file mode 100644 index 0000000..59b3fde --- /dev/null +++ b/src/Chromosome.cpp.old @@ -0,0 +1,232 @@ +#include "Chromosome.hpp" + +#include +#if __GNUC__ < 7 // gcc 7 will support clamp +namespace std { + template + T clamp(T v, T lo, T hi) + { + return std::min(hi, std::max(lo, v)); + } +} +#endif + +#include +#include + + + +// #include +sf::Vector2f Chromosome::size(0, 0); +float Chromosome::stddev_position = .1; +float Chromosome::stddev_radius = .1; +float Chromosome::stddev_color = 20; +std::minstd_rand* Chromosome::re; + +sf::CircleShape Chromosome::circle; + + +Chromosome::Chromosome() +{ + // this->genes is already empty + this->circle.setPointCount(36); +} + + +Chromosome::Chromosome(Chromosome& father, Chromosome& mother) : + Chromosome() +{ + std::uniform_int_distribution<> booldist(0, 1); + +// auto fpair = this->selectSegment(father.genes); +// auto mpair = this->selectSegment(mother.genes); + +// auto cur_it = this->genes.begin(); +// std::cout << std::distance(cur_it, father.genes.begin()) << std::endl; +// std::cout << std::distance(cur_it, mother.genes.begin()) << std::endl; +// cur_it = this->genes.insert(cur_it, fpair.second, father.genes.end()); +// cur_it = this->genes.insert(cur_it, mpair.first, mpair.second); +// cur_it = this->genes.insert(cur_it, father.genes.begin(), fpair.first); + +// if (booldist(*Chromosome::re)) { +// this->genes.insert(this->genes.begin(), fpair.second, father.genes.end()); +// this->genes.insert(this->genes.begin(), mpair.first, mpair.second); +// this->genes.insert(this->genes.begin(), father.genes.begin(), fpair.first); +// } else { +// this->genes.insert(this->genes.begin(), mpair.second, mother.genes.end()); +// this->genes.insert(this->genes.begin(), fpair.first, fpair.second); +// this->genes.insert(this->genes.begin(), mother.genes.begin(), mpair.first); +// } + + auto gene_father = this->selectGene(father.genes); + auto gene_mother = this->selectGene(mother.genes); + + if (booldist(*Chromosome::re)) { + this->genes.insert(this->genes.begin(), father.genes.begin(), gene_father); + this->genes.insert(this->genes.begin(), gene_mother, mother.genes.end()); + } else { + this->genes.insert(this->genes.begin(), mother.genes.begin(), gene_mother); + this->genes.insert(this->genes.begin(), gene_father, father.genes.end()); + } +} + + +void Chromosome::mutate() +{ + std::uniform_int_distribution<> mutatedist(0, 1); // 1/2 of the time, it mutates everytime! + std::uniform_int_distribution<> choicedist(0, 12); + while (mutatedist(*Chromosome::re)) { + int choice = choicedist(*Chromosome::re); + + if (choice < 1) { // add +// std::cout << "Added circle" << std::endl; + this->genes.push_back(this->randomGene()); + + } else if (choice < 2) { // remove +// std::cout << "Removed circle" << std::endl; + auto it = this->selectGene(this->genes); + if (it != this->genes.end()) { + this->genes.erase(it); + } + + } else if (choice < 4) { // swap +// std::cout << "Swapped circles" << std::endl; + auto it_one = this->selectGene(this->genes); + auto it_two = this->selectGene(this->genes); + if (it_one != this->genes.end() && it_two != this->genes.end() && it_one != it_two) { + auto tmp = *it_one; + *it_one = *it_two; + *it_two = tmp; + } + + } else { // mutate +// std::cout << "Mutated circle" << std::endl; + auto it = this->selectGene(this->genes); + if (it != this->genes.end()) { + this->mutateGene(*it); + } + } + } +} + + +void Chromosome::draw(sf::RenderTarget& target, sf::RenderStates states) const +{ + this->circle.setPosition(0, 0); + this->circle.setRadius(Chromosome::size.x + Chromosome::size.y); + this->circle.setOrigin(Chromosome::size); + this->circle.setFillColor(sf::Color::White); + target.draw(this->circle, states); + + for (auto gene : this->genes) { + Chromosome::circle.setPosition(gene.position); + Chromosome::circle.setRadius(gene.radius); + Chromosome::circle.setOrigin(sf::Vector2f(gene.radius, gene.radius)); + Chromosome::circle.setFillColor(gene.color); + target.draw(Chromosome::circle, states); + } +} + + +size_t Chromosome::length() +{ + return this->genes.size(); +} + + +float Chromosome::maxRadius() +{ + return std::min(Chromosome::size.x, Chromosome::size.y)/2; +} + + +Chromosome::Gene Chromosome::randomGene() +{ + float max_radius = this->maxRadius(); + std::uniform_real_distribution<> xdist(0, Chromosome::size.x); + std::uniform_real_distribution<> ydist(0, Chromosome::size.y); + std::uniform_real_distribution<> rdist(0, sqrt(max_radius)); + std::uniform_int_distribution<> colordist(0, 255); + + sf::Vector2f position(xdist(*Chromosome::re), ydist(*Chromosome::re)); + float radius = (pow(rdist(*Chromosome::re), 2)); + sf::Color color( + colordist(*Chromosome::re), + colordist(*Chromosome::re), + colordist(*Chromosome::re), + 150 + ); + + Chromosome::Gene gene; + gene.position = position; + gene.radius = radius; + gene.color = color; + + return gene; +} + + +void Chromosome::mutateGene(Gene& gene) +{ + std::uniform_int_distribution<> booldist(0, 1); + float max_radius = this->maxRadius(); + + if (booldist(*Chromosome::re)) { // position + std::normal_distribution<> posdist(0, Chromosome::stddev_position); + gene.position.x = std::clamp( + gene.position.x + posdist(*Chromosome::re)*max_radius, + 0, + Chromosome::size.x + ); + gene.position.y = std::clamp( + gene.position.y + posdist(*Chromosome::re)*max_radius, + 0, + Chromosome::size.y + ); + } + + if (booldist(*Chromosome::re)) { // radius + std::normal_distribution<> raddist(0, Chromosome::stddev_radius); + gene.radius = std::clamp( + gene.radius + pow(raddist(*Chromosome::re)*sqrt(max_radius), 2), + 0, + max_radius + ); + } + + if (booldist(*Chromosome::re)) { // color (all three values at the same time) + std::normal_distribution<> coldist(0, Chromosome::stddev_color); + gene.color.r = std::clamp(gene.color.r + coldist(*Chromosome::re), 0, 255); + gene.color.g = std::clamp(gene.color.g + coldist(*Chromosome::re), 0, 255); + gene.color.b = std::clamp(gene.color.b + coldist(*Chromosome::re), 0, 255); + gene.color.a = std::clamp(gene.color.a + coldist(*Chromosome::re), 0, 255); + } +} + + +std::pair::iterator, std::vector::iterator> +Chromosome::selectSegment(std::vector& genes) +{ + std::uniform_int_distribution<> randdist(0, genes.size()-1); + auto first = genes.begin() + randdist(*Chromosome::re); + auto second = genes.begin() + randdist(*Chromosome::re); + + if (first > second) { + std::swap(first, second); + } + + return std::pair::iterator, + std::vector::iterator>(first, second); +} + + +std::vector::iterator +Chromosome::selectGene(std::vector& genes) +{ + if (genes.empty()) { + return genes.end(); + } else { + std::uniform_int_distribution<> posdist(0, genes.size()-1); + return genes.begin() + posdist(*Chromosome::re); + } +} diff --git a/src/Chromosome.hpp b/src/Chromosome.hpp index 2366eb3..42fe79e 100644 --- a/src/Chromosome.hpp +++ b/src/Chromosome.hpp @@ -1,50 +1,45 @@ #pragma once -#include -#include +#include +#include #include #include -#include + +#include "Genes.hpp" class Chromosome : public sf::Drawable { public: - static sf::Vector2f size; - static float stddev_position; // percent of max_radius - static float stddev_radius; // percent of max_radius - static float stddev_color; + enum GeneType + { + Circle + }; + static std::minstd_rand* re; + static void allowGeneType(GeneType gt, bool allowed=true); + static bool isGeneTypeAllowed(GeneType gt); + Chromosome(); // create empty chromosome Chromosome(Chromosome& father, Chromosome& mother); // crossover - void mutate(); // randomly mutate chromosome's genes - virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; - size_t length(); + void mutate(); // randomly mutate chromosome's genes -protected: - static sf::CircleShape circle; + size_t length() const; - struct Gene - { - sf::Vector2f position; - float radius; - sf::Color color; - }; +private: + static std::unordered_set allowedGeneTypes; - std::vector genes; + std::vector> genes; - float maxRadius(); + std::vector>::iterator selectGene(); - Gene randomGene(); - void mutateGene(Gene& gene); - - std::pair::iterator, std::vector::iterator> - selectSegment(std::vector& genes); - - std::vector::iterator selectGene(std::vector& genes); + void addGene(); + void removeGene(); + void swapGenes(); + void mutateGene(); }; diff --git a/src/Chromosome.hpp.old b/src/Chromosome.hpp.old new file mode 100644 index 0000000..2366eb3 --- /dev/null +++ b/src/Chromosome.hpp.old @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include +#include +#include + + + +class Chromosome : public sf::Drawable +{ +public: + static sf::Vector2f size; + static float stddev_position; // percent of max_radius + static float stddev_radius; // percent of max_radius + static float stddev_color; + static std::minstd_rand* re; + + Chromosome(); // create empty chromosome + Chromosome(Chromosome& father, Chromosome& mother); // crossover + + void mutate(); // randomly mutate chromosome's genes + + virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; + + size_t length(); + +protected: + static sf::CircleShape circle; + + struct Gene + { + sf::Vector2f position; + float radius; + sf::Color color; + }; + + std::vector genes; + + float maxRadius(); + + Gene randomGene(); + void mutateGene(Gene& gene); + + std::pair::iterator, std::vector::iterator> + selectSegment(std::vector& genes); + + std::vector::iterator selectGene(std::vector& genes); +};