Function That Checks For Duplicates While Traversing Array & Prompts User To Enter New Input

Hey everyone, so I'm on the last bit of my project assignment and the professor requires us to create a function that traverses the array(s) and checks for duplicates.

Copied from assignment instructions: "The lotto does NOT have duplicate numbers in it. Find a way to not allow duplicate numbers to be picked by the user. You may want to create another function called noDuplicates that checks to see if the user's selection is already in the userTicket array. If the user enters a number already in the array, ask them to enter another number until they enter one that is not a duplicate. This means the userTicket array should contain no duplicate numbers."

Below is my code so far; this is the last step of my project and I am wondering if anyone can help me out. Thank you very much!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
#include <cstdlib>
#include <ctime>
using namespace std;

void getLottoPicks(int numbers[], int); /* FUNCTION PROTOTYPES ARE LISTED HERE */
void genWinNums(int numbers[], int); /* END OF FUNCTION PROTOTYPES */

const int num = 7; //Defines a constant for the number of ints

int main()
{
	char selection;
	string name;
	int matchingNumbers = 0;
	int userTicket[num]; //Declares array to hold each of the user's lotto number selections. (up to 7); refer to constant at top of program
	int winningNums[num]; //Declares array to hold the winning lotto numbers. (up to 7); refer to constant at top of program
						 //Both of these arrays hold enough memory for 7 int values because of named constant num above main

	do
	{
		cout << "LITTLETON CITY LOTTO MODEL:\n"
			<< "---------------------------\n"
			<< "1) Play Lotto\n"
			<< "q) Quit Program\n"
			<< "Please make a selection: ";
		cin >> selection;
		cin.ignore();

		if (selection == '1')
		{
			cout << "Please enter your name: ";
			getline(cin, name);

			getLottoPicks(userTicket, num); //Calls getLottoPicks function
			genWinNums(winningNums, num); //Calls genWinNums function

			for (int i = 0; i < 7; ++i) //This traverses the entire for loop and basically we create a temp int for userTicket[i]
			{						   //which basically translates to if userTicket = winningNumber, then ++ to matchingNumbers
				int temp = userTicket[i];

				for (int i = 0; i < 7; ++i)
				{
					if (temp == winningNums[i]) //If userTicket (which we are holding in int temp is equal to winningNumber then
												//++matchingNumbers
					{
						++matchingNumbers;
					}
				}
			}

			cout << "\n" << name << "'S LOTTO RESULTS\n"
				<< "----------------------\n"
				<< "WINNING TICKET NUMBERS :";

			for (int i = 0; i < num; ++i) //This for loop iterates & displays the winning ticket numbers
			{
				cout << " " << setw(2) << setfill('0') << winningNums[i] << " ";
			}

			cout << "\n" << name << "'S TICKET         :";

			for (int i = 0; i < num; ++i) //This for loop iterates & displays user's chosen numbers
			{
				cout << " " << setw(2) << setfill('0') << userTicket[i] << " ";
			}

			cout << "\n\nRESULTS :\n"
				<< "---------\n"
				<< "Number Matches: " << matchingNumbers
				<< "\nWinnings      : ";

			if (matchingNumbers <= 2)
			{
				cout << "SORRY NOTHING\n\n";
			}

			else if (matchingNumbers == 3)
			{
				cout << "FREE TICKET\n\n";
			}

			else if (matchingNumbers == 4)
			{
				cout << "NOT BAD - $100\n\n";
			}

			else if (matchingNumbers == 5)
			{
				cout << "LUCKY YOU! - $5,000\n\n";
			}

			else if (matchingNumbers == 6)
			{
				cout << "GREAT! - $100,000\n\n";
			}

			else
			{
				cout << "JACKPOT - 1 MILLION\n\n";
			}
		}

		else if (tolower(selection) == 113) //This makes Q equal to q before "processing"; neater formatting
		{
			cout << "You have chosen to quit the program. Thank you for using!\n";
		}

		else if (tolower(selection) != 113 || selection != '1')
		{
			cout << "Invalid selection. Please try again.\n";
		}

	} while (tolower(selection) != 113); //This makes Q equal to q before "processing"; neater formatting
	
	system("PAUSE");
	return 0;
}

