3
\$\begingroup\$

We were given a homework assignment to create a C++ program that generates 3 different random numbers each time and the user is supposed to guess the three of them AND in order. I already achieved that, however I'm not very satisfied with how long my code is, especially with the fact that I had so many if statements. We were told at the beginning of the year that good programming is the ability to write less but more efficiently. (We haven't learned anything about arrays or vectors yet) but I'm still curious to know what are other ways to compare the 3 generated numbers and the 3 user input numbers, all while keeping the order criterion in mind)

PS. 3 guesses of 3 numbers in order -> User wins. If the users fails to guess the 3 numbers in their order within 10 attempts, they lose + I also kept the generated numbers to print out just for testing purposes. ALSO, we were required to have 3 functions so that's why I didn't write everything in just one.

Long story short, is there any way to write the conditions more concisely and efficiently instead of having to do a for statement for each and every possibility? I still haven't learned arrays since I'm just beginning but all suggestions and methods applicable in C++ are fascinatingly admired and highly appreciated, thank you very much!

Here's my code:

#include <iostream>
using namespace std;

#include <cstdlib>
#include <iomanip>
#include <ctime>

void randnumbers(int&, int&, int&); // Random Numbers Prototype
void guessnumbers(int&, int&, int&); // Guess Numbers Prototype


int main()
{

    // --> Guesses of Numbers and their Orders
    int guesses = 0;

    for (int counter = 0; counter <= 10; counter++)
    {

        while (guesses <= 2)
        {


            //Random Numbers
            int a, b, c;
            randnumbers(a, b, c);

            //Guessed Numbers
            int d, e, f;
            guessnumbers(d, e, f);


            // IF 3 GUESSES
            //IF A=D, A=E, A=F
            if (a == d && b == f && c == e)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            else if (a == d && b == e && c == f)
            {
                cout << "3 numbers guessed!.. 3 numbers in order!..\n";
                guesses++;
                break;
            }

            else if (a == e && b == d && c == f)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            else if (a == e && b == f && c == d)
            {
                cout << "3 numbers guessed!.. 0 numbers in order..\n";
                break;
            }

            else if (a == f && b == e && c == d)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            else if (a == f && b == d && c == e)
            {
                cout << "3 numbers guessed!.. 0 numbers in order..\n";
                guesses++;
                break;
            }

            //IF B=D, B=E, B=F
            else if (b == d && a == e && c == f)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            else if (b == d && a == e && c == e)
            {
                cout << "3 numbers guessed!.. 0 numbers in order..\n";
                break;
            }

            else if (b == e && a == d && c == f)
            {
                cout << "3 numbers guessed!.. 3 numbers in order..\n";
                guesses++;
                break;
            }

            else if (b == e && a == f && c == d)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            else if (b == f && a == e && c == d)
            {
                cout << "3 numbers guessed!.. 0 numers in order..\n";
                break;
            }

            else if (b == f && a == d && c == e)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            // IF C=D, C=E, C=F

            else if (c == d && a == e && d == f)
            {
                cout << "3 numbers guessed!.. 0 number in order..\n";
                break;
            }

            else if (c == d && a == f && b == e)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            else if (c == e && a == d && b == f)
            {
                cout << "3 numbers guessed!.. 1 number in order..\n";
                break;
            }

            else if (c == e && a == f && b == d)
            {
                cout << "3 numbers guessed!.. 0 numbers in order..\n";
                break;
            }

            else if (c == f && a == e && b == d)
            {
                cout << "3 numbers guessed!.. 0 numbers in order..\n";
                break;
            }

            else if (c == f && a == d && b == e)
            {
                cout << "3 numbers guessed! 3 numbers in order!..\n";
                guesses++;
                break;
            }

            //IF 2 GUESSES

            else if (a == d && c == f)
            {
                cout << "2 numbers guessed.. 2 numbers in order..\n";
                break;
            }

            else if (a == d && c == e)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (a == d && b == f)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (a == d && b == e)
            {
                cout << "2 numbers guessed.. 2 numbers in order..\n";
                break;
            }


            else if (a == e && c == f)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (a == e && c == d)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (a == e && b == f)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (a == e && b == d)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }


            else if (a == f && c == d)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (a == f && c == e)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (a == f && b == d)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (a == f && b == e)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }


            else if (b == d && c == f)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (b == d && c == e)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (b == d && a == f)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (b == d && a == e)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }


            else if (b == e && c == f)
            {
                cout << "2 numbers guessed.. 2 numbers in order..\n";
                break;
            }

            else if (b == e && c == d)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (b == e && a == f)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (b == e && a == d)
            {
                cout << "2 numbers guessed.. 2 numbers in order..\n";
                break;
            }


            else if (b == f && c == d)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }


            else if (b == f && c == e)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }


            else if (b == f && a == d)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (b == f && a == e)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }


            else if (c == d && a == f)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }


            else if (c == d && a == e)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (c == d && b == f)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (c == d && b == e)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }


            else if (c == e && a == f)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (c == e && a == d)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (c == e && b == f)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }

            else if (c == e && b == d)
            {
                cout << "2 numbers guessed.. 0 numbers in order..\n";
                break;
            }


            else if (c == f && a == d)
            {
                cout << "2 numbers guessed.. 2 numbers in order..\n";
                break;
            }

            else if (c == f && a == e)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (c == f && b == d)
            {
                cout << "2 numbers guessed.. 1 number in order..\n";
                break;
            }

            else if (c == f && b == e)
            {
                cout << "2 numbers guessed.. 2 numbers in order..\n";
                break;
            }

            //IF ONE GUESS

            else if (a == d || b == e || c == f)
            {
                cout << "1 number guessed.. 1 number in order..\n";
                break;
            }

            else if (a == e || a == f || b == d || b == f || c == d || c == e)
            {
                cout << "1 number guessed.. 0 numbers in order..\n";
                break;
            }

            else
            {
                cout << "0 numbers guessed.. 0 numbers in order..\n";
                break;
            }

        }
    }

    if (guesses >= 3)
        cout << "Congratulations, you guessed the numbers in order 3 times! You win..\n";

    else if (guesses<3)
        cout << "You failed to guess the numbers in order over an attempt of 10 times! You lose..\n";

    system("pause");
    return 0;
}

