This question already has an answer here:
-
How to make Random Numbers unique
6 answers
As a part of code for a certain game I want to generate 4 unique random numbers into a vector.
This code works for some number of repeated plays and then application crashes (not responding window).
While I understand that if-condition prevents for-loop from inserting the same number into a vector, how much time does this for-loop takes until it generates unique numbers via rand()
function?
How srand(time(NULL))
and rand()
exactly work together to create random values depending on the system time?
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
//plays bulls and cows
int main() {
srand(time(NULL));
string play="yes";
int nums=4; // number of values in an answer (must NOT exceed 10)
vector<int> answer;
while (play=="yes" || play=="YES" || play=="Y" || play=="Yes" || play=="y") { //plays the game
answer.push_back(rand()%10+1);
do { //fills vector with unique random numbers
for (int i=1; i<nums; i++) {
answer.push_back(rand()%10+1);
if (answer[i]==answer[i-1]) {
i=i-1;
continue;
}
}
} while (answer.size()!=nums);
for (int i=0; i<nums; i++) {
cout<<answer[i];
}
cout<<"Do you want to play again?"<<'\n';
cin>>play;
answer.clear();
} //game ends
if (play=="no" || play=="n" || play=="No" || play=="NO" || play=="N") { //terminates and checks for exceptions
cout<<"Thank you for playing!"<<'\n';
return 0;
} else {
cerr<<"Error: wrong input. Terminating."<<'\n';
return 0;
}
return 0; //safety return
}
The problem is you always push back the random value in your vector before checking if it's valid. Let's say your program generates these random value in order:
2, 6, 6, 7, 9, 10
What happens is you will insert 2 (i == 2), 6 (i == 3), 6 (i == 4), then realize 6 is repeated twice, so you go back one iteration (i == 3), but both your sixes are still in your vector. So now you will add 7 (i == 4) and you will exit the for loop with 5 values in your vector.
Then when you evaluate your do-while condition, your answer.size() won't ever equal 4 because it already is equal to 5. You are now stuck in an infinite loop, and your application crashes when it consumes all the available memory from your vector growing infinitely.
Also, you appear to have an error in your logic. To make sure you don't have a repeated value (and you are stuck with vectors), you should not only validate the last inserted value but the whole vector. Like this:
#include <algorithm>
if ( std::find(vector.begin(), vector.end(), item) != vector.end() )
do_this();
else
do that();
Why do you add the new try into answer
instead of temporary variable. If the variable is valid, then add it into the answer. In your case, i
always keep at 1
;
while (play=="yes" || play=="YES" || play=="Y" || play=="Yes" || play=="y") { //plays the game
int last_try=rand()%10+1;
answer.push_back(last_try);
do { //fills vector with unique random numbers
int new_try=rand()%10+1;
if (last_try!=new_try)
{
answer.push_back(new_try);
last_try=new_try;
}
} while (answer.size()!=nums);
for (int i=0; i<nums; i++)
{
cout<<answer[i]<<"\n";
}
cout<<"Do you want to play again?"<<'\n';
cin>>play;
answer.clear();
} //game ends
Assume that you must use std::vector
(and not a std::set
). The easiest way to fill your vector with random numbers is to check to see if the number has already been "seen" -- if not, then add it to the vector.
This can be accomplished by using an array of bool
as a helper to determine if the number has been seen:
#include <vector>
#include <iostream>
#include <cstdlib>
int main()
{
std::vector<int> answer;
int num = 4;
// 10 numbers
bool seen[10] = {false};
// keeps track of numbers added
int numsAdded = 0;
while (numsAdded < num)
{
int numRand = rand()%10;
if ( !seen[numRand] )
{
// not seen, so add it to vector and update bool array and
// numsAdded
answer.push_back(numRand + 1);
seen[num] = true;
++numsAdded;
}
}
for (size_t i = 0; i < num; ++i)
std::cout << answer[i] << " ";
}
Live Example