zxcbcv 发表于 2020-9-14 10:31:34

S1E31洗牌小程序


0. 实现一个洗牌程序。所谓洗牌程序,就是将所有的扑克牌放入一个数组中,要求把数组内的扑克牌顺序随机打乱,然后输出。

答:洗牌的思路其实很简单,就是从所有元素中随机选取一个元素,然后将它与第一个元素进行交换;然后在第二个之后随机选择一个元素与第二个交换,以此类推……直到最后一个元素。这样就能确保每个元素在每个位置的概率都是 1/n 啦~

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void shuffle(int array[], int length);
void deal(int array[], int player);
void show(char names, int player);

void shuffle(int array[], int length)    //这个函数 谁能讲解一下 我有点看不懂{:5_92:}
{
      int index, temp, i;

      srand(time(NULL));
      for (i = 0; i < length; i++)
      {
                index = rand() % (length - i) + i;
                if (index != i)
                {
                        temp = array;
                        array = array;
                        array = temp;
                }
      }
}

void deal(int array[], int player)
{
      int i, j, k = 0;

      // 模拟发牌:拿起一副无序的扑克每人轮流发一张牌
      for (i = 0; i < 14; i++)
      {
                for (j = 0; j < 3; j++)
                {
                        player = array;
                }
      }
}

void show(char names, int player)
{
      int i, j, poker;

      printf("\n方=方角,梅=梅花,红=红桃,黑=黑桃\n\n");

      for (i = 0; i < 3; i++)
      {
                printf("%s手上的牌是:", names);
                for (j = 0; j < 14; j++)
                {
                     poker = player;

                     if (poker < 11 && 0 < poker)
                     {
                               printf("方%d ", poker);
                     }
                     else if (poker < 21 && 10 < poker)
                     {
                               printf("梅%d ", poker-10);
                     }
                     else if (poker < 31 && 20 < poker)
                     {
                               printf("红%d ", poker-20);
                     }
                     else if (poker < 41 && 30 < poker)
                     {
                               printf("黑%d ", poker-30);
                     }
                     else
                     {
                               switch (poker)
                               {
                                       case 41: printf("方J "); break;
                                       case 42: printf("方Q "); break;
                                       case 43: printf("方K "); break;
                                       case 44: printf("梅J "); break;
                                       case 45: printf("梅Q "); break;
                                       case 46: printf("梅K "); break;
                                       case 47: printf("红J "); break;
                                       case 48: printf("红Q "); break;
                                       case 49: printf("红K "); break;
                                       case 50: printf("黑J "); break;
                                       case 51: printf("黑Q "); break;
                                       case 52: printf("黑K "); break;
                                       case 53: printf("小王 "); break;
                                       case 54: printf("大王 "); break;
                               }
                     }

                }
                printf("\n\n");
      }

}

int main(void)
{
      int array;
      int player;
      int i, ch;
      char names;

      // 初始化扑克牌
      // 1~10代表方(角)1~10, 41、42、43代表方(角)J、Q、K
      // 11~20代表梅(花)1~10, 44、45、46代表梅(花)J、Q、K
      // 21~30代表红(桃)1~10, 47、48、49代表红(桃)J、Q、K
      // 31~40代表黑(桃)1~10, 50、51、52代表黑(桃)J、Q、K
      // 53、54当然就代表小王大王啦~
      for (i = 0; i < 54; i++)
      {
                array = i + 1;
      }

      for (i = 0; i < 3; i++)
      {
                printf("\n请输入%d号玩家的名字:", i+1);
                scanf("%s", names);
      }

      do
      {
                shuffle(array, 54);
                deal(array, player);
                show(names, player);

                printf("重新洗牌(Y/N)?");
                do
                {
                        ch = getchar(); // 过滤输入缓冲区的其他字符
                } while (ch != 'Y' && ch != 'N');
      } while (ch == 'Y');

      return 0;
}

风过无痕1989 发表于 2020-9-14 10:33:24

本帖最后由 风过无痕1989 于 2020-9-14 11:38 编辑

先占个位置

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void shuffle(int array[], int length);
void deal(int array[], int player);
void show(char names, int player);

