洗牌
洗牌
题目:
扑克游戏
部分:洗牌、发牌、手中的牌排序
全部:基于网络的扑克游戏
详解:
扑克游戏洗牌
1 |
|
这段程序可以实现基本的洗牌功能,但也有一些问题和不足之处:
- 问题一:shuffle函数中使用了一个宏定义SHUFFLE_TIMES来表示随机交换的次数,这个值是固定的100,而不是根据牌的数量动态调整。这可能导致洗牌结果不够均匀和随机,因为每张牌被交换的概率不一样。例如,如果SHUFFLE_TIMES等于52,那么每张牌被交换的期望次数是1,但实际上有些牌可能被交换多次,有些牌可能一次都不被交换。如果SHUFFLE_TIMES等于52×51/2=1326,那么每张牌被交换的期望次数是25.5,但实际上也有可能出现极端情况。一般来说,SHUFFLE_TIMES越大,洗牌结果越接近理想情况,但也会增加时间和空间开销。
- 问题二:shuffle函数中使用了rand函数来生成随机数,这个函数是基于线性同余法实现的伪随机数生成器12。这意味着它生成的随机数序列是有规律和周期性的,并不真正随机。而且rand函数生成的随机数范围是0到RAND_MAX(通常是32767),如果要生成0到51之间的随机数,需要对RAND_MAX取余。这样做会导致低位数字出现的概率比高位数字出现的概率高34。例如,在RAND_MAX等于32767时,0到15之间的数字出现的概率是1/2048,而16到51之间的数字出现的概率是1/2056。这会影响洗牌结果的均匀性和随机性。
- 问题三:print_deck函数中使用了一个硬编码的数字13来表示每行输出多少个元素。这个数字与牌的花色和大小有关,并不适合作为一个常量。如果要修改牌的花色或大小,或者增加或减少牌的数量,就需要修改这个数字。这样做不利于程序的扩展性和可维护性。更好的做法是将这个数字作为一个参数传递给print_deck函数,或者定义一个宏或常量来表示它。
综上所述,这段程序生成的牌并不是完全随机的,而是有一定的规律和偏差的。如果要提高洗牌的质量,可以考虑以下几点改进:
改进一:使用一个更好的随机数生成器,例如梅森旋转算法56,它可以生成高质量的伪随机数序列,且周期非常长。C语言中可以使用mt19937函数来实现这个算法 。
改进二:使用一个更好的洗牌算法,例如Fisher-Yates算法 ,它可以保证每张牌在每个位置出现的概率相等,且只需要进行N次交换,其中N是牌的数量。C语言中可以用如下代码实现这个算法:
1
2
3
4
5
6
7
8
9
10void shuffle(int deck[]) {
srand(time(NULL));
for (int i = CARDS - 1; i > 0; i--) {
int j = rand() % (i + 1);
// 生成0到i之间的随机数
int temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}改进三:将一些常量或参数封装成宏或变量,例如SHUFFLE_TIMES,13等,以便于修改和扩展。或者使用枚举类型来表示牌的花色和大小,以提高程序的可读性和可维护性。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 thewindsing!
评论