void getLottoPicks(int nums[], int size) // Function that prompts user for their lotto number picks; number must be between 1 & 40
{
	cout << "Please enter your 7 lotto number picks between 1 and 40.\n";

	for (int i = 0; i < size; ++i) //This for loop will repeat as long as i < size; 
								  //size in this case is 7 (refer to constant at top of program)
	{
		do
		{
			cout << "selection #" << i + 1 << ": ";
			cin >> nums[i];

			if (nums[i] < 1 || nums[i] > 40) //Input validation to ensure user's selection is between 1 & 40
			{
				cout << "The number must be between 1 and 40. Please try again: ";
			}
		} while (nums[i] < 1 || nums[i] > 40);
	}

}

void genWinNums(int nums[], int size) //Function that randomly generates winning lotto numbers; for loop traverses and does the 
									  //int nums[i] = rand() % 40 + 1 for each of the 7 winning numbers
									  //the 40 + 1 makes it so that the winning numbers are between 1 & 40
{
	srand((unsigned int)time(NULL)); //Selects random numbers based on computer's internal time (which is constantly changing)

	for (int i = 0; i < size; ++i)
	{
		nums[i] = rand() % 40 + 1; //Ensures winning numbers are between 1 & 40
	}
}
Last edited on
Find a way to not allow duplicate numbers to be picked by the user