void shuffle(int array[], int length)    // 调用函数 shuffle 进行洗牌
{
      int index, temp, i;

      srand(time(NULL));               // 使用当前时间进行随机数发生器的初始化
      for (i = 0; i < length; i++)
      {
                index = rand() % (length - i) + i;// 产生一个随机数
                if (index != i)                     // 如果 index 不等于 i,这是为了充分打乱 array 中的原值,即109行所赋的值
                {
                        temp = array;               // 将原值(第 i 张牌)赋给临时变量
                        array = array;       // 将第 index 张牌替换原值
                        array = temp;      // 将第 i 张牌换到第 index 张牌的位置
                }
      }
}

void deal(int array[], int player)
{
      int i, j, k = 0;

      // 模拟发牌:拿起一副无序的扑克每人轮流发一张牌
      for (i = 0; i < 14; i++)
      {
                for (j = 0; j < 3; j++)
                {
                        player = array;
                }
      }
}

void show(char names, int player)
{
      int i, j, poker;

      printf("\n方=方角,梅=梅花,红=红桃,黑=黑桃\n\n");

      for (i = 0; i < 3; i++)
      {
                printf("%s手上的牌是:", names);
                for (j = 0; j < 14; j++)
                {
                     poker = player;

                     if (poker < 11 && 0 < poker)
                     {
                               printf("方%d ", poker);
                     }
                     else if (poker < 21 && 10 < poker)
                     {
                               printf("梅%d ", poker-10);
                     }
                     else if (poker < 31 && 20 < poker)
                     {
                               printf("红%d ", poker-20);
                     }
                     else if (poker < 41 && 30 < poker)
                     {
                               printf("黑%d ", poker-30);
                     }
                     else
                     {
                               switch (poker)
                               {
                                       case 41: printf("方J "); break;
                                       case 42: printf("方Q "); break;
                                       case 43: printf("方K "); break;
                                       case 44: printf("梅J "); break;
                                       case 45: printf("梅Q "); break;
                                       case 46: printf("梅K "); break;
                                       case 47: printf("红J "); break;
                                       case 48: printf("红Q "); break;
                                       case 49: printf("红K "); break;
                                       case 50: printf("黑J "); break;
                                       case 51: printf("黑Q "); break;
                                       case 52: printf("黑K "); break;
                                       case 53: printf("小王 "); break;
                                       case 54: printf("大王 "); break;
                               }
                     }

                }
                printf("\n\n");
      }

}

int main(void)
{
      int array;
      int player;
      int i, ch;
      char names;

      // 初始化扑克牌
      // 1~10代表方(角)1~10, 41、42、43代表方(角)J、Q、K
      // 11~20代表梅(花)1~10, 44、45、46代表梅(花)J、Q、K
      // 21~30代表红(桃)1~10, 47、48、49代表红(桃)J、Q、K
      // 31~40代表黑(桃)1~10, 50、51、52代表黑(桃)J、Q、K
      // 53、54当然就代表小王大王啦~
      for (i = 0; i < 54; i++)
      {
                array = i + 1;
      }

      for (i = 0; i < 3; i++)
      {
                printf("\n请输入%d号玩家的名字:", i+1);
                scanf("%s", names);
      }

      do
      {
                shuffle(array, 54);
                deal(array, player);
                show(names, player);

                printf("重新洗牌(Y/N)?");
                do
                {
                        ch = getchar(); // 过滤输入缓冲区的其他字符
                } while (ch != 'Y' && ch != 'N');
      } while (ch == 'Y');

      return 0;
}

风过无痕1989 发表于 2020-9-14 11:56:22

你要的那段程序已经帮你注释了。

说实话,我还没有想通 index = rand() % (length - i) + i 是怎么保证 index <= 54 的,等想通了再来回复。

也请其他朋友前来帮我想通这个事情

巴巴鲁 发表于 2020-9-14 12:23:23

风过无痕1989 发表于 2020-9-14 11:56
你要的那段程序已经帮你注释了。

说实话,我还没有想通 index = rand() % (length - i) + i 是怎么保证...

这个是取余的公式,表示在之间取随机数
顺便捞2个鱼币{:10_256:}