void randnumbers(int& x, int& y, int &z)
{
    srand(time(0));
    x = 1 + rand() % 6;
    cout << x << setw(2);

    do {
        y = 1 + rand() % 6;
    } while (y == x);
    cout << y << setw(2);

    do {
        z = 1 + rand() % 6;
    } while (z == x || z == y);
    cout << z << setw(2);

}

void guessnumbers(int& nb1, int& nb2, int& nb3)
{

    cout << "Guess the 3 numbers from 1-->6: ";
    cin >> nb1 >> nb2 >> nb3;

}
\$\endgroup\$
  • \$\begingroup\$ You could sort a,b,c and d,e,f in two 3-item arrays A[3] and B[3], then quickly test how many numbers were guessed by scanning the arrays with two wandering pointers: you start with 3 vs. 3 numbers; If the least item of A is smaller than the least one in B, drop it and continue with 2 vs. 3, similary in opposite case; and if they are equal, count the hit and drop both items, proceeding with remaining 2 vs. 2. Finally you know how many numbers were guessed. And the direct comparision of a to d, b to e and c to f will tell how many of them are in right positions. \$\endgroup\$ – CiaPan Nov 3 '16 at 6:36
  • \$\begingroup\$ @CiaPan Interesting suggestion, thanks! However can you elaborate a bit further or just give a short example on how to compare the two arrays using the "two wandering points"? \$\endgroup\$ – Jad Nov 3 '16 at 14:20
  • \$\begingroup\$ Please see my answer. I apologize I didn't manage to publish it sooner, but I'm a bit more busy IRL these days than usual. \$\endgroup\$ – CiaPan Nov 5 '16 at 20:42
  • \$\begingroup\$ @CiaPan Aw no, don't apologise, it's totally fine! I really appreciate the help/ effort! Have a wonderful weekend and thank you! :-) \$\endgroup\$ – Jad Nov 6 '16 at 4:55