you could tackle the problem right at the root - fill an array (or preferably std::vector<int>) with the numbers 1-48 - then std::shuffle (http://en.cppreference.com/w/cpp/algorithm/random_shuffle) the container and pick the first 7 numbers - these'd be unique by construction
> Find a way to not allow duplicate numbers to be picked by the user


Without changing the structure of your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void getLottoPicks(int nums[], int size) // Function that prompts user for their lotto number picks; number must be between 1 & 40
{
    const int maxv = 40 ; // maximum lotto number

    // maxv+1 bool flags to indicate if a number has already been picked
    // already_picked[0] is unused.
    bool already_picked[maxv+1] = {false} ; // initialise to all false

    cout << "Please enter your 7 lotto number picks between 1 and " << maxv << '\n';

    for (int i = 0; i < size; ++i) //This for loop will repeat as long as i < size;
    //size in this case is 7 (refer to constant at top of program)
    {
        do
        {
            cout << "selection #" << i + 1 << ": ";
            cin >> nums[i];

            if (nums[i] < 1 || nums[i] > maxv) //Input validation to ensure user's selection is between 1 & 40
            {
                cout << "The number must be between 1 and 40. Please try again: ";
            }

            else if ( already_picked[ nums[i] ] ) // number was already picked earlier
            {
                cout << "This number was already picked earlier. Please try again: ";
                nums[i] = 0 ; // so that the do-while loop won't exit
            }

            else already_picked[ nums[i] ] = true ; // new valid number; mark it as already picked

        } while (nums[i] < 1 || nums[i] > 40);
    }
}


Note: you may also want to ensure that genWinNums() does not generate duplicate numbers.
JLBorges, what are the odds! I was just taking a look at your comments to helping another forum member with the same question!

http://www.cplusplus.com/forum/beginner/102125/

In regard to ensuring that genWinNums() does not generate duplicate numbers; yes, the professor actually wants us to make sure neither the user NOR the computer's random numbers have any duplicates.

EDIT: I didn't expect to receive help this quick (thank you!); I'm going to give what you suggested a shot, but I was also wondering is there a way to do this where I can create a separate function that checks for duplicates? That way I could implement it into genWinNums()?
Last edited on
> a separate function that checks for duplicates?
> That way I could implement it into genWinNums()?

1
2
3
4
5
6
7
8
9
10
// returns true if the number at the position pos_current
// is already present in an earlier position (complexity is linear)
bool already_picked( const int nums[], int pos_current )
{
    if( pos_current == 0 ) return false ;

    int pos_found = 0 ;
    while( nums[pos_found] != nums[pos_current] ) ++pos_found ;
    return pos_found != pos_current ; // true if found earlier
}


And then:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void getLottoPicks(int nums[], int size) // Function that prompts user for their lotto number picks; number must be between 1 & 40
{
    const int maxv = 40 ; // maximum lotto number

    cout << "Please enter your " << size << " lotto number picks between 1 and " << maxv << '\n';

    for (int i = 0; i < size; ++i) //This for loop will repeat as long as i < size;
    //size in this case is 7 (refer to constant at top of program)
    {
        do
        {
            cout << "selection #" << i + 1 << ": ";
            cin >> nums[i];

            if (nums[i] < 1 || nums[i] > maxv) //Input validation to ensure user's selection is between 1 & 40
            {
                cout << "The number must be between 1 and 40. Please try again: ";
            }

            else if ( already_picked( nums, i ) ) // number was already picked earlier
            {
                cout << "This number was already picked earlier. Please try again: ";
                nums[i] = 0 ; // so that the do-while loop won't exit
            }

        } while (nums[i] < 1 || nums[i] > 40);
    }
}

void genWinNums(int nums[], int size) //Function that randomly generates winning lotto numbers; for loop traverses and does the
									  //int nums[i] = rand() % 40 + 1 for each of the 7 winning numbers
									  //the 40 + 1 makes it so that the winning numbers are between 1 & 40
{
        // *** seed the rng once, at the start of the program (do this in main)
	// srand((unsigned int)time(NULL)); //Selects random numbers based on computer's internal time (which is constantly changing)

	for (int i = 0; i < size; ++i)
	{
                // loop till we get a non-dulicated number (not the most efficient way, if size is large)
		do nums[i] = rand() % 40 + 1; while( already_picked( nums, i ) ) ;
	}
}
Last edited on
Thank you very much, JLBorges!!!! Very helpful! Now I'm having an issue where in the event that I try to select a duplicate number, after printing out the error message, it will reprint which selection number I am on (which in the real world in my opinion would make sense, but to match my assignment's output it is "incorrect")

REQUIRED OUTPUT:
selection #1: selection #2: You already picked this number. Please enter a different number: You already picked this number. Please enter a different number: selection #3: and etc, etc

MY OUTPUT:
selection #1: selection #2: You already picked this number. Please enter a different number: selection #2: You already picked this number. Please enter a different number: selection #2:

As you can see, mine will reprint which selection I am on each time, but I'll figure this part out on my own. You've already been tremendously helpful.

UPDATE:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
void getLottoPicks(int nums[], int size) // Function that prompts user for their lotto number picks; number must be between 1 & 40
{
	const int maxNum = 40;

	cout << "Please enter your 7 lotto number picks between 1 and 40.\n";

	for (int i = 0; i < size; ++i) //This for loop will repeat as long as i < size; 
								  //size in this case is 7 (refer to constant at top of program)
	{
		do
		{

			cout << "selection #" << i + 1 << ": ";
			cin >> nums[i];

			if (nums[i] < 1 || nums[i] > maxNum) //Input validation to ensure user's selection is between 1 & 40
			{
				cout << "The number must be between 1 and 40. Please try again: ";
			}

			else if (noDuplicates(nums, i))
			{
				cout << "You already picked this number. Please enter a different number: ";
				cin >> nums[i];
			}

		} while (nums[i] < 1 || nums[i] > maxNum);
	}

}