风过无痕1989 发表于 2020-9-14 17:28:17

巴巴鲁 发表于 2020-9-14 12:23
这个是取余的公式,表示在之间取随机数
顺便捞2个鱼币

中午出去喝酒了,回来一睡就到现在了。

      查了一下百度百科:srand(unsigned)time(NULL))使用系统定时/计数器的值作为随机种子每个种子对应一组根据算法预先生成的随机数,所以在相同平台的环境下,不同时间产生的随机数是不同的,相应的若将srand(unsigned)tima(NULL)改为任一常量,则无论何时运行,运行多少次得到的随机数都是一组特定的序列,所以srand生成的随机数是伪随机数。但是,所谓的“伪随机数”指的并不是假的随机数,其实绝对的对技术只是一种假想状态的随机数,计算机只能生成相对的随机数,而这些随机数既是随机的又是有规律的,一部分遵守一定规律,一部分则不遵守任何规律,总结来说就是:计算机产生伪随机数而不是绝对的随机数。

      由于rand产生的随机数是0到rand_max,而rand_max是一个很大的数,那么要产生一个从X到Y的随机数,可以这样:s=rand()%(x-Y+1)+Y,这表示从X到Y范围内的随机数。

hornwong 发表于 2020-9-14 18:55:16

感谢分享!

风过无痕1989 发表于 2020-9-14 19:18:11

原来的程序是有错误的,比如:35行,试图将一张牌值赋给一个地址 player; 51行 poker = player 也是不对。下面的程序已经可以运行了,就是名字怎么弄,我暂时还没想好,因为你的做法,前面两人的名字都将被第3个人的名字所覆盖

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void shuffle(int array[], int length);
void deal(int array[], int player);
void show(char names, int player);

void shuffle(int array[], int length)    // 调用函数 shuffle 进行洗牌
{
      int index, temp, i;

      srand(time(NULL));               // 使用当前时间进行随机数发生器的初始化
      for (i = 0; i < length; i++)
      {
                index = rand() % (length - i + 1) + i; // 产生一个随机数
                if (index != i)                        // 如果 index 不等于 i,这是为了充分打乱 array 中的原值,即109行所赋的值
                {
                        temp = array;               // 将原值(第 i 张牌)赋给临时变量
                        array = array;       // 将第 index 张牌替换原值
                        array = temp;         // 将第 i 张牌换到第 index 张牌的位置
                }
      }
}

void deal(int array[], int player)
{
      int i, j, k = 0;

      // 模拟发牌:拿起一副无序的扑克每人轮流发一张牌
      for (i = 0; i < 14; i++)
      {
                for (j = 0; j < 3; j++)
                {
                        player = array;
                }
      }
}

void show(char names, int player)
{
      int i, j, poker;

      printf("\n方=方角,梅=梅花,红=红桃,黑=黑桃\n\n");

      for (i = 0; i < 3; i++)
      {
                printf("%s手上的牌是:", names);
                for (j = 0; j < 14; j++)
                {
                     poker = player;

                     if (poker < 11 && 0 < poker)
                     {
                               printf("方%d ", poker);
                     }
                     else if (poker < 21 && 10 < poker)
                     {
                               printf("梅%d ", poker-10);
                     }
                     else if (poker < 31 && 20 < poker)
                     {
                               printf("红%d ", poker-20);
                     }
                     else if (poker < 41 && 30 < poker)
                     {
                               printf("黑%d ", poker-30);
                     }
                     else
                     {
                               switch (poker)
                               {
                                       case 41: printf("方J "); break;
                                       case 42: printf("方Q "); break;
                                       case 43: printf("方K "); break;
                                       case 44: printf("梅J "); break;
                                       case 45: printf("梅Q "); break;
                                       case 46: printf("梅K "); break;
                                       case 47: printf("红J "); break;
                                       case 48: printf("红Q "); break;
                                       case 49: printf("红K "); break;
                                       case 50: printf("黑J "); break;
                                       case 51: printf("黑Q "); break;
                                       case 52: printf("黑K "); break;
                                       case 53: printf("小王 "); break;
                                       case 54: printf("大王 "); break;
                               }
                     }

                }
                printf("\n\n");
      }

}

