Implement and test Chromosome
This commit is contained in:
parent
836887d209
commit
8f47088a56
3 changed files with 246 additions and 115 deletions
|
|
@ -1,57 +1,195 @@
|
||||||
#include "Chromosome.hpp"
|
#include "Chromosome.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#if __GNUC__ < 7 // gcc 7 will support clamp
|
||||||
/*
|
namespace std {
|
||||||
class Chromosome : public sf::Drawable
|
template<typename T>
|
||||||
{
|
T clamp(T v, T lo, T hi)
|
||||||
public:
|
|
||||||
Chromosome(); // create empty chromosome
|
|
||||||
Chromosome(Chromosome& father, Chromosome& mother); // cross over two chromosomes
|
|
||||||
|
|
||||||
void mutate(); // randomly mutate chromosome's genes
|
|
||||||
|
|
||||||
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Gene
|
|
||||||
{
|
{
|
||||||
sf::Vector2f position;
|
return std::min(hi, std::max(lo, v));
|
||||||
float size;
|
}
|
||||||
sf::Color color;
|
}
|
||||||
};
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// #include <cmath>
|
||||||
|
sf::Vector2f Chromosome::size(0, 0);
|
||||||
|
float Chromosome::stddev_position = .1;
|
||||||
|
float Chromosome::stddev_radius = .1;
|
||||||
|
float Chromosome::stddev_color = 20;
|
||||||
|
std::mt19937_64* Chromosome::re;
|
||||||
|
|
||||||
sf::CircleShape circle; // drawing the chromosome, one draw call at a time
|
|
||||||
std::vector<Gene> genes;
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
Chromosome::Chromosome()
|
Chromosome::Chromosome()
|
||||||
{
|
{
|
||||||
// this->genes is already empty
|
// this->genes is already empty
|
||||||
};
|
this->circle.setPointCount(100);
|
||||||
|
}
|
||||||
|
|
||||||
Chromosome::Chromosome(Chromosome& father, Chromosome& mother) {
|
|
||||||
// randomly swap father and mother
|
Chromosome::Chromosome(Chromosome& father, Chromosome& mother) :
|
||||||
if (/*TODO: random bool*/ false) {
|
Chromosome()
|
||||||
Chromosome& tmp = father;
|
{
|
||||||
father = mother;
|
std::uniform_int_distribution<> booldist(0, 1);
|
||||||
mother = tmp;
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Chromosome::mutate()
|
||||||
|
{
|
||||||
|
std::uniform_int_distribution<> booldist(0, 1);
|
||||||
|
std::uniform_int_distribution<> choicedist(0, 12);
|
||||||
|
while (booldist(*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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace random segment of mother with random segment of father
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: in seperate function:
|
} else { // mutate
|
||||||
// finding random segment:
|
// std::cout << "Mutated circle" << std::endl;
|
||||||
// randomly find starting position, then length
|
auto it = this->selectGene(this->genes);
|
||||||
// find starting iterator, then end iterator
|
if (it != this->genes.end()) {
|
||||||
|
this->mutateGene(*it);
|
||||||
// using function from above:
|
}
|
||||||
// find father segment: f_start, f_stop (iterators)
|
}
|
||||||
// find mother segment: m_start, m_stop (iterators)
|
}
|
||||||
|
}
|
||||||
// RIGHT:
|
|
||||||
// append mother until m_start
|
|
||||||
// append father from f_start to f_end
|
void Chromosome::draw(sf::RenderTarget& target, sf::RenderStates states) const
|
||||||
// append mother from m_end
|
{
|
||||||
|
for (auto gene : this->genes) {
|
||||||
|
this->circle.setPosition(gene.position);
|
||||||
|
this->circle.setRadius(gene.radius);
|
||||||
|
this->circle.setOrigin(sf::Vector2f(gene.radius, gene.radius));
|
||||||
|
this->circle.setFillColor(gene.color);
|
||||||
|
target.draw(this->circle, states);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Chromosome::Gene Chromosome::randomGene()
|
||||||
|
{
|
||||||
|
float max_radius = std::min(Chromosome::size.x, Chromosome::size.y)/2;
|
||||||
|
std::uniform_real_distribution<> xdist(-max_radius, Chromosome::size.x + max_radius);
|
||||||
|
std::uniform_real_distribution<> ydist(-max_radius, Chromosome::size.y + max_radius);
|
||||||
|
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));
|
||||||
|
|
||||||
|
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 = std::min(Chromosome::size.x, Chromosome::size.y)/2;
|
||||||
|
|
||||||
|
if (booldist(*Chromosome::re)) { // position
|
||||||
|
std::normal_distribution<> posdist(0, Chromosome::stddev_position);
|
||||||
|
gene.position.x = std::clamp<float>(
|
||||||
|
gene.position.x + posdist(*Chromosome::re)*max_radius,
|
||||||
|
-max_radius,
|
||||||
|
Chromosome::size.x + max_radius
|
||||||
|
);
|
||||||
|
gene.position.y = std::clamp<float>(
|
||||||
|
gene.position.y + posdist(*Chromosome::re)*max_radius,
|
||||||
|
-max_radius,
|
||||||
|
Chromosome::size.y + max_radius
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (booldist(*Chromosome::re)) { // radius
|
||||||
|
std::normal_distribution<> raddist(0, Chromosome::stddev_radius);
|
||||||
|
gene.radius = std::clamp<float>(
|
||||||
|
gene.radius + raddist(*Chromosome::re)*max_radius,
|
||||||
|
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<unsigned int>(gene.color.r + coldist(*Chromosome::re), 0, 255);
|
||||||
|
gene.color.g = std::clamp<unsigned int>(gene.color.g + coldist(*Chromosome::re), 0, 255);
|
||||||
|
gene.color.b = std::clamp<unsigned int>(gene.color.b + coldist(*Chromosome::re), 0, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<std::vector<Chromosome::Gene>::iterator, std::vector<Chromosome::Gene>::iterator>
|
||||||
|
Chromosome::selectSegment(std::vector<Chromosome::Gene>& genes)
|
||||||
|
{
|
||||||
|
std::uniform_int_distribution<> randdist(0, genes.size());
|
||||||
|
auto first = genes.begin() + randdist(*Chromosome::re);
|
||||||
|
auto second = genes.begin() + randdist(*Chromosome::re);
|
||||||
|
|
||||||
|
if (first > second) {
|
||||||
|
std::swap(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::pair<std::vector<Chromosome::Gene>::iterator,
|
||||||
|
std::vector<Chromosome::Gene>::iterator>(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Chromosome::Gene>::iterator
|
||||||
|
Chromosome::selectGene(std::vector<Chromosome::Gene>& genes)
|
||||||
|
{
|
||||||
|
if (genes.empty()) {
|
||||||
|
return genes.end();
|
||||||
|
} else {
|
||||||
|
std::uniform_int_distribution<> posdist(0, genes.size());
|
||||||
|
return genes.begin() + posdist(*Chromosome::re);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,45 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <SFML/System.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Chromosome : public sf::Drawable
|
class Chromosome : public sf::Drawable
|
||||||
{
|
{
|
||||||
public:
|
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::mt19937_64* re;
|
||||||
|
|
||||||
Chromosome(); // create empty chromosome
|
Chromosome(); // create empty chromosome
|
||||||
Chromosome(Chromosome& father, Chromosome& mother); // cross over two chromosomes
|
Chromosome(Chromosome& father, Chromosome& mother); // crossover
|
||||||
|
|
||||||
void mutate(); // randomly mutate chromosome's genes
|
void mutate(); // randomly mutate chromosome's genes
|
||||||
|
|
||||||
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
|
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
// TODO: random numbers
|
|
||||||
// pass as reference to Chromosome and Mutate?
|
|
||||||
// pass as reference on object creation?
|
|
||||||
|
|
||||||
struct Gene
|
struct Gene
|
||||||
{
|
{
|
||||||
sf::Vector2f position;
|
sf::Vector2f position;
|
||||||
float size;
|
float radius;
|
||||||
sf::Color color;
|
sf::Color color;
|
||||||
};
|
};
|
||||||
|
|
||||||
sf::CircleShape circle; // drawing the chromosome, one draw call at a time
|
Gene randomGene();
|
||||||
|
void mutateGene(Gene& gene);
|
||||||
|
|
||||||
size_t genesize = 0;
|
std::pair<std::vector<Gene>::iterator, std::vector<Gene>::iterator>
|
||||||
std::forward_list<Gene> genes;
|
selectSegment(std::vector<Gene>& genes);
|
||||||
|
|
||||||
|
std::vector<Gene>::iterator selectGene(std::vector<Gene>& genes);
|
||||||
|
|
||||||
|
mutable sf::CircleShape circle; // drawing the chromosome, one draw call at a time
|
||||||
|
std::vector<Gene> genes;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
101
src/main.cpp
101
src/main.cpp
|
|
@ -1,5 +1,7 @@
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <random>
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include "Chromosome.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UI Modes:
|
* UI Modes:
|
||||||
|
|
@ -106,10 +108,25 @@
|
||||||
int main() {
|
int main() {
|
||||||
const float winW = 480;
|
const float winW = 480;
|
||||||
const float winH = 480;
|
const float winH = 480;
|
||||||
|
std::mt19937_64 randomEngine;
|
||||||
|
randomEngine.seed(1);
|
||||||
|
|
||||||
sf::RenderWindow window(sf::VideoMode(winW, winH), "gross");
|
sf::RenderWindow window(sf::VideoMode(winW, winH), "gross");
|
||||||
window.setMouseCursorVisible(false); // hide the cursor
|
window.setMouseCursorVisible(false); // hide the cursor
|
||||||
|
|
||||||
|
Chromosome::size = sf::Vector2f(winW/2, winH/2);
|
||||||
|
Chromosome::re = &randomEngine;
|
||||||
|
Chromosome father, mother, child, monster;
|
||||||
|
sf::View vfather(sf::FloatRect(0, 0, winW/2, winH/2));
|
||||||
|
sf::View vmother(sf::FloatRect(0, 0, winW/2, winH/2));
|
||||||
|
sf::View vchild(sf::FloatRect(0, 0, winW/2, winH/2));
|
||||||
|
sf::View vmonster(sf::FloatRect(0, 0, winW/2, winH/2));
|
||||||
|
vfather.setViewport(sf::FloatRect(0, 0, .5, .5));
|
||||||
|
vmother.setViewport(sf::FloatRect(.5, 0, .5, .5));
|
||||||
|
vchild.setViewport(sf::FloatRect(0, .5, .5, .5));
|
||||||
|
vmonster.setViewport(sf::FloatRect(.5, .5, .5, .5));
|
||||||
|
|
||||||
|
/*
|
||||||
// load images
|
// load images
|
||||||
sf::Texture base;
|
sf::Texture base;
|
||||||
sf::Texture comp;
|
sf::Texture comp;
|
||||||
|
|
@ -137,8 +154,8 @@ int main() {
|
||||||
std::cout << "The medshader is not available\n";
|
std::cout << "The medshader is not available\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
medcompshdr.setUniform("base", comp);
|
medcompshdr.setUniform("base", base);
|
||||||
medcompshdr.setUniform("curr", base);
|
medcompshdr.setUniform("curr", comp);
|
||||||
medcompshdr.setUniform("size", sf::Vector2f(240, 240));
|
medcompshdr.setUniform("size", sf::Vector2f(240, 240));
|
||||||
medcompshdr.setUniform("offs", sf::Vector2f(240, 0));
|
medcompshdr.setUniform("offs", sf::Vector2f(240, 0));
|
||||||
|
|
||||||
|
|
@ -148,6 +165,9 @@ int main() {
|
||||||
// Use a timer to obtain the time elapsed
|
// Use a timer to obtain the time elapsed
|
||||||
// sf::Clock clk;
|
// sf::Clock clk;
|
||||||
// clk.restart(); // start the timer
|
// clk.restart(); // start the timer
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while (window.isOpen()) {
|
while (window.isOpen()) {
|
||||||
// Event handling
|
// Event handling
|
||||||
|
|
@ -155,8 +175,17 @@ int main() {
|
||||||
|
|
||||||
while (window.pollEvent(event)) {
|
while (window.pollEvent(event)) {
|
||||||
// Exit the app when a key is pressed
|
// Exit the app when a key is pressed
|
||||||
if (event.type == sf::Event::KeyPressed)
|
if (event.type == sf::Event::KeyPressed) {
|
||||||
window.close();
|
father = Chromosome();
|
||||||
|
mother = Chromosome();
|
||||||
|
for (int i=0; i<100; ++i) {
|
||||||
|
father.mutate();
|
||||||
|
mother.mutate();
|
||||||
|
}
|
||||||
|
child = Chromosome(father, mother);
|
||||||
|
monster = child;
|
||||||
|
monster.mutate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the others parameters who need to be updated every frames
|
// Set the others parameters who need to be updated every frames
|
||||||
|
|
@ -167,7 +196,13 @@ int main() {
|
||||||
|
|
||||||
// Draw the sprites
|
// Draw the sprites
|
||||||
window.clear();
|
window.clear();
|
||||||
|
window.setView(vfather); window.draw(father);
|
||||||
|
window.setView(vmother); window.draw(mother);
|
||||||
|
window.setView(vchild); window.draw(child);
|
||||||
|
window.setView(vmonster); window.draw(monster);
|
||||||
|
window.display();
|
||||||
|
|
||||||
|
/*
|
||||||
window.draw(sprbase);
|
window.draw(sprbase);
|
||||||
|
|
||||||
sprcomp.setPosition(240, 0);
|
sprcomp.setPosition(240, 0);
|
||||||
|
|
@ -178,63 +213,9 @@ int main() {
|
||||||
|
|
||||||
sprcomp.setPosition(240, 240);
|
sprcomp.setPosition(240, 240);
|
||||||
window.draw(sprcomp, &medcompshdr);
|
window.draw(sprcomp, &medcompshdr);
|
||||||
|
*/
|
||||||
|
|
||||||
window.display();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// old main - keep for testing purposes
|
|
||||||
/*
|
|
||||||
int main() {
|
|
||||||
const float winW = 800;
|
|
||||||
const float winH = 600;
|
|
||||||
|
|
||||||
sf::RenderWindow window(sf::VideoMode(winW, winH), "gross");
|
|
||||||
window.setMouseCursorVisible(false); // hide the cursor
|
|
||||||
|
|
||||||
// Create a texture and a sprite for the shader
|
|
||||||
sf::Texture tex;
|
|
||||||
tex.create(winW, winH);
|
|
||||||
sf::Sprite spr(tex);
|
|
||||||
|
|
||||||
sf::Shader shader;
|
|
||||||
shader.loadFromFile("fire.glsl", sf::Shader::Fragment); // load the shader
|
|
||||||
|
|
||||||
if (!shader.isAvailable()) {
|
|
||||||
std::cout << "The shader is not available\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the resolution parameter (the resoltion is divided to make the fire smaller)
|
|
||||||
shader.setParameter("resolution", sf::Vector2f(winW / 2, winH / 2));
|
|
||||||
|
|
||||||
// Use a timer to obtain the time elapsed
|
|
||||||
sf::Clock clk;
|
|
||||||
clk.restart(); // start the timer
|
|
||||||
|
|
||||||
while (window.isOpen()) {
|
|
||||||
// Event handling
|
|
||||||
sf::Event event;
|
|
||||||
|
|
||||||
while (window.pollEvent(event)) {
|
|
||||||
// Exit the app when a key is pressed
|
|
||||||
if (event.type == sf::Event::KeyPressed)
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the others parameters who need to be updated every frames
|
|
||||||
shader.setParameter("time", clk.getElapsedTime().asSeconds());
|
|
||||||
|
|
||||||
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
|
|
||||||
shader.setParameter("mouse", sf::Vector2f(mousePos.x, mousePos.y - winH));
|
|
||||||
|
|
||||||
// Draw the sprite with the shader on it
|
|
||||||
window.clear();
|
|
||||||
window.draw(spr, &shader);
|
|
||||||
window.display();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue