没有数字重复的四位数随机数

时间:2016-02-18 10:53:09

标签: c++ random

有没有办法可以不重复地使用4位数字 - 例如不是1130而是1234?我读过std::random_shuffle可以做到这一点,但它只会交换两者之间的数字。

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

unsigned seed = static_cast<size_t>(std::chrono::system_clock::now().time_since_epoch().count());

using namespace std;

class Player {
private:
    string playername;

public:
    void setName(string b) {
        cout << "Please enter your name:" << endl;
        getline(cin, b);
        playername = b; 
    }

    string getName () {
        return playername;
    }
};

class PasswordGuessingGame {
private:
    std::mt19937 random_engine;
    std::uniform_int_distribution<size_t> random_generator;

public:
    PasswordGuessingGame():
        random_engine(seed),
        random_generator(1000,9999)
    { 
    }

    int getNumber () {
        return random_generator(random_engine);
    }
};

int main () {
    Player newgame;
    PasswordGuessingGame b;
    newgame.setName("");

    cout << newgame.getName() << " " <<  "password " << b.getNumber() <<  endl;
    }

5 个答案:

答案 0 :(得分:2)

一种可能性是生成包含数字的字符串,并使用C ++ 14函数std::experimental::sample()

#include <iostream>
#include <random>
#include <string>
#include <iterator>
#include <experimental/algorithm>

int main() {
std::string in = "0123456789", out;
do {
    out="";
    std::experimental::sample(in.begin(), in.end(), std::back_inserter(out), 4, std::mt19937{std::random_device{}()});
    std::shuffle(out.begin(), out.end(), std::mt19937{std::random_device{}()});
  } while (out[0]=='0');
  std::cout << "random four-digit number with unique digits:"  << out << '\n';
}

修改

更改是为了防止以0开头的结果向@Bathsheba提示,表明这可能是个问题。

答案 1 :(得分:1)

我认为你需要分别生成每个数字。例如,您有0到9之间的数组,其中包含0..9位数。对于第一个数字,您将生成从0到9的数字,并从该数组中获取数字。然后将此数组元素t与数组的最后一个元素交换。对于第二个数字,您将生成0到8之间的数字。依此类推。

答案 2 :(得分:1)

我认为std::random_shuffle没有问题:

#include <iostream>
#include <string>
#include <algorithm>
#include <random>
#include <chrono>

int main()
{
    std::string s;    
    std::generate_n(std::back_inserter(s), 10,
        []() { static char c = '0'; return c++; });
    // s is now "0123456789"

    std::mt19937 gen(std::random_device{}());

    // if 0 can't be the first digit
    std::uniform_int_distribution<size_t> dist(1, 9);
    std::swap(s[0], s[dist(gen)]);

    // shuffle the remaining range
    std::shuffle(s.begin() + 1, s.end(), gen); // non-deprecated version

    // convert only first four
    auto x = std::stoul(s.substr(0, 4));
    std::cout << x << std::endl;
}

Live on Coliru

答案 3 :(得分:0)

如果可以计算存在多少有效(即可接受的)序列,并且您可以设计一个从该计数器映射到每个有效序列实例的双射函数,那么事情变得微不足道。

如果我正确理解你的例子,你想要生成一个随机的4位数序列ABCD(表示[0,9999]范围内的整数),其中数字 A B C D 彼此不同。

有5040个这样的有效序列:10 * 9 * 8 * 7.

给定[0,5039]范围内的任何整数,以下函数将返回一个有效序列(即每个数字唯一的一个),表示为整数:

int counter2sequence(int u) {
  int m = u/504;
  u %= 504;
  int h = u/56;
  u %= 56;
  int t = u/7;
  u %= 7;

  const int ih = h;
  const int it = t;

  if (ih >= m) ++h;
  if (it >= ih) ++t;
  if (t >= m) ++t;
  if (u >= it) ++u;
  if (u >= ih) ++u;
  if (u >= m) ++u;

  return ((m*10 + h)*10 + t)*10 + u;
}

E.g。

counter2sequence(0) => 0123
counter2sequence(5039) => 9876

答案 4 :(得分:0)

另一种方法,仅使用标准数据和数值算法。

#include <random>
#include <array>
#include <iostream>
#include <numeric>

template<class Engine>
int unrepeated_digits(int ndigits, Engine &eng) {
    std::array<int, 10> digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto add_digit = [](auto x, auto digit) {
        return x * 10 + digit;
    };
    std::shuffle(std::begin(digits), std::end(digits), eng);
    return std::accumulate(std::begin(digits), std::next(std::begin(digits), ndigits), 0, add_digit);
}

int main() {
    std::random_device rnd;
    std::default_random_engine eng(rnd());

    for (int i = 0; i < 10; ++i)
        std::cout << unrepeated_digits(4, eng) << std::endl;
}

示例输出:

7623
3860
9563
9150
3219
8652
4789
2457
1826
9745