From 6dfce33f83bae29ea3574e28708e67e27fa1356f Mon Sep 17 00:00:00 2001 From: bbhsu2 Date: Mon, 8 Jun 2015 22:05:26 -0500 Subject: [PATCH] o adding genetic colors, a genetic algorithm to conform led panel to random target color --- demo-main.cc | 217 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 198 insertions(+), 19 deletions(-) diff --git a/demo-main.cc b/demo-main.cc index 07ed861..4d443a5 100644 --- a/demo-main.cc +++ b/demo-main.cc @@ -12,9 +12,7 @@ #include #include #include -#include #include - #include using std::min; @@ -366,7 +364,7 @@ public: : ThreadedCanvasManipulator(m), delay_ms_(delay_ms) { width_ = canvas()->width() - 1; // We need an odd width height_ = canvas()->height() - 1; // We need an odd height - + // Allocate memory values_ = new int*[width_]; for (int x=0; xwidth(); height_ = canvas()->height(); - + // Allocate memory values_ = new int*[width_]; for (int x=0; xwidth(); + height_ = canvas()->height(); + popSize_ = width_ * height_; + + // Allocate memory + children_ = new citizen[popSize_]; + parents_ = new citizen[popSize_]; + srand(time(NULL)); + } + + ~GeneticColors() { + delete [] children_; + delete [] parents_; + } + + static int rnd (int i) { return rand() % i; } + + void Run() { + // Set a random target_ + target_ = rand() & 0xFFFFFF; + + // Create the first generation of random children_ + for (int i = 0; i < popSize_; ++i) { + children_[i].dna = rand() & 0xFFFFFF; + } + + while(running()) { + swap(); + sort(); + mate(); + std::random_shuffle (children_, children_ + popSize_, rnd); + + // Draw citizens to canvas + for(int i=0; i < popSize_; i++) { + int c = children_[i].dna; + int x = i % width_; + int y = (int)(i / width_); + canvas()->SetPixel(x, y, R(c), G(c), B(c)); + } + + // When we reach the 85% fitness threshold... + if(is85PercentFit()) { + // ...set a new random target_ + target_ = rand() & 0xFFFFFF; + + // Randomly mutate everyone for sake of new colors + for (int i = 0; i < popSize_; ++i) { + mutate(children_[i]); + } + } + usleep(delay_ms_ * 1000); + } + } + +private: + /// citizen will hold dna information, a 24-bit color value. + struct citizen { + citizen() { } + + citizen(int chrom) + : dna(chrom) { + } + + int dna; + }; + + /// for sorting by fitness + class comparer { + public: + comparer(int t) + : target_(t) { } + + inline bool operator() (const citizen& c1, const citizen& c2) { + return (calcFitness(c1.dna, target_) < calcFitness(c2.dna, target_)); + } + + private: + const int target_; + }; + + static int R(const int cit) { return at(cit, 16); } + static int G(const int cit) { return at(cit, 8); } + static int B(const int cit) { return at(cit, 0); } + static int at(const int v, const int offset) { return (v >> offset) & 0xFF; } + + /// fitness here is how "similar" the color is to the target + static int calcFitness(const int value, const int target) { + // Count the number of differing bits + int diffBits = 0; + for (unsigned int diff = value ^ target; diff; diff &= diff - 1) { + ++diffBits; + } + return diffBits; + } + + /// sort by fitness so the most fit citizens are at the top of parents_ + /// this is to establish an elite population of greatest fitness + /// the most fit members and some others are allowed to reproduce + /// to the next generation + void sort() { + std::sort(parents_, parents_ + popSize_, comparer(target_)); + } + + /// let the elites continue to the next generation children + /// randomly select 2 parents of (near)elite fitness and determine + /// how they will mate. after mating, randomly mutate citizens + void mate() { + // Adjust these for fun and profit + const float eliteRate = 0.30f; + const float mutationRate = 0.20f; + + const int numElite = popSize_ * eliteRate; + for (int i = 0; i < numElite; ++i) { + children_[i] = parents_[i]; + } + + for (int i = numElite; i < popSize_; ++i) { + //select the parents randomly + const float sexuallyActive = 1.0 - eliteRate; + const int p1 = rand() % (int)(popSize_ * sexuallyActive); + const int p2 = rand() % (int)(popSize_ * sexuallyActive); + const int matingMask = (~0) << (rand() % bitsPerPixel); + + // Make a baby + int baby = (parents_[p1].dna & matingMask) + | (parents_[p2].dna & ~matingMask); + children_[i].dna = baby; + + // Mutate randomly based on mutation rate + if ((rand() / (float)RAND_MAX) < mutationRate) { + mutate(children_[i]); + } + } + } + + /// parents make children, + /// children become parents, + /// and they make children... + void swap() { + citizen* temp = parents_; + parents_ = children_; + children_ = temp; + } + + void mutate(citizen& c) { + // Flip a random bit + c.dna ^= 1 << (rand() % bitsPerPixel); + } + + /// can adjust this threshold to make transition to new target seamless + bool is85PercentFit() { + int numFit = 0; + for (int i = 0; i < popSize_; ++i) { + if (calcFitness(children_[i].dna, target_) < 1) { + ++numFit; + } + } + return ((numFit / (float)popSize_) > 0.85f); + } + + static const int bitsPerPixel = 24; + int popSize_; + int width_, height_; + int delay_ms_; + int target_; + citizen* children_; + citizen* parents_; +}; + static int usage(const char *progname) { fprintf(stderr, "usage: %s -D [optional parameter]\n", progname); @@ -864,7 +1038,8 @@ static int usage(const char *progname) { "\t6 - Abelian sandpile model (-m )\n" "\t7 - Conway's game of life (-m )\n" "\t8 - Langton's ant (-m )\n" - "\t9 - Volume bars (-m )\n"); + "\t9 - Volume bars (-m )\n" + "\t10 - Evolution of color (-m )\n"); fprintf(stderr, "Example:\n\t%s -t 10 -D 1 runtext.ppm\n" "Scrolls the runtext for 10 seconds\n", progname); return 1; @@ -1046,6 +1221,10 @@ int main(int argc, char *argv[]) { case 9: image_gen = new VolumeBars(canvas, scroll_ms, canvas->width()/2); break; + + case 10: + image_gen = new GeneticColors(canvas, scroll_ms); + break; } if (image_gen == NULL)