/* ** This is free and unencumbered software released into the public domain. ** ** Anyone is free to copy, modify, publish, use, compile, sell, or ** distribute this software, either in source code form or as a compiled ** binary, for any purpose, commercial or non-commercial, and by any ** means. ** ** In jurisdictions that recognize copyright laws, the author or authors ** of this software dedicate any and all copyright interest in the ** software to the public domain. We make this dedication for the benefit ** of the public at large and to the detriment of our heirs and ** successors. We intend this dedication to be an overt act of ** relinquishment in perpetuity of all present and future rights to this ** software under copyright law. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR ** OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ** OTHER DEALINGS IN THE SOFTWARE. ** ** For more information, please refer to */ #include #include #include #include #include #include using namespace std; #define randquotient 10 // Randomize every one in ten alleles #define randomization 3 // Randomize up to three extra alleles #define randrate 0.1 // Randomize somewhat infrequently #define bufsiz 256 // Max number of characters to read (long strings will take a long time) #define print_dead false // Don't print the ones that didn't survive // ========================================================== // === Character Range Convenience Functions ================ // ========================================================== #define char_min ' ' #define char_max 'z' // Returns true iff a character is in our range. bool legalChar(char c) { return c >= char_min && c <= char_max; } // Returns a random character in our range inline char rand_char() { return char(rand() % (char_max - char_min) + char_min); } // Returns a random string of characters in our range string rand_str(size_t len) { string res; res.reserve(len); for (size_t i = 0; i < len; ++i) { res.append(1, rand_char()); } return res; } // ========================================================== // === Genetic Functions ==================================== // ========================================================== // Generate a child from two parents string breed(string mother, string father) { string res = mother; // Copy alleles randomly from mother/father for (size_t i = 0; i < mother.length(); ++i) if (rand() & 1) res[i] = father[i]; // Randomize some alleles if (rand() / (double)RAND_MAX < randrate) { size_t randomize = (mother.length()) / randquotient + (randomization? rand() % randomization : 0); for (size_t i = 0; i < randomize; ++i) res[rand() % res.length()] = rand_char(); } return res; } // Check a child for fitness; how close is it to the target? size_t fitness(string child, string target) { size_t fit = 0; for (size_t i = 0; i < target.length(); ++i) fit += target[i] == child[i]; return fit; } int main() { string str; char buf[bufsiz]; size_t children = 5; cout << "Enter a string to evolve to:" << endl; cin.getline(buf, bufsiz); str.reserve(bufsiz); for (const char* i = buf; *i; ++i) if (legalChar(*i)) str.append(i, 1); srand(time(0)); string parent1 = rand_str(str.length()), parent2 = rand_str(str.length()); cout << "Evolve to `" << str << "'" << endl; cout << "Initial parents:" << endl << " " << parent1 << endl << " " << parent2 << endl << endl; cout << "Enter the number of children in each generation: "; cin >> children; if (children < 2) children = 2; cout << endl << "Each generation will have " << children << " children." << endl << endl; size_t num_generations = 0; for (;;) { size_t rounds = 0; cout << "Enter the number of generations to run: "; cin >> rounds; for (size_t gen = 0; gen < rounds; ++gen) { ++num_generations; multimap kids; set clones; // Nature doesn't do this, but we can't have clones in our tiny strings for (size_t child = 0; child < children; ++child) { string kid = breed(parent1, parent2); // Don't allow clones if (clones.find(kid) != clones.end()) { --child; continue; } clones.insert(kid); kids.insert(pair(fitness(kid, str), kid)); } map::reverse_iterator it = kids.rbegin(); cout << '"' << (parent1 = (it++)->second) << "\" and "; cout << '"' << (parent2 = (it++)->second) << "\" live to breed"; if (print_dead) { cout << "; "; for (; it != kids.rend(); ++it) cout << it->second << ", "; cout << "died virgins."; } cout << endl; if (parent1 == str) break; } if (parent1 == str) break; } cout << "Your string, `" << parent1 << "', appeared in generation " << num_generations << "." << endl; }