1
\$\begingroup\$

Do the easiest work first and avoid if statement while you can.

Just, the easiest work is count the numbers guessed in order:

int success_in_order = 0;

if (a == d)
    success_in_order++;
if (b == e)
    success_in_order++;
if (c == f)
    success_in_order++;

cout << sucess_in_order << " numbers in order!" << endl;

What about numbers guessed in no order? The trick is put both in a same way. For example, we could take the max of (a, b, c), the min of (a, b, c) and the midle value.

Let's start for the max, we have to implement the max function:

int max(int a, int b,int c)
{
    if (a > b) {
      if (a > c)
        return a;
      else
        return c;
    }
    else if (b > c)
        return b;
    else
        return c;
}

The middle function and the min function works in a similar way.

Just the algorithm looks now as:

int success = 0;

if (max(a,b,c) == max(d,e,f))
   success++;
if(middle(a,b,c) == middle(d,e,f))
   success++;
if (min(a,b,c) == min(d,e,f))
   success++;

cout << success << " numbers guessed" <<endl;

So the code now looks this way:

#include <iostream>
using namespace std;

#include <cstdlib>
#include <iomanip>
#include <ctime>

void randnumbers(int&, int&, int&); // Random Numbers Prototype
void guessnumbers(int&, int&, int&); // Guess Numbers Prototype
int max(int a,int b,int c);
int middle(int a,int b,int c);
int min(int a,int b,int c);

int main()
{

// --> Guesses of Numbers and their Orders
int guesses=0;

for (int counter=0; counter<=10; counter++)
{

  while (guesses<=2)
  {


     //Random Numbers
    int a, b, c;
    randnumbers(a,b,c);

    //Guessed Numbers
    int d, e, f;
    guessnumbers(d,e,f);


    int success = 0;

    if (max(a,b,c) == max(d,e,f))
       success++;
    if(middle(a,b,c) == middle(d,e,f))
       success++;
    if (min(a,b,c) == min(d,e,f))
       success++;

    cout << success << " numbers guessed!" << endl;

    int success_in_order = 0;

    if (a == d)
        success_in_order++;
    if (b == e)
        success_in_order++;
    if (c == f)
        success_in_order++;

    cout << sucess_in_order << " numbers in order!" << endl;

    if (success == 3)
       guesses++;
  }
}

if (guesses>=3)
  cout<<"Congratulations, you guessed the numbers in order 3 times! You win..\n";

else if (guesses<3)
  cout<<"You failed to guess the numbers in order over an attempt of 10 times! You lose..\n";

  system("pause");
  return 0;
}

int max(int a, int b,int c)
{
  if (a > b) {
    if (a > c)
       return a;
    else
       return c;
  }
  else if (b > c)
     return b;
  else
     return c;
}

int middle(int a,int b,int c)
{
    // Exercise for the reader
}

int min(int a,int b,int c)
{
   // Exercise for the reader
}

void randnumbers(int& x, int& y, int &z)
{
  srand(time(0));
  x=1+rand()%6;
  cout<<x<<setw(2);

  do {
    y=1+rand()%6;
  }
  while (y==x);
  cout<<y<<setw(2);

  do {
    z=1+rand()%6;
  } while (z==x || z==y);
  cout<<z<<setw(2);
}

void guessnumbers(int& nb1, int& nb2, int& nb3)
{
  cout<<"Guess the 3 numbers from 1-->6: ";
  cin>>nb1>>nb2>>nb3;
}

Looks shorter. Can we improve more? Yes! We have duplicate code, we can set the duplicate code in functions:

#include <iostream>
using namespace std;

#include <cstdlib>
#include <iomanip>
#include <ctime>

void randnumbers(int&, int&, int&); // Random Numbers Prototype
void guessnumbers(int&, int&, int&); // Guess Numbers Prototype
int max(int a,int b,int c);
int middle(int a,int b,int c);
int min(int a,int b,int c);

