一个好的随机数生成器的想法是什么

What is the idea of a good random numbers generator?

本文关键字:随机数生成器 是什么 一个      更新时间:2023-10-16

我正在为纸牌游戏编写一个程序。可以有多个游戏玩家(例如,从 2 到 7)。一副牌由54张牌组成。我需要随机分发/发牌给玩家。

我们可以将 54 张牌视为包含 54 个元素的字符数组。让我们假设在某个游戏中,每个玩家必须获得 6 张牌。玩家人数为2人。因此,有必要生成两个数组,每个数组由从 6 个元素的"大"数组中选择的 54 个元素组成。此外,在这两个生成的数组中,不应该有共享/重复的元素。

我尝试了一种递归算法来获得从 0 到 (m - 1) 的 m 个唯一随机数序列。

X(n+1) = (a * X(n) + c) mod m

您需要设置参数:

    m
  • -- 模块,m> 0
  • a
  • -- 因子, 0 <= a
  • c
  • -- 增量, 0 <= c
  • X(0) -- 初始值 , 0 <= X(0)
  • 数字 cm 必须是互质数。
  • (a - 1) 对于作为 m 除数的每个素数 p 可被 p 整除
  • 如果 m 能被 4 整除,则 (a - 1) 必须能被 4 整除。

下面是此算法的代码。如您所见,参数 a、c、m 和 X(0) 满足上述条件。

int a = 13,
    c = 11,
    m = 54, // because the total number of cards is 54
    x0 = 1;
int x[100];
x[0] = x0;
cout << x[0] << "  ";
for (int i = 1; i < m; i++)
{
    x[i] = (a * x[i - 1] + c) % m;
    cout << x[i] << "  ";
}
其结果是 :1 24 53 52 39 32 49 0 11 46 15 44 43 30 23 40 45 2 37 6 35 34 21 14 31 36 47 28

51 26 25 12 5 22 27 38 19 42 17 16 3 50 13 18 29 10 33 8 7 48 41 4 9 20.你认为这是随机的吗?

你能对这个算法说些什么?一般来说,每个玩家随机分配卡片的想法应该是什么?

你看,如果我将此算法集成到我的程序中,它将处理与每次启动程序时显示的相同的卡片序列(因为参数不会更改)。所以我需要在程序启动之间更改 a、m、c 和 X(0)。然后我将遇到另一个问题:如何自动(并且也是随机)设置这些参数,以便它们满足必要的条件(请参阅上面的项目符号列表)。

在我看来,你正在制作一个不必要的复杂系统。

一种更简单的方法是创建一个包含所有元素的数组,对其进行随机播放,然后一次删除一个元素。

一种简单有效的洗牌方法是使用费舍尔-耶茨洗牌:

//Initialize an array/vector/etc. with all the possible values
for (int i = NUMBER_OF_ELEMENTS-1; i >= 0; i--)
{
  //Pick a random integer j between 0 and i (inclusive)
  //Swap elements i and j
}

现在,您可以遍历随机数组,每次需要新卡时选择下一个元素。

int pos = 0; //The position of the next card in the deck
for (int i = 0; i < 6; i++)
{
  for (int j = 0; j < NUMBER_OF_PLAYERS; j++)
  {
    player[j].addCard(deck[pos++])
  }
}

理想情况下,您可能希望将其中一些打包到类中,但为了简洁起见,我将其省略了。

你不能保证随机性。它是一个生成序列,信息吸引力低 - 换句话说,它很容易被黑客入侵。你可以简单地使用 stdlib http://www.cplusplus.com/reference/cstdlib/rand/中的标准 rand()。

我建议在 c++11 中使用带有 std 的 mt19937 http://www.cplusplus.com/reference/random/mt19937/或注释中提到的提升一个。

另一种方法可能是随机化拿牌而不是洗牌的动作。

像这样:

// first step
// init and fill container
std::vector<int> v;
for (int i = 0; i < 54; ++i)
    v.push_back(i);
// second step
// take a random card
srand(time(NULL)); // init seed
int i = std::rand() % v.size();
int card = v[i]; // get card
v.erase(vec.begin() + i); // remove card from deck
return card;

对于第二步,您需要 <ctime><cstdlib> .我不确定它是否比其他解决方案更好。只有我的两分钱。