If I understand the goal of your code, you have a number of fundamental problems. Take for example:
vector<std::string> Mchance = {"E", "A", "D", "Cr", "Ch", "Z", "G", "O",
"To", "Sb", "W", "Rn", "Spl", "Prl"};
...
Mchance[1] = (rand() % 100);
if (Mchance[1] <= "50") {
cout << "At";
}
else {
cout << "a";
}
Mchance[1] = (rand() % 100)
is simply wrong. You are attempting to overwrite the second string in the vector of strings Mchance
with an integer value. Instead, it looks like what you intend is to use the integer value to make a random choice between outputting "At"
or "a"
. To do that you do not need to overwrite anything. Simply use a separate integer variable to hold the result of rand() % 100
filled before your set of conditionals, e.g.
vector<std::string> Mchance = {"E", "A", "D", "Cr", "Ch", "Z", "G", "O",
"To", "Sb", "W", "Rn", "Spl", "Prl"};
int randnum;
...
srand (time(NULL));
randnum = rand() % 100; /* random number for mare test */
...
if (randnum <= 50) {
cout << "At\n"; /* note the addition of '\n', adjust to you needs */
}
else {
cout << "a\n";
}
Further note in Mchance[1] = (rand() % 100); if (Mchance[1] <= "50")
you are attempting to compare the string Mchance[1]
(notwithstanding the assignment of the int
return from rand()
) with <=
to the string "50"
, this isn't what you want. You want to compare the integer result from rand() % 100
with the integer 50
not the string "50"
.
If you take input, validate that you received the input you expected. At minimum, validate the return of the input function, e.g.
cout << "Enter the mare's genotype: ";
if (!getline(cin, mgenotype)) {
cerr << "error: user canceled input.\n";
return 1;
}
Additionally, you need to validate that you did match a substring in your first two conditional blocks, such as:
if (mgenotype.find ("AtAt") != string::npos) {
cout << "At\n";
}
else if (...) {
...
}
else { /* handle non-match */
cerr << "error: mgenotype not found.\n";
return 1;
}
There is no reason to proceed to the "D"
tests if you fail to match the mare and sire types above.
Next, two notes on program formatting: (1) know what headers your program requires and don't include extraneous headers (doesn't hurt, just very telling of whether you know what is going on), e.g.
#include <iostream>
// #include <algorithm>
#include <string>
// #include <cstdlib>
#include <ctime>
#include <vector>
(2) try and format your code so the lines are reasonable in length (that is to personal taste, but I try and limit line length to around 80 chars). You are free to break lines anywhere that makes sense to you, e.g.
else if (mgenotype.find ("Ata") != string::npos ||
mgenotype.find ("aAt" ) != string::npos) {
Lastly, your "How do I back up..." question, isn't a question about backing up. It appears you want to capture the results of the mgenotype
and sgenotype
conditional tests rather than just outputting with cout << ...
. Either build a string to contain the results, or build another vector of strings to store the values. Something similar to:
vector<std::string> Mresults, Sresults;
Then instead of cout << "At";
(or in addition to it), you can simply Mresults.push_back ("At");
to capture the string in a vector. When you need to determine what type of foal is available, you have Mresults
and Sresults
holding the results of your conditional tests.
Fixing the points above will allow your logic to work closer to what you have intended. Retired Ninja makes the good point that your code is largely repetitive and you probably want to refactor your two primary type of conditional blocks into a function. That can help keep the logic flow within main()
cleaner and give you one function for each repeated set of logic to validate, rather than having to remember to make changes to both blocks in main()
when you change one or the other. Putting corrections together, but leaving the refactoring into functions and addition of results vectors to you, you could do something similar to:
#include <iostream>
#include <string>
#include <ctime>
#include <vector>
using namespace std;
int main() {
string mgenotype, sgenotype, start_position_to_erase;
vector<std::string> Mchance = {"E", "A", "D", "Cr", "Ch", "Z", "G", "O",
"To", "Sb", "W", "Rn", "Spl", "Prl"};
vector<std::string> Schance = {"E", "A", "D", "Cr", "Ch", "Z", "G", "O",
"To", "Sb", "W", "Rn", "Spl", "Prl"};
int randnum;
cout << "Enter the mare's genotype: ";
if (!getline(cin, mgenotype)) {
cerr << "error: user canceled input.\n";
return 1;
}
cout << "Enter the sire's genotype: ";
if (!getline(cin, sgenotype)) {
cerr << "error: user canceled input.\n";
return 1;
}
srand (time(NULL));
randnum = rand() % 100; /* random number for mare test */
// "A" (and it's variants "At" and "A+") gene MARE
cout << "mgenotype : ";
if (mgenotype.find ("AtAt") != string::npos) {
cout << "At\n";
}
else if (mgenotype.find ("A+A+") != string::npos) {
cout << "A+\n";
}
else if (mgenotype.find ("AA") != string::npos) {
cout << "A\n";
}
else if (mgenotype.find ("aa") != string::npos) {
cout << "a\n";
}
else if (mgenotype.find ("Ata") != string::npos ||
mgenotype.find ("aAt" ) != string::npos) {
if (randnum <= 50) {
cout << "At\n";
}
else {
cout << "a\n";
}
}
else if (mgenotype.find ("A+a") != string::npos ||
mgenotype.find ("aA+") != string::npos) {
if (randnum <= 50)
cout << "A+\n";
else
cout << "a\n";
}
else if (mgenotype.find ("Aa") != string::npos ||
mgenotype.find ("aA")!= string::npos) {
if (randnum <= 50)
cout << "A\n";
else
cout << "a\n";
}
else {
cerr << "error: mgenotype not found.\n";
return 1;
}
randnum = rand() % 100; /* random number for sire test */
cout << "sgenotype : ";
// "A" (and it's variants "At" and "A+") gene SIRE
if (sgenotype.find ("AtAt") != string::npos)
cout << "At\n";
else if (sgenotype.find ("A+A+") != string::npos)
cout << "A+\n";
else if (sgenotype.find ("AA") != string::npos)
cout << "A\n";
else if (sgenotype.find ("aa") != string::npos)
cout << "a\n";
else if (sgenotype.find ("Ata") != string::npos ||
sgenotype.find ("aAt") != string::npos) {
if (randnum <= 50)
cout << "At\n" ;
else
cout << "a\n";
}
else if (sgenotype.find ("A+a") != string::npos ||
sgenotype.find ("aA+") != string::npos) {
if (randnum <= 50)
cout << "A+\n";
else
cout << "a\n";
}
else if (sgenotype.find ("Aa") != string::npos ||
sgenotype.find ("aA")!= string::npos) {
if (randnum <= 50)
cout << "A\n";
else
cout << "a\n";
}
else {
cerr << "error: sgenotype not found.\n";
return 1;
}
randnum = rand() % 100; /* random number for mare "D" test */
// "D" gene MARE
cout << "mgenotypeD: ";
if (mgenotype.find ("DD") != string::npos)
cout << "D\n";
else if (mgenotype.find ("nn") != string::npos ||
mgenotype.find ("")!= string::npos )
cout << "n\n";
else if (mgenotype.find ("Dn") != string::npos ||
mgenotype.find ("nD") != string::npos) {
if (randnum <= 50)
cout << "D\n" ;
else
cout << "n\n";
}
randnum = rand() % 100; /* random number for sire "DD" test */
// "D" gene SIRE
cout << "sgenotypeD: ";
if (sgenotype.find ("DD") != string::npos)
cout << "D\n";
else if (sgenotype.find ("nn") != string::npos ||
sgenotype.find ("") != string::npos)
cout << "n\n";
else if (sgenotype.find ("Dn") != string::npos ||
sgenotype.find ("nD") != string::npos) {
if (randnum <= 50)
cout << "D\n";
else
cout << "n\n";
}
}
(note: the formatting of the second block of if...else if...
removes the {..}
from single expression blocks since you seemed to be trying to shorten your code length by putting the entire conditional blocks on a single-line. Better to proper indention (at minimum) if you do not include enclosing braces for each conditional. It's a matter of style, entirely up to you, but it does make your code easier to follow.
Example Use/Output
While you didn't provide example input, it was apparent the mgenotype
and sgenotype
were to contain at least substrings that would match your conditional logic. The following just ensure that they do.
$ ./bin/mare-foal
Enter the mare's genotype: Ata
Enter the sire's genotype: A+a
mgenotype : a
sgenotype : a
mgenotypeD: n
sgenotypeD: n
Edit Per-Summary in Comments
In order to save the values that result from your conditional expressions, you can simply save the individual strings determined for both the sire and mare in another vector of strings. (call them results, say Mresults
for mare and Sresults
for sire). You can reduce the overall confusion in your code by moving the conditionals to simple functions. That will clean up your main()
to:
string mgenotype, sgenotype, tmp;
/* vectors to store results of tests instead of outputting */
vector<std::string> Mresults, Sresults;
cout << "Enter the mare's genotype: ";
if (!getline(cin, mgenotype)) {
cerr << "error: user canceled input.\n";
return 1;
}
cout << "Enter the sire's genotype: ";
if (!getline(cin, sgenotype)) {
cerr << "error: user canceled input.\n";
return 1;
}
srand (time(NULL)); /* seed ranndom number generator */
if (!gettypes (Mresults, mgenotype)) /* parse mgenotype */
return 1;
if (!gettypes (Sresults, sgenotype)) /* parse sgenotype */
return 1;
Putting a trimmed down version together, you could do:
#include <iostream>
#include <iomanip>
#include <string>
#include <ctime>
#include <vector>
using namespace std;
/* parse function prototype */
int gettypes (vector<std::string>& results, const string& genotype);
int main (void) {
string mgenotype, sgenotype, tmp;
/* vectors to store results of tests instead of outputting */
vector<std::string> Mresults, Sresults;
cout << "Enter the mare's genotype: ";
if (!getline(cin, mgenotype)) {
cerr << "error: user canceled input.\n";
return 1;
}
cout << "Enter the sire's genotype: ";
if (!getline(cin, sgenotype)) {
cerr << "error: user canceled input.\n";
return 1;
}
srand (time(NULL)); /* seed ranndom number generator */
if (!gettypes (Mresults, mgenotype)) /* parse mgenotype */
return 1;
if (!gettypes (Sresults, sgenotype)) /* parse sgenotype */
return 1;
cout << "Mresults:"; /* output Mresults */
for (auto& s : Mresults)
cout << " " << setw(3) << s;
cout << '\n';
cout << "Sresults:"; /* output Sresults */
for (auto& s : Sresults)
cout << " " << setw(3) << s;
cout << '\n';
}
/* function parsing substring from string genotype,
* returns string value on success, empty-string on failure.
*/
string getAtype (const string& genotype)
{
int randnum = rand() % 100;
if (genotype.find ("AtAt") != string::npos)
return "At";
else if (genotype.find ("A+A+") != string::npos)
return "A+";
else if (genotype.find ("AA") != string::npos)
return "A";
else if (genotype.find ("aa") != string::npos)
return "a";
else if (genotype.find ("Ata") != string::npos ||
genotype.find ("aAt") != string::npos) {
if (randnum <= 50)
return "At";
else
return "a";
}
else if (genotype.find ("A+a") != string::npos ||
genotype.find ("aA+") != string::npos) {
if (randnum <= 50)
return "A+";
else
return "a";
}
else if (genotype.find ("Aa") != string::npos ||
genotype.find ("aA")!= string::npos) {
if (randnum <= 50)
return "A";
else
return "a";
}
cerr << "error: genotype not found.\n";
return "";
}
/* function parsing substring from string genotype for "D" tests,
* returns string value on success, empty-string on failure.
*/
string getDtype (const string& genotype)
{
int randnum = rand() % 100;
if (genotype.find ("DD") != string::npos)
return "D";
else if (genotype.find ("nn") != string::npos || ! genotype.empty() )
// genotype.find ("")!= string::npos)
return "n";
else if (genotype.find ("Dn") != string::npos ||
genotype.find ("nD") != string::npos) {
if (randnum <= 50)
return "D";
else
return "n";
}
cerr << "error: genotypeD not found.\n";
return "";
}
/* calls all conditional tests for string genotypes, stores results
* strings in results on success and returns 1, otherwise returns 0.
*/
int gettypes (vector<std::string>& results, const string& genotype)
{
string tmp;
tmp = getAtype (genotype); /* parse values in genotype */
if (tmp.empty()) /* validate/handle error */
return 0;
results.push_back(tmp); /* add result to Mresults */
tmp = getDtype (genotype); /* now "D" test for each */
if (tmp.empty())
return 0;
results.push_back(tmp);
return 1;
}
Example Use/Output
$ ./bin/mare-foal
Enter the mare's genotype: AtanD
Enter the sire's genotype: A+aDD
Mresults: At n
Sresults: A+ D
Printing The Results In Columns Rather Than Rows
If you want to change the output from printing all the mare's data on one line followed by the sire's data on the next -- to printing the results in tabular form with the data for the mare in one column followed by data for the sire in the next, you will change the way you loop over the stored results.
Rather than using the range-based for
loop to loop over one vector of results and then a separate loop to do the same for the next vector, you need a way to coordinate printing a element from each vector in a single-loop. C++ provides std::vector::begin and std::vector::end iterators that provide a pointer to elements in the vector that you can use in a traditional for
to iterate over the contents of the vector until the vector.end()
iterator is reached.
By creating an iterator to the Mresults
vector and another to the Sresults
vector, you can use a single-loop and access the elements of each vector in-order. (just like using two indexes, say int i, j;
for two arrays and looping incrementing i++, j++
in the loop).
To output your results column-wise, replace the two range based for loops currently outputting the Mresults
and Sresults
vector with the following:
cout << "\nresults:\n Mare Sire\n";
vector<string>::const_iterator iterM = Mresults.begin();
vector<string>::const_iterator iterS = Sresults.begin();
for (; iterM != Mresults.end() && iterS != Sresults.end();
iterM++, iterS++) {
cout << " " << setw(4) << *iterM <<
" " << setw(4) << *iterS << '\n';
}
Example Use/Output
$ ./bin/mare-foal
Enter the mare's genotype: AtanD
Enter the sire's genotype: A+aDD
results:
Mare Sire
a a
n D
or
$ ./bin/mare-foal
Enter the mare's genotype: AtanD
Enter the sire's genotype: A+aDD
results:
Mare Sire
At A+
n D
Let me know if this is what you were looking for.