BigPaws
BigPaws

Reputation: 109

Picking about random character without repetition c++

I need to pick m amount of random characters(letters) without repetition and im completely stuck, i keep getting only 1 random letter. How can i fix my code? Is there even a way to fix this or should i just scrap this idea and look for a solution from some kinf od tutorials?

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <string>

using namespace std;

int main()
{
  cout << "number below 27" << endl;
  int m;
  cin >> m;

  srand(time(NULL));
  bool repeat = false;
  char letters[m];
  char letter;
  for(int i = 0; i < m; i++){
    letter = rand()%26 +97;
    repeat = true;
    for(int j = 0; j < m; j++){
      if(letters[m] == letters[j]){
        repeat = false;
        break;
      }
    }
    if(repeat){
      letters[m] = letter;
    }
  }
  for (int i = 0; i < m; i++){
    cout << letters[m];
  }
}

Upvotes: 0

Views: 1408

Answers (4)

Walter
Walter

Reputation: 45424

There is an obvious error in the logic of your code: when you test for repetition you compare to the beyond the end letter only, instead to all those sampled so far. The correct test would be

  for(int i = 0; i < m; i++) {
    bool repeating;        
    char tryletter;
    do {
      tryletter = rand()%26 +97;
      repeating = false;
      for(auto j=0; j!=i && !repeating; ++j)
        repeating = tryletter == letters[j];
    } while(repeating);
    letters[i] = tryletter;
  }

Though this is not the most efficient way to do what you've been asked to do. A more efficient way would be to start with all 26 letters, pick one at random and remove it from the set, then continue to pick and remove random letters. For example

std::string random_letters_without_repetition(std::size_t m)
{
  std::string letters;
  std::string all = "abcdefghijklmnopqrstuvwxyz";
  assert(m <= all.size());
  std::random_device r;
  std::default_random_engine rng(r());
  while(m--) {
    std::uniform_int_distribution<std::size_t> uni{0,all.size()-1};
    auto index = uni(rng);
    letters += all[index];
    all.erase(index);
  }
  return letters;
}

Upvotes: 0

user1438832
user1438832

Reputation: 493

You can use suffle -

#include <random>
#include <iostream>
#include <algorithm> 
#include <vector>

using namespace std;

int main ()
{
  char charSet[]={'a','b','c'};//You can add all the charecters
  std::random_device rd;
  std::mt19937 g(rd());
  std::shuffle(charSet,charSet+3,g);
  for(auto c : charSet)
  {
    std::cout<<c;
  }
  std::cout<<endl;
  return 0;
}

Upvotes: 3

Hearen
Hearen

Reputation: 7828

I think the direct method is to use set in C++. The following solution is done just now utilising set to ensure the unique. Hope it could be helpful.

#include <iostream>
#include <ctime>
#include <set>
#include <random>

using namespace std;

int main()
{
  cout << "number below 27" << endl;
  int m;
  cin >> m;

  srand(time(NULL));
  set<char> letters_set;
  while(letters_set.size() < m){
      char c = rand()%26+'a';
      letters_set.insert(c);
  }
  for(auto c: letters_set)
      cout<<c<<endl;
}

A more efficient solution which also ensure the equal possibility for each letter.

#include <iostream>
#include <ctime>
#include <set>
#include <random>

using namespace std;

int main()
{
  cout << "number below 27" << endl;
  int m;
  cin >> m;
  srand(time(NULL));
  vector<int> all_letters(26, 'a');
  for(int i = 0; i < 26; ++i) all_letters[i] += i;
  vector<char> letters_set;
  for(int i = 0; i < m; ++i){
      int select = rand()%all_letters.size();
      letters_set.push_back(all_letters[select]);
      all_letters.erase(all_letters.begin()+select);
  }
  for(auto c: letters_set)
      cout<<c<<endl;
}

Upvotes: 0

izlin
izlin

Reputation: 2138

bool repeat = false;
vector<char> letters(m);
char letter;
for(int i = 0; i < m; i++){
    do
    {
        repeat = false;
        letter = rand()%26 +97; // generate new random number
        for(int j = 0; j<=i; j++) // iterate through the already generated numbers
        {
            if (letter == letters[j]){ // if the generated number already exists, do the while again
                repeat = true;
                break;
            }
        }
    } while(repeat);
    letters[i] = letter; // assign the unique number
    cout << letter;
    repeat = false;
}

You repeat the random number generator until you have a unique random number. And to output your values use i because m is constant and out of bounds:

for (int i = 0; i < m; i++){
  cout << letters[i];
}

Upvotes: 0

Related Questions