C程序-为什么我的洗牌功能不能正常工作



我正在创建一个洗牌函数,它遍历一个传递的数组,调用另一个函数swap来更改传递中的每个元素,并将该元素存储到另一个名为shuffledDeck的数组中。然后我从功能中返回打乱的牌组。我在调用函数时收到了一些洗牌,但大多数都在同一个地方。我不知道为什么甲板的其他部分没有像其他部分一样移动。有人能指出我的函数中有什么错误来解释输出吗?

初始化的甲板与我从函数中得到的输出。

Unshuffled 
[AH] [2H] [3H] [4H] [5H] [6H] [7H] [8H] [9H] [10H] [JH] [QH] [KH] 
[AD] [2D] [3D] [4D] [5D] [6D] [7D] [8D] [9D] [10D] [JD] [QD] [KD] 
[AC] [2C] [3C] [4C] [5C] [6C] [7C] [8C] [9C] [10C] [JC] [QC] [KC] 
[AS] [2S] [3S] [4S] [5S] [6S] [7S] [8S] [9S] [10S] [JS] [QS] [KS] 
Shuffled 
[AD] [AH] [2H] [3H] [4H] [5H] [6H] [7H] [8H] [9H] [10H] [JH] [QH] 
[KH] [KH] [2D] [3D] [4D] [5D] [6D] [7D] [8D] [9D] [10D] [JD] [QD] 
[KD] [AC] [2C] [3C] [4C] [5C] [6C] [7C] [8C] [9C] [10C] [JC] [QC] 
[KC] [AS] [2S] [3S] [4S] [5S] [6S] [7S] [8S] [9S] [10S] [JS] [QS]

我的功能

void swap(char *(*deck)[13], int r, int c)
{
time_t t;
srand((unsigned) time(&t));
int rowToSwap = -1;  //will hold generated row and column to swap
int colToSwap = -1;

while(rowToSwap < 0 || rowToSwap > 3 && colToSwap < 0 || colToSwap > 12){ //while row to swap and col to swap are outside appropriate ranges
rowToSwap = rand() % (3 + 1 - 0);
colToSwap = rand() % (12 + 1 - 0);
}
char *temp = deck[rowToSwap][colToSwap];    //swap by elements using a temp holder
deck[rowToSwap][colToSwap] = deck[r][c];
deck[r][c] = temp;
}

char *(*shuffleDeck(char *(*deck)[13]))[13]
{
char *(*shuffledDeck)[13] = malloc(4 * sizeof(*shuffledDeck));
for(int i = 0; i < 4; i++){
for(int j = 0; j < 13; j++){
swap(deck, i, j);
shuffledDeck[i][j] = deck[i][j];
}

}
return shuffledDeck;
}

@chux建议使用Fisher Yates洗牌。";由内而外";费舍尔-耶茨的变体允许新牌组在从旧牌组复制时进行洗牌。Fisher Yates在一维阵列上工作,但可以使用一点数学来修改它以用于二维阵列:

char *(*shuffleDeck(char *(*deck)[13]))[13]
{
char *(*shuffledDeck)[13] = malloc(4 * sizeof(*shuffledDeck));
/* Use "inside out" Fisher-Yates shuffle, modified for 2-D array. */
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 13; j++) {
int b = randInt(i * 13 + j + 1);
int a = b / 13;
b -= 13 * a;
/*
* Note: a*13+b <= i*13+j,
* so &shuffledDeck[a][b] <= &shuffledDeck[i][j]
*/
if (a != i || b != j) {
shuffledDeck[i][j] = shuffledDeck[a][b];
}
shuffledDeck[a][b] = deck[i][j];
}
}
return shuffledDeck;
}

上面使用的b = randInt(i * 13 + j + 1)函数调用返回一个小于其参数值的随机整数。自变量i * 13 + j + 1比迄今为止洗牌的牌数多出一张。a = b / 13;b -= a * 13;语句将该随机数转换为行a、列b。至关重要的是,a * 13 + b <= i * 13 + j,因此随机位置(a,b(小于或等于位置(i,j(。

如果随机位置(a,b(小于当前位置(i,j(,则混洗牌组中的牌从位置(a、b(复制到位置(i、j(。然后,打乱的牌组中的随机位置(a,b(要么从未被设置(如果随机位置与当前位置相同(,要么包含过时的副本。在任何一种情况下,来自未混洗牌组的当前位置(i,j(的牌被复制到混洗牌中的随机位置(a,b(。

最后,所有未洗牌牌组的牌都被复制到洗牌牌组中随机但唯一的位置。

以下是上面使用的randInt函数的实现:

#include <stdlib.h>
/* Return random integer from 0 to n-1 (for n in range 1 to RAND_MAX+1u) */
int randInt(unsigned int n) {
unsigned int x = (RAND_MAX + 1u) / n;
unsigned int limit = x * n;
int s;
do {
s = rand();
} while (s >= limit);
return s / x;
}

请注意,一个简单的rand() % n通常会导致一个稍微有偏差的结果。上面的randInt(n)函数使用rand(),但产生无偏结果。

随机数生成器需要通过srand函数来播种。在程序中只能执行一次,例如从main函数:

#include <stdlib.h>
#include <time.h>
int main(void)
{
srand(time(NULL));
/* other stuff */
}

首先,您可以删除while循环,只需为行和列调用一次rand%值。其次,应该用常量替换那些整数。为什么要放3+1-0而不是NUM_ROWS?第三,您应该只调用srand一次,否则您将重置随机数生成器的种子。

最后,代码中的逻辑错误。我认为你错过了上一个标签的函数定义,但问题似乎是在swap中,你交换牌,在shuffle_deck函数中,你还将shuffled_deck设置为shuffled值。将牌组中的牌交换到位(即交换(,或者制作一份副本并洗牌。

相关内容

  • 没有找到相关文章

最新更新