Limit for Random #s

I have a random # being generated but I only want each number to be generated no more than 4 times (so like a deck of cards. There are only 4 of each number)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//c++ version 5.11

#include <iostream>
#include <cstdlib> 
#include <stdlib.h> 
#include <time.h> 
using namespace std;

main ()
{
	srand(time(NULL));
	int random, i;
	
	for (i = 0; i<=20; i++)
	{
		random = rand() % 10 + 1; //generating a random #
		cout<<"\nThe random # is: "<<random;//outputting the random #	
	}	
}
For this you will need a way to track what numbers have been generated. I suggest storing the numbers in a vector. Then you can use Count to search the array for the int that has been generated.

Now this is half arse C++ and half pesudo but it should help point you in the write direction.

1
2
3
4
5
6
7
8
9
10
Vector Numbers;

for (i =0;i<=20;i++){
random =rand()
While (count(numbers.begin, numbers.end, random) > 4){ // we already have this number 4 times
random = rand();
}

cout << "The random number is " << random << endl;
}
Last edited on
for a small number of values (and small is actually rather big on modern machine) you can use the bucket sort approach.

char used[10] = {0};
...
for...
z = rand()%10;
if(used[z] > 4)
compute z again until false
else
used[z] ++ z is usable and not seen 4x yet

you can also just generate a vector from 0-9 or 1-10 (4 copies of each value in your case) or whatever and do a random shuffle on it and take the first N values, they will be unique and random in your given range. This is a better way because you can have gaps (you can make the vector 0-10 and 90-100 and skip the rest and it still works).

Last edited on
Small sets of known values 

For decks of cards and the like, just create an array/vector/whatever of the numbers you want, and randomly shuffle them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>

int main()
{
  std::ranlux48 rng( std::chrono::system_clock::now().time_since_epoch().count() );

  int fours[ 100 ];
  // fours[] ← (1..25)*4
  int value = 0;
  for (int& x : fours)
  {
    x = (value++ % 25) + 1;
  }
  std::shuffle( fours, fours+100, rng );
  
  std::cout << "random values in [1,25]:\n";
  for (int x : fours)
    std::cout << x << " ";
  std::cout << "\n";
}

You don’t need to use all 100/whatever values, of course.


Large sets / unknown values 

If you cannot meet the conditions for a set like above, use a std::unordered_map to track numbers already pulled.

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
#include <chrono>
#include <iostream>
#include <random>
#include <unordered_map>

int next_random_value_in( int low, int high )
{
  static std::ranlux48 rng( std::chrono::system_clock::now().time_since_epoch().count() );
  static std::unordered_map <int, int> values;
  std::uniform_int_distribution uid( low, high );
  
  while (true)
  {
    int v = uid( rng );
    if (values[ v ] < 4)
    {
      values[ v ]++;
      return v;
    }
  }
}

int main()
{
  for (int n = 0; n < 20; n++)
    std::cout << next_random_value_in( 1, 100 ) << "\n";
}

Hope this helps.

*disclaimer: all code typed-in off the top of my head. Typos/dumb errors may have occurred.
Topic archived. No new replies allowed.