int guessed(int a,int b,int c,int d,int e,int f);

int main()
{

    int guesses=0;

    for (int counter=0; counter<=10; counter++)
    {

        while (guesses<=2)
        {
            //Random Numbers
            int a, b, c;
            randnumbers(a,b,c);

            //Guessed Numbers
            int d, e, f;
            guessnumbers(d,e,f);

            int success = guessed(max(a,b,c),middle(a,b,c),min(a,b,c),
                                  max(d,e,f),middle(d,e,f),min(d,e,f)
                                 );

            cout << success << " numbers guessed!" << endl;

            int success_in_order = guessed(a,b,c,
                                           d,e,f
                                          );

            cout << sucess_in_order << " numbers in order!" << endl;

            if (success == 3)
                guesses++;
        }
    }

    if (guesses>=3)
        cout<<"Congratulations, you guessed the numbers in order 3 times! You win..\n";

    else if (guesses<3)
        cout<<"You failed to guess the numbers in order over an attempt of 10 times! You lose..\n";

    system("pause");
    return 0;
}


int guessed(int a,int b,int c,int d,int e,int f)
{
    int success = 0;

    if (a == d)
        success++;
    if (b == e)
        success++;
    if (c == f)
        success++;

    return success;
}

int max(int a, int b,int c)
{
    if (a > b)
    {
        if (a > c)
            return a;
        else
            return c;
    }
    else if (b > c)
        return b;
    else
        return c;
}

int middle(int a,int b,int c)
{
    // Exercise for the reader
}

int min(int a,int b,int c)
{
    // Exercise for the reader
}

void randnumbers(int& x, int& y, int &z)
{
    srand(time(0));
    x=1+rand()%6;
    cout<<x<<setw(2);

    do
    {
        y=1+rand()%6;
    }
    while (y==x);
    cout<<y<<setw(2);

    do
    {
        z=1+rand()%6;
    }
    while (z==x || z==y);
    cout<<z<<setw(2);
}

void guessnumbers(int& nb1, int& nb2, int& nb3)
{
    cout<<"Guess the 3 numbers from 1-->6: ";
    cin>>nb1>>nb2>>nb3;
}

This time, i indented the code. Looks nicer, isn't it?

\$\endgroup\$
  • \$\begingroup\$ Wow, yes absolutely! Thank you so much for putting in the time/ effort! \$\endgroup\$ – Jad Nov 3 '16 at 8:07
  • \$\begingroup\$ Suppose a,b,c=1,2,3 and d,e,f=2,3,4. Your max-to-max rule compares 3 to 4 and says 'missed'; min-to-min rule finds 1 different from 2; and mid-to-mid also says 2 is not 3. As a result: "0 numbers guessed", though actually there are two... \$\endgroup\$ – CiaPan Nov 3 '16 at 9:27
  • \$\begingroup\$ @CiaPan good point, i will find another way \$\endgroup\$ – amchacon Nov 3 '16 at 9:45
2
\$\begingroup\$

Here is an example routine to count a number of numbers appearing in two sets, implemented as vectors of ints. Please note the routine takes data by value (i.e. a copy) so that it can modify (sort) them without affecting the caller's data.

int CountSameNumbers(std::vector<int> A, std::vector<int> B)
{
    std::sort(A.begin(), A.begin() + 3);
    std::sort(B.begin(), B.begin() + 3);

    int count = 0;
    for(int i = 0, j = 0; i < 3 && j < 3;)
        if(A[i] < B[j])
            i ++;
        else if(A[i] > B[j])
            j ++;
        else
            count ++, i ++, j ++;

    return count;
}

The routine sorts both vectors first, then starts scanning them with two pointers (actually, integer indices) i and j, wandering along the data. In every iteration one or both indices are incremented, and equal numers are counted.

And this is a simple loop to count 'exact hits' by comparing values at corresponding positions in both vectors. It does not modify data, that's why it can safely take them by a reference.