int main(void)
{
      int array;
      int player;
      int i, ch;
      char names;

      // 初始化扑克牌
      // 1~10代表方(角)1~10, 41、42、43代表方(角)J、Q、K
      // 11~20代表梅(花)1~10, 44、45、46代表梅(花)J、Q、K
      // 21~30代表红(桃)1~10, 47、48、49代表红(桃)J、Q、K
      // 31~40代表黑(桃)1~10, 50、51、52代表黑(桃)J、Q、K
      // 53、54当然就代表小王大王啦~
      for (i = 0; i < 54; i++)
      {
                array = i + 1;
      }

      for (i = 0; i < 3; i++)
      {
                printf("\n请输入%d号玩家的名字:", i+1);
                scanf("%s", names);
      }

      do
      {
                shuffle(array, 54);
                deal(array, player);
                show(names, player);

                printf("重新洗牌(Y/N)?");
                do
                {
                        ch = getchar(); // 过滤输入缓冲区的其他字符
                } while (ch != 'Y' && ch != 'N');
      } while (ch == 'Y');

      return 0;
}

我是渣男 发表于 2020-9-15 00:03:41

哇,前来学习大佬的作品

风过无痕1989 发表于 2020-9-15 01:06:37

本帖最后由 风过无痕1989 于 2020-9-15 01:08 编辑

见你一直没反应,想来还没有满意,我还是帮你将最后这个错误修改了吧。正确的程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void shuffle(int array[], int length);
void deal(int array[], int player);
void show(char names, int player);

void shuffle(int array[], int length)    // 调用函数 shuffle 进行洗牌
{
      int index, temp, i;

      srand(time(NULL));               // 使用当前时间进行随机数发生器的初始化
      for (i = 0; i < length; i++)
      {
                index = rand() % (length - i + 1) + i; // 产生一个随机数
                if (index != i)                        // 如果 index 不等于 i,这是为了充分打乱 array 中的原值,即109行所赋的值
                {
                        temp = array;               // 将原值(第 i 张牌)赋给临时变量
                        array = array;       // 将第 index 张牌替换原值
                        array = temp;         // 将第 i 张牌换到第 index 张牌的位置
                }
      }
}

void deal(int array[], int player)
{
      int i, j, k = 0;

      // 模拟发牌:拿起一副无序的扑克每人轮流发一张牌
      for (i = 0; i < 14; i++)
      {
                for (j = 0; j < 3; j++)
                {
                        player = array;
                }
      }
}

void show(char names, int player)
{
      int i, j, poker;

      printf("\n方=方角,梅=梅花,红=红桃,黑=黑桃\n\n");

      for (i = 0; i < 3; i++)
      {
                printf("%s手上的牌是:", names);    // 改为数组0行第一个元素的地址
                for (j = 0; j < 14; j++)
                {
                     poker = player;

                     if (poker < 11 && 0 < poker)
                     {
                               printf("方%d ", poker);
                     }
                     else if (poker < 21 && 10 < poker)
                     {
                               printf("梅%d ", poker-10);
                     }
                     else if (poker < 31 && 20 < poker)
                     {
                               printf("红%d ", poker-20);
                     }
                     else if (poker < 41 && 30 < poker)
                     {
                               printf("黑%d ", poker-30);
                     }
                     else
                     {
                               switch (poker)
                               {
                                       case 41: printf("方J "); break;
                                       case 42: printf("方Q "); break;
                                       case 43: printf("方K "); break;
                                       case 44: printf("梅J "); break;
                                       case 45: printf("梅Q "); break;
                                       case 46: printf("梅K "); break;
                                       case 47: printf("红J "); break;
                                       case 48: printf("红Q "); break;
                                       case 49: printf("红K "); break;
                                       case 50: printf("黑J "); break;
                                       case 51: printf("黑Q "); break;
                                       case 52: printf("黑K "); break;
                                       case 53: printf("小王 "); break;
                                       case 54: printf("大王 "); break;
                               }
                     }

                }
                printf("\n\n");
      }

}

