-2

EDIT: Adding that this is basically how I wanted it to work:

User input #1:

(#1 Option 1a)(#1 Option 1b)

(#1 Option 2a)(#1 Option 2b)

(#1 Option 3a)(Option3b)

User input #2:

(#2 Option 1a)(#2 Option 1b)

(#2 Option 2a)(#2 Option 2b)

(#2 Option 3a)(#2 Option3b)

From user input #1, there is a

  • 50% chance of either option 1a or 1b
  • 50% chance of either option 2a or 2b
  • 50% chance of either option 3a or 3b

From user input #2, there is a

  • 50% chance of either option 1a or 1b
  • 50% chance of either option 2a or 2b
  • 50% chance of either option 3a or 3b

If the randomly rolled chance is more than 50 out of 100, then it chooses "a". If the randomly rolled chance is equal or less than 50 out of 100, then it chooses "b".

(#1 randomized choice of 1st gene a or b)(#2 randomized choice of 1st gene a or b)

(#1 randomized choice 2nd gene a or b)(#2 randomized choice 2nd gene a or b)

(#1 randomized choice of 3rd gene a or b)(#2 randomized choice of 3rd gene a or b)

and so on and so forth.


I just started coding with c++ a few days ago and I started on this project to get the ball rolling.

So far it has worked, but I'm running into an issue where I want to remove a sub(?) string "nn" from the results of previous cout(s). However, since it's already printed to the console, I don't think I can edit it. Is there any way around this?

This project is an "RNG" roller and for those who are familiar with MMOs, might know how if a player is about to receive loot, the game decides what you get by chance.

In this project, I am having the user input the genetic code (genotype) of the parent horses, and have this spit out a randomly generated genotype of the foal (baby horse) given the possibilities from their parents. (I hope that made sense.)

I've tried adding

start_position_to_erase = find("nn");
erase(start_position_to_erase, 2);

at the end to erase any "nn" that would pop up as a result of the gene "D" (dun) not being present in the parents' gene and subsequently the foals, but it's spitting out errors on how you have to specify a string so it can erase from that said string.

#include <iostream>
#include <algorithm>
#include <string>
#include <cstdlib>
#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"};

cout << "Enter the mare's genotype: "; getline(cin, mgenotype);
cout << "Enter the sire's genotype: "; getline(cin, sgenotype);

srand((int)time(0));

// "A" (and it's variants "At" and "A+") gene MARE ----------------------------------------------------------------
if (mgenotype.find ("AtAt") != string::npos){ cout << "At" ;}
else if (mgenotype.find ("A+A+") != string::npos){ cout << "A+" ;}
else if (mgenotype.find ("AA") != string::npos){ cout << "A";}
else if (mgenotype.find ("aa") != string::npos){ cout << "a";}

else if (mgenotype.find ("Ata") != string::npos || mgenotype.find ("aAt" ) != string::npos){
    Mchance[1] = (rand() % 100);
    if (Mchance[1] <= "50") { cout << "At" ;}
    else { cout << "a" ;}}

else if (mgenotype.find ("A+a") != string::npos || mgenotype.find ("aA+") != string::npos){
    Mchance[1] = (rand() % 100);
    if (Mchance[1] <= "50") { cout << "A+" ;}
    else { cout << "a" ;}}

else if (mgenotype.find ("Aa") != string::npos || mgenotype.find ("aA")!= string::npos) {
    Mchance[1] = (rand() % 100);
    if (Mchance[1] <= "50") { cout << "A" ;}
    else { cout << "a" ;}}

else {}

// "A" (and it's variants "At" and "A+") gene SIRE ----------------------------------------------------------------
if (sgenotype.find ("AtAt") != string::npos){ cout << "At" ;}
else if (sgenotype.find ("A+A+") != string::npos){ cout << "A+" ;}
else if (sgenotype.find ("AA") != string::npos){ cout << "A";}
else if (sgenotype.find ("aa") != string::npos){ cout << "a";}

else if (sgenotype.find ("Ata") != string::npos || sgenotype.find ("aAt") != string::npos){
    Schance[1] = (rand() % 100);
    if (Schance[1] <= "50") { cout << "At" ;}
    else { cout << "a" ;}}

else if (sgenotype.find ("A+a") != string::npos || sgenotype.find ("aA+") != string::npos){
    Schance[1] = (rand() % 100);
    if (Schance[1] <= "50") { cout << "A+" ;}
    else { cout << "a" ;}}

else if (sgenotype.find ("Aa") != string::npos || sgenotype.find ("aA")!= string::npos) {
    Schance[1] = (rand() % 100);
    if (Schance[1] <= "50") { cout << "A" ;}
    else { cout << "a" ;}}

else {}

cout << " ";

// "D" gene MARE ----------------------------------------------------------------
if (mgenotype.find ("DD") != string::npos){ cout << "D" ;}
else if (mgenotype.find ("nn") != string::npos || mgenotype.find ("")!= string::npos ){ cout << "n";}

else if (mgenotype.find ("Dn") != string::npos || mgenotype.find ("nD") != string::npos) {
    Mchance[2] = (rand() % 100);
    if (Mchance[2] <= "50") { cout << "D" ;}
    else { cout << "n" ;}}

else {}

// "D" gene SIRE ----------------------------------------------------------------
if (sgenotype.find ("DD") != string::npos){ cout << "D" ;}
else if (sgenotype.find ("nn") != string::npos || sgenotype.find ("") != string::npos){ cout << "n";}

else if (sgenotype.find ("Dn") != string::npos || sgenotype.find ("nD") != string::npos) {
    Schance[2] = (rand() % 100);
    if (Schance[2] <= "50") { cout << "D" ;}
    else { cout << "n" ;}}

else {}

cout << " ";

As you can see from the vector<std::string> Mchance = { and Schance line, I have quite a list of genes I want to add by the end and having 12 or more "nn" would be annoying and untidy.

Even worse, if there was a gene in the middle that was passed on to the foal, but the rest weren't, it would be very hard to read. Therefore, I'd just like to keep the ones that would have a gene that was passed on to its foal.

I have a feeling I'll have to get the code to print to a file and edit from there, but I have no idea how to do that as well.

Any help or directions would be greatly appreciated. Thank you!

Mapleia
  • 3
  • 3
  • `but it's spitting out errors on how you have to specify a string...` I wonder why. – DimChtz Apr 21 '19 at 22:00
  • That whole thing just screams for you to use a lookup table or map container to store all those combinations. Is there any change you can streamline it down to just one if clause in each block so it is easier to read and follow. Also, include the error you are receiving copy/pasted verbatim from the compile output and indicate which line it is occurring on. Read through how to make a [mcve] for some pointers. – Retired Ninja Apr 21 '19 at 22:06
  • https://stackoverflow.com/a/20595061 – ppetraki Apr 21 '19 at 22:07
  • Thank you both for guiding me to resources. I'll be sure to read them up. Sorry for the bad post. – Mapleia Apr 22 '19 at 00:21

2 Answers2

1

It's really unclear to me what you're hoping to do, and your code is very hard to read, but I was bored so I came up with something that is both much simpler and may solve your problem of building your output conditionally before displaying it.

#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>

struct ConditionalReplacement
{
    int threshold;
    std::string choices[2];
};

std::map<std::string, std::string> simple_replacements =
{
    {"AtAt", "At"},
    {"A+A+", "A+"},
    {"AA", "A"},
    {"aa", "a"},
    {"DD", "D"},
    {"nn", "n"},
};

std::map<std::string, ConditionalReplacement> conditional_replacements =
{
    {"Ata", {50, "At", "a"}},
    {"aAt", {50, "At", "a"}},
    {"A+a", {50, "A+", "a"}},
    {"aA+", {50, "A+", "a"}},
    {"Aa", {50, "A", "a"}},
    {"aA", {50, "A", "a"}},
    {"Dn", {50, "D", "n"}},
    {"nD", {50, "D", "n"}},
};

void HandleReplacements(const std::string &in, std::stringstream &out, const std::string &default_for_empty_src)
{
    if (in.empty())
    {
        out << std::right << std::setw(6) << ("'" + in + "'")
            << std::left << " = " << ("'" + default_for_empty_src + "'");
        return;
    }
    for (const auto &item : simple_replacements)
    {
        if (in.find(item.first) != std::string::npos)
        {
            out << std::right << std::setw(6) << ("'" + in + "'")
                << std::left << " = " << ("'" + item.second + "'");
            return;
        }
    }
    for (const auto &item : conditional_replacements)
    {
        if (in.find(item.first) != std::string::npos)
        {
            int r = rand() % 100;
            int index = 1 - (r <= item.second.threshold);
            out << "r = " << std::setw(2) << r << " : " << std::right << std::setw(6) << ("'" + in + "'")
                << std::left << " = " << ("'" + item.second.choices[index] + "'");
            return;
        }
    }
}

int main()
{
    srand((int)time(0));

    std::string mgenotypes[] = { "AtAt", "AA", "DD", "", "Ata", "A+a", "Aa", "Dn" };
    std::string sgenotypes[] = { "", "A+A+", "aa", "nn", "aAt", "aA+", "aA", "nD" };
    std::stringstream output;

    for (const auto &mgenotype : mgenotypes)
    {
        HandleReplacements(mgenotype, output, "n");
        std::cout << output.str() << "\n";
        output.str("");
    }
    for (const auto &sgenotype : sgenotypes)
    {
        HandleReplacements(sgenotype, output, "n");
        std::cout << output.str() << "\n";
        output.str("");
    }

    return 0;
}

Since you said you just started C++ a few days ago it's possible that this may be overwhelming, and I won't explain each line, but I will try and explain the concepts.

If you find yourself repeating a lot of very similar code don't keep doing it. Take a look at why you're repeating that code and try and abstract that away into a function or series of functions. The wikipedia article on the DRY principle has some links to other reading about this. The best source, IMO, is the book The Pragmatic Programmer. I recommend it to anyone that has not read it.

std::map and other associative containers are awesome. If you need to replace something with something else just add the source as the key and the substitution as the value and you've got an instant lookup table you can iterate through or search. Combine that with a function to do the work and you're probably close to all set.

There are no time machines that will easily let you go back and change previous output, but you don't need that. Instead, gather all of the data you need to generate the output and then generate it all at once. std::stringstream can be helpful for this in the simple case, but even then you can't go backwards easily so you might consider not doing any output at all and just putting all your data into a model that you can output when the model is complete and accurate.

I wussed out and used stringstream anyway, mostly because I am uncertain what your end goal is.

Anyway, perhaps this helps a little. In the future I hope you'll ask more questions if you need help, but take some time first and make sure you're explaining everything the best you can and that you've reduced your problem to a manageable size. Reading through how to create a [mcve] can help with that.

Good luck!

Retired Ninja
  • 4,785
  • 3
  • 25
  • 35
  • Thank you so much for writing this up. I'm sorry my code was hard to read, but I'll make sure to study your example so I can improve my project. I was kind of scared I didn't know what to look for so I kind of went with whatever google had for my (I can assume) very vague questions but I think stringstream would be the exact thing I'm looking for. Again, thank you. Maybe I'll come back with a better explained post and better questions. – Mapleia Apr 21 '19 at 23:59
0

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.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • **So if I understand this correctly, I need to:** 1) Remove the unneeded ```#include```(s) that were in my code. 2) Fix up the comparison of the vector string that already has a value to the not integer values by bringing in a separate integer variable for the random number. 3) Make sure that there was actual input inputted by the user (and give an error if there wasn't one). 4) Edit the format so it's easy to follow for other coders/readers. 5) Store the results in a vector by adding to it with ```.push_back``` 6) Provide input/output examples when asking on stack overflow. – Mapleia Apr 22 '19 at 23:59
  • @Mapleia - yes, hold on and I'll drop concise example removing the unused vectors you have in your code. – David C. Rankin Apr 23 '19 at 03:48
  • Wow, this vector string is so useful! Thank you so much for taking the time to type this up, your code is so much easier to read than mine! Sorry to ask another question, is it possible to alternate the output of ```Mresults``` and ```Sresults```? Like **```Mresults of A Sresults of A```** "space here" **```Mresults of D Sresults of D```**? What I want to say, does vector string allows alternating the strings of two different vector strings? Or could that be solved with ```.push_back``` of all of the results into 1 string? – Mapleia Apr 23 '19 at 06:01