【问题标题】:Problems with my random number generator我的随机数生成器有问题
【发布时间】:2012-03-05 13:21:32
【问题描述】:

我正在自学基本的 C 语言并尝试创建一个扑克客户端。我有一个带有卡片的数组(称为kortArray)和一个玩家手(称为kortHand)。我的实现不是洗牌,而是依次添加所有 52 张牌,然后从牌组中随机选择 5 张牌。我添加了一个标志(称为draget),它表明一张卡片是否已经被捡起。

现在,当我运行下面的算法时,它通常会生成五个随机数,这使得玩家或计算机的手。但有时它会生成少于五个数字,即使我已经明确指出生成五个可接受的值。

我有两个循环,一个运行五次,另一个嵌套并运行,直到找到一张尚未被选中的卡片。中间的printf 告诉我,这个算法并不总是生成五个可接受的数字,当这种情况发生时,玩家的手牌中会包含无意义的牌。

srand((unsigned)(time(0)));
for(i = 0; i < 5; i++) {                        
    int x = rand()%52 + 1;
    while (kortArray[x].draget!=1) {                
        x = rand()%52 + 1;
        if (kortArray[x].draget != 1) {
            printf("%i\n", x);
            kortArray[x].draget = 1;
            kortHand[i] = kortArray[x];
        }
    }
}

【问题讨论】:

  • 您的代码没有正确缩进。
  • @ManojR:Codereview 与 SO 一样不能用于调试
  • 当问题中的代码是真实代码时,请告诉我们。

标签: c random


【解决方案1】:

问题仍然在于随机数的 +1。

此外,如果卡片已被选中,您首先将第一个分配签入 x,然后将其分配给另一张卡片。

为什么不使用类似的东西:

int nr_cards_picked = 0             /* Number of uniquely picked cards in hand */
/* Continue picking cards until 5 unique cards are picked. */
while (nr_cards_picked < 5) {
    x = rand() % 52;                         /* Take a random card */
    if (kortArray[x].draget == 0) {
        /* Pick this card. */
        kortArray[x].draget = 1;             /* Card is picked */
        kortHand[i]         = kortArray[x];  /* Add picked card to hand */
        nr_cards_picked++;
    }
}

原谅编译器错误;我这里附近没有编译器。

这种情况下你只有一次随机数调用。

理论上它可能永远不会结束,但这不太可能。

【讨论】:

  • 哦,这只是一个错字。我一直在尝试不同的方法,所以应该是 52+1。仍然给我一些问题:)
  • @JimmyGustafsson:“这只是一个错字”我们怎么知道还有什么是“只是一个错字”?制作一个测试用例,这样我们就不会浪费时间了。
  • @JimmyGustafsson:此外,“修复”并没有改变 Michel 所说的内容。我建议再次阅读他的答案
【解决方案2】:

你有:

   int x = rand()%52+1; 
      while (kortArray[x].draget!=1){                 
        x = rand()%52; 

C 中的数组从 0 开始索引。您对 rand() 的第一次调用将生成一个从 1 开始的值。假设您声明 kortArray[] 保存 52 个值,您将有大约 2% 的机会溢出数组。

您对 rand() 的第一次调用会生成 1..52 范围内的值。您的第二次调用生成 0..51。其中一个是错误的。

【讨论】:

  • 哦,这只是一个错字。我一直在尝试不同的方法,所以应该是 52+1。仍然给我一些问题:)
【解决方案3】:

一些注意事项。

首先,如果您对随机数生成器进行 mod 操作,则不能保证它们是随机的。更好的是把它分成 52 段,然后这样选择。

其次,最好将在 while 循环中生成随机数的调用移到末尾,或者在 for 循环的开头不生成随机数。

你的问题是你有时会离开 while 循环而没有真正进入它,因为你在进入循环之前随机生成一个数字。

考虑到这一切,我会做如下代码:

srand((unsigned)(time(0)));
for(i=0;i<5;i++){         
     x=-1;               
     while (kortArray[x].draget!=1){                
          x = floor(rand()*52);
      }
      printf("%i\n", x);
      kortArray[x].draget=1;
      kortHand[i]=kortArray[x];
}

【讨论】:

  • 感谢您指出错误。在您发布之前,我已经提供了一个可行的解决方案,但也给了您 +1 以给我一个可行的解决方案。谢谢
【解决方案4】:

只有当kortArray[x].draget 不为1 时才进入嵌套循环。所以每次为1 时,什么都不做,也不分配卡片。首先确保你有一个唯一的 x,然后在所有情况下更新 kortHand[i]

【讨论】:

    【解决方案5】:

    我建议使用不同的算法:

    1. 创建一个介于 0 和卡组卡数之间的随机数
    2. 将卡片从该位置分配到相应的手牌
    3. 将最后一张牌换到那个位置
    4. 将卡片组中的卡片数量减少 1。
    5. 继续使用 1,直到发完所需数量的牌。

    这样,您就可以摆脱标志,并且可以保证线性性能。无需检查是否已发牌。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-16
      • 2016-05-26
      • 2017-04-10
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多