int main(void)
{
      int array;
      int player;
      int i,ch;
      char names;

      // 初始化扑克牌
      // 1~10代表方(角)1~10, 41、42、43代表方(角)J、Q、K
      // 11~20代表梅(花)1~10, 44、45、46代表梅(花)J、Q、K
      // 21~30代表红(桃)1~10, 47、48、49代表红(桃)J、Q、K
      // 31~40代表黑(桃)1~10, 50、51、52代表黑(桃)J、Q、K
      // 53、54当然就代表小王大王啦~
      for (i = 0; i < 54; i++)
      {
                array = i + 1;
      }

      for (i = 0; i < 3; i++)
      {
                printf("\n请输入%d号玩家的名字:", i+1);
                scanf("%s",names);            // 改为数组0行第一个元素的地址,因为 i 的变化,是为了改变行
      }
      do
      {
                shuffle(array, 54);
                deal(array, player);
                show(names, player);

                printf("重新洗牌(Y/N)?");
                do
                {
                        ch = getchar(); // 过滤输入缓冲区的其他字符
                } while (ch != 'Y' && ch != 'N');
      } while (ch == 'Y');

      return 0;
}

zxcbcv 发表于 2020-9-15 08:08:11

风过无痕1989 发表于 2020-9-15 01:06
见你一直没反应,想来还没有满意,我还是帮你将最后这个错误修改了吧。正确的程序如下:

还有鱼币没有领,我心想帖子挂满一天

心驰神往 发表于 2020-9-15 08:41:09

学习

wzdr 发表于 2020-9-15 09:08:02

{:10_256:}{:10_256:}{:10_256:}学习学习

wzdr 发表于 2020-9-15 09:08:46

{:10_256:}{:10_256:}{:10_256:}

风过无痕1989 发表于 2020-9-15 09:51:57

zxcbcv 发表于 2020-9-15 08:08
还有鱼币没有领,我心想帖子挂满一天

这个程序只是洗牌、发牌,还有等完善,还有自己的牌没有显示出来,对四家的牌进行相关游戏的排序,隐藏另外三家的牌,出牌等

gzq44 发表于 2020-10-9 14:23:21

风过无痕1989 发表于 2020-9-14 10:33
先占个位置

你好大佬,我发现你在第一行哪里又names【3】【40】也有【20】不是很懂,是打错了吗,再问names后面是三是三人的意思然后第二数是什么意思呢?{:10_242:}

风过无痕1989 发表于 2020-10-9 14:51:04

gzq44 发表于 2020-10-9 14:23
你好大佬,我发现你在第一行哪里又names【3】【40】也有【20】不是很懂,是打错了吗,再问names后面是三 ...

我的程序里有行号,你不指明行号,我很难知道你在问什么

gzq44 发表于 2020-10-9 15:28:25

风过无痕1989 发表于 2020-10-9 14:51
我的程序里有行号,你不指明行号,我很难知道你在问什么

不好意思,打错了第七行哪里

风过无痕1989 发表于 2020-10-9 17:04:59

gzq44 发表于 2020-10-9 15:28
不好意思,打错了第七行哪里

void show(char names, int player); 这一语句是定义一个函数,用来专门显示各人牌的。

names这个二维数组是用来玩家名字的,它有3行,每行贮存一位玩家,他们名字用20个字符来显示,外国人的名字较长,需要用比较多的单元元素来贮存。咱中国人的名字是三个汉字,每个汉字占两个字节,加上一个结束符,有7个单元元素就可以了,因此,对于中国人来说,这个数组定义为:names 就可以了。

player这个数组是用来贮存三个玩家手中的牌的,一副扑克牌有54张牌,四个人玩,每个人至少有13张牌(54 / 4 = 13 余 2),余下的2张牌只有两个人得到,换句话说,一副牌有两个人是13张牌,有两个人是14张牌。所以,这个数组被定义为:player

gzq44 发表于 2020-10-9 20:10:25

风过无痕1989 发表于 2020-10-9 17:04
void show(char names, int player); 这一语句是定义一个函数,用来专门显示各人牌的。

...

谢谢{:10_276:}
页: [1]
查看完整版本: S1E31洗牌小程序