int CountSamePositions(std::vector<int> &A, std::vector<int> &B)
{
    int count = 0;
    for(int i = 0; i < 3; i++)
        if(A[i] == B[i])
            count ++;

    return count;
}

Once you have two vectors, one with your generated data and another one with data input from a user, you can test the user's answer with these two functions:

    std::vector<int> A, B;

    // fill one vector with your data
    A.push_back(a); A.push_back(b); A.push_back(c);
    // fill the other one with user's data
    B.push_back(d); B.push_back(e); B.push_back(f);

    int samepos = CountSamePositions(A, B);
    int samenum = CountSameNumbers(A, B);

    if(samepos == 3)
        std::cout << "You won!\n";
    else if(samenum > 0)
        std::cout << "You guessed " << samenum << " numbers, "
                  << samepos << " of them at right positions.\n";
    else
        std::cout << "You failed to guess any number. :(\n";

You can see a working example in Ideone.
I just wanted to explain the data processing here, so I didn't implement the 'ten attempts' loop (with an early exit in 'You won' case), but I hope that will not be a big problem.

\$\endgroup\$
  • \$\begingroup\$ Absolutely not, rather really appreciate the example! Thank you!! \$\endgroup\$ – Jad Nov 6 '16 at 5:01
  • \$\begingroup\$ @Jad The CountSameNumbers routine has another feature which I haven't even noticed when writing it: it properly handles repeating values, which is more general than required. That's because it discards just one item from each set on hit, so it will recognize another hit even if the next equal pair is same as the current one. \$\endgroup\$ – CiaPan Nov 6 '16 at 11:02
1
\$\begingroup\$

Another way would be to put the verifying in a function with a switch bock and check each number as it's entered:

void randnumbers(int& x, int& y, int &z)
{
    srand(time(0));
    x = 1 + rand() % 6;    
    do {
        y = 1 + rand() % 6;
    } while (y == x);
    do {
        z = 1 + rand() % 6;
    } while (z == x || z == y);
}
void VerifyGuess(const int guess, const int rank, int& position, int& correct, const int rand1, const int rand2, const int rand3)
{
    switch (rank)
    {
    case 1:
        if (rand1 == guess)
        {
            position++;
        }
        else if (rand2 == guess || rand3 == guess)
        {
            correct++;
        }
        break;
    case 2:
        if (rand2 == guess)
        {
            position++;
        }
        else if (rand1 == guess || rand3 == guess)
        {
            correct++;
        }
        break;
    case 3:
        if (rand3 == guess)
        {
            position++;
        }
        else if (rand2 == guess || rand1 == guess)
        {
            correct++;
        }
        break;
    }

}
int main()
{
    int rand1 = 0, rand2 = 0, rand3 = 0;
    srand(time(NULL));
    randnumbers(rand1, rand2, rand3);
    cout << "Guess 3 randoms numbers(1-6) in order, in 10 tries\n";
    for (int i = 1; i < 11; i++)
    {
        int position = 0, correct = 0, guess1 = 0, guess2 = 0, guess3 = 0;
        cout << "Attempt No. " << i << ":\n";
        cout << "Guess the first number\n";
        cin >> guess1;
        VerifyGuess(guess1, 1, position, correct, rand1, rand2, rand3);
        cout << "Guess the second number\n";
        cin >> guess2;
        VerifyGuess(guess2, 2, position, correct, rand1, rand2, rand3);
        cout << "Guess the third number\n";
        cin >> guess3;
        VerifyGuess(guess3, 3, position, correct, rand1, rand2, rand3);
        if (position == 3)
        {
            cout << "You Won!\n";
            cin.ignore(1);
            cin.get();
            return 0;
        }
        cout << "No. in right position\tNo.in wrong position\n";
        cout << setw(10) << position << setw(24) << correct << '\n';
    }
    cout << "You Lost!\n";
    cin.ignore(1);
    cin.get();
    return 0;
}
\$\endgroup\$
  • \$\begingroup\$ I really appreciate your method, it's very interesting! Thank you! \$\endgroup\$ – Jad Nov 3 '16 at 8:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.