The code was written for fun, and it is by far the most complicated program I've written yet. It's also my first step from C into C++. I have some training in algorithms but almost none in coding. It is pretty long and I don't expect anyone to analyze the whole thing. I would, however, appreciate it if anyone has the time to scan through looking for bad coding practice and give me some style suggestions or topics to look into that would help me write better/more efficient code. Also I'd like to hear about it if you spot any room for OOP in this code as I will be venturing into that area soon and would love to use it in this program. There is a description of what the code does at the bottom if you would like to get an idea of what is being accomplished.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <string>
#include <math.h>
using namespace std;
/*
Idea for program comes from Richard Dawkins' "The Blind Watchmaker"
*/
char chargen(void);
//Generates a random character for insertion
string sentgen(int length);
//Generates the initial random sentence
int compare(string ancestor,string s);
//discovers the number of correct letters in each baby
void reproduce(string ancestor, string s[], string target, int length);
//produces 8 mutated offspring
int mutations();
//randomly determines a number of mutations between 0 and 10
int whichone(int length);
//randomly determines which letter to mutate
int wholives(int alike[8], int *who);
//determines which baby survives to reproduce
string evolution(string initial, string target, int *alike); //coordinates the evolution
string initialize();
//determines the target string and such
void introduction(); //the concept
long double probability(int length);
//determines the alternative probability, could be done inline
int main()
{
string initial, target, parents[3000], tab = " ";
int complete = 0, count = 1;
srand((unsigned)time(0)); //seeds rand()
introduction(); //the background
target = initialize(); //user input
int length = target.length();
initial = sentgen(length); //generates initial random sentence
cout << "Ancestor: " << initial << endl << endl << "Enter to continue." << endl;
fflush(stdin);
getchar();
parents[0] = initial;
for (int k = 1; (unsigned int)complete < target.length(); k++)
{
//main loop generates offspring and chooses the next ancestor thru evolution().
parents[k] = evolution(parents[k-1], target, &complete);
cout << parents[k];//output
count++;//generation counter
cout << tab << "|| Good Chars: " << complete;
cout << " || Count: " << count << endl;
}
cout << endl << "Generations to completion: " << count << endl;
cout << "Probability of this string randomly mutating without natural selection: ";
cout << endl << "One in " << probability(target.length()) << endl;
cout << endl << "Enter to exit." << endl;
getchar();
}
string evolution(string initial, string target, int *complete)
{
//controls the evolutionary process through calls to the other functions
string s[8], nancestor;//s-array of 8 strings, nancestor - next ancestor
int alike[8], who, size = target.length();
//alike-int array holding the number of correct chars
//who - allows the winner to be accessed without calling wholives() twice. probably not needed
reproduce(initial, s, target, size); //makes the babies
for (int y = 0; y < 8; y++) alike[y] = compare(target,s[y]); //gets the #of correct chars for each
nancestor = s[wholives(alike, &who)];//identifies the chosen
*complete = alike[who]; //CBR to MAIN(), allows main loop to know when it is finished
return nancestor;
}
int compare(string target,string s)//outputs # of correct characters
{
int alike = 0;
for (int i = 0; (unsigned int)i < target.length(); i++)
{
if (target[i] == s[i]) alike++;
}
return alike;
}
void reproduce(string ancestor, string s[], string target, int length)
{//makes the babies
int mut = mutations();//# of mutations
for (int i = 0; i <= 7; i++) s[i] = ancestor;//babies are first copies of ancestor
for (int k = 0; k <= 7; k++)
{
for (int j = 0; j <= mut; j++)//then they are mutated
{
int L = whichone(ancestor.length());
if (ancestor[L] == target[L]) continue;//if a char is correct don't change it
s[k].replace(L, 1, 1, chargen());
}
}
}
char chargen(void)
{
char r,s;
while (1)
{
s = rand() % 100; //could be more efficient (do research on rand division and such)
r = s + 25;
if ( (r == 44) || (r == 46) || (r == 32) || (r == 33) || (r == 63) || (r == 59) ||\
(r == 58) || ( (r >= 65) && (r <= 90) ) || ((r >= 97) && (r <= 122)) || \
(r == 39) || (r == 34)) //upper, lower, space, punctuation (ASCII)
break;
else continue;
}
return r;
}
int whichone(int length)//randomly determines which char to change
{ //randomly determines which char to change
double x = RAND_MAX/length;
double r = ((rand()/x));
return (int)r;
}
int mutations() //random # of mutations
{
double mut = ((rand() / 3276.002442));//up to ten
return (int) mut;
}
string sentgen(int length)
{ //generates initial sentence
string st;
for(int i = 0; i < length/*strlen(s)*/; i++) st += chargen();
return st;
}
int wholives(int alike[8], int *who)
{ //goes thru alike array and chooses next ancestor
int winner = 0;
for (int i = 0; i < 8; i++)
{
if (alike[i] > alike[winner])
{
winner = i;
}
}
*who = winner;//call by reference
return winner;
}
string initialize()
{ //User input
string target;
int choice = 0;
cout << "1. Default starting sentence." << endl \
<< "2. Enter starting sentence." << endl;
cin >> choice;
if (choice == 2)
{
cout <<endl<< "Upper and lower case letters, spaces, and common punctuation are \
allowed." << endl << "Input target sentence: " ;
cin.ignore(); cin.clear();
getline(cin, target);
cout << endl;
}
else target = "Also Spracht Zarathustra";
cout << "Target: " << target << endl;
return target;
}
long double probability(int length)
{ //could be inline
return pow((long double)61, (long double)length);
void introduction()
{
cout<<"This program attempts to demonstrate the fact" << endl;
cout<<"that natural selection is not random chance, but a chance-" << endl;
cout<<"driven process guided by positive and negative feedback." << endl;
cout<<"This concept is demonstrated by randomly generating an" << endl;
cout<<"""ancestor"" sentence of the length of the target string." << endl;
cout<<"Each ""generation"" eight babies are born with variations." << endl;
cout<<"The offspring closest to the target sentence survive as a" <<endl;
cout<<"result of natural selection and passes it's ""genes"" on " <<endl;
cout<<"to the next generation with a random number of mutations." << endl;
cout<<"The remaining progeny die off. One unrealistic aspect of " <<endl;
cout<<"the simulation is the frequency of mutation, but this does" <<endl;
cout<<"not ruin the concept; it only shrinks the number of " << endl;
cout<<"generations required for convenience (and to prevent stack" << endl;
cout<<"overflow)." << endl << endl;
cout<<"The credit for the idea goes to Richard Dawkins in "<< endl;
cout<<"'The Blind Watchmaker'. I just implemented the program" << endl;
cout<<"for practice in coding." << endl << endl;