void genWinNums(int nums[], int size) //Function that randomly generates winning lotto numbers; for loop traverses and does the 
									  //int nums[i] = rand() % 40 + 1 for each of the 7 winning numbers
									  //the 40 + 1 makes it so that the winning numbers are between 1 & 40
{
	for (int i = 0; i < size; ++i)
	{
		do
		{ 
			nums[i] = rand() % 40 + 1;
		} while (noDuplicates(nums, i));
	} 
}

bool noDuplicates(const int nums[], int currentPosition)
{
	int positionFound = 0;

	if (currentPosition == 0)
	{
		return false;
	}

	while (nums[positionFound] != nums[currentPosition])
	{
		++positionFound;
	}

	return positionFound != currentPosition;
}


UPDATE: I got it to stop displaying the current selection # after attempting to enter a duplicate, but now it only verifies the duplicate once before allowing me to enter a duplicate and having the program accept it. Basically, I can bypass my "noDuplicates" function by just attempting to enter a duplicate number again after the warning message and it'll go through for some reason unbeknownst to me.
Last edited on
Comment out / delete Line 24 cin >> nums[i];
Replace with: nums[i] = 0 ;

1
2
3
4
5
6
else if (noDuplicates(nums, i))
{
    cout << "You already picked this number. Please enter a different number: ";
    // cin >> nums[i]; // line 24
    nums[i] = 0 ; // so that the do-while loop won't exit 
}

Hi JLBorges, I actually wrote the code the way you had it with nums[i] = 0; before attempting cin >> nums[i];

What I noticed when I do nums[i] = 0; is that the noDuplicates function is working perfectly and I can't bypass it and somehow force a duplicate entry, but what it's also causing is for the current selection # to redisplay as well.

For example, if I'm on selection #2 and I entered 10 for selection #1 and I attempt to enter 10 for selection #2 with the code you've showed me, what I get is:

selection #1: selection #2: You already picked this number. Please enter a different number: selection #2: You already picked this number. Please enter a different number: selection #2: selection #3:

Whereas what our professor is requiring the output to be is:

selection #1: selection #2: You already picked this number. Please enter a different number:
You already picked this number. Please enter a different number: (whatever I enter would still go for selection #2 here before the program moves to selection #3) selection #3:
What should the output be for "The number must be between 1 and 40. Please try again: "?

Shouldn't there be some internal consistency between the handling of these two input errors?
Hi, not sure what you mean by what should the output be for the input validation to ensure the number is between 1 & 40 sorry.
Should it be
selection #1: 
selection #2: The number must be between 1 and 40. Please try again:
selection #2: The number must be between 1 and 40. Please try again: 
selection #2: The number must be between 1 and 40. Please try again: 
selection #2:


or
selection #1: 
selection #2: The number must be between 1 and 40. Please try again: 
The number must be between 1 and 40. Please try again: 
The number must be between 1 and 40. Please try again: 

Ah ok! :) I see what you mean now! I personally think the first one you did looks better and makes more sense, but the professor is having us do the second version. I can't really blame the professor as all these projects are a student's work she's using as examples for us.

http://i.imgur.com/sKdgZ51.png

I linked a screenshot of what the input validation for number between 1-40 should look like and I see what you mean about consistency. I 100% agree with you and if it were me, I would consider my program complete at this point because I think it makes more sense for the program to display

selection #1:
selection #2: You already picked this number. Please enter a different number:
selection #2: You already picked this number. Please enter a different number:
selection #3:


but the student's output that I am trying to match has it displaying as

selection #1:
selection #2: You already picked this number. Please enter a different number:
You already picked this number. Please enter a different number:
You already picked this number. Please enter a different number:
selection #3:


Worst comes to worst, I'll just leave it as is. I know the professor won't mark me for it, but I was just curious how this other student did it.
Leave it as it is (consistent), perhaps with an added comment indicating that this (identical treatment for both kinds of input validation failures) is for providing a consistent interface to the user.
I'm going to heed your advice and leave it as is :) thank you very much JLBorges!
Topic archived. No new replies allowed.