洗牌、发牌算法 (打乱扑克牌顺序)

 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int  d[6];
int  i,n,a,b,t;
int  c,j;
void  main() {
     srand ( time (NULL));
     printf ( "shuffle 0..n-1 demo\n" );
     for  (n=1;n<=5;n++) { /* 测试1~5个元素 */
         printf ( "_____n=%d_____\n" ,n);
         j=1;
         for  (c=1;c<=n;c++) j=j*c; /* j为n! */
         j*=n*2;
         for  (c=1;c<=j;c++) { /* 测试n*2*n!次 */
             for  (i=0;i<n;i++) d[i]=i; /* 填写0~n-1 */
             for  (i=n;i>0;i--) { /* 打乱0~n-1 */
                 a=i-1;b= rand ()%i;
                 if  (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
             }
             printf ( "%04d:" ,c);
             for  (i=0;i<n;i++)  printf ( "%d" ,d[i]);
             printf ( "\n" );
         }
     }
     printf ( "shuffle 1..n demo\n" );
     for  (n=1;n<=5;n++) { /* 测试1~5个元素 */
         printf ( "_____n=%d_____\n" ,n);
         j=1;
         for  (c=1;c<=n;c++) j=j*c; /* j为n! */
         j*=n*2;
         for  (c=1;c<=j;c++) { /* 测试n*2*n!次 */
             for  (i=1;i<=n;i++) d[i]=i; /* 填写1~n */
             for  (i=n;i>1;i--) { /* 打乱1~n */
                 a=i;b= rand ()%i+1;
                 if  (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
             }
             printf ( "%04d:" ,c);
             for  (i=1;i<=n;i++)  printf ( "%d" ,d[i]);
             printf ( "\n" );
         }
     }
}
 
 
 洗牌的算法有很多,这里主要介绍下几种主要的算法。

  方法一:每次找一个随机的位置,然后将这54个数放到找的位置中。

   步骤:1.用一个整型数组记录各个位置是否已经放置了数,如果放置了则不为0,否则为0。所以在算法开始的时候,初始化此数组每个元素的值都为0.

           2.每次产生一个0-53之间的数,看这个位置是否放置了数,如果已经放置了,则继续采用同样的方法找一个随机的位置进行判断,如果这个位置还未放置,则设置此位置。

           3.反复执行步骤2,直到所有的位置都放好了数。

   代码实现如下:

    

 1 void shuffle(int *dest,int N)
 2 {
 3     int pos,card;
 4     for (card=1;card<=N;card++)
 5     {
 6         do 
 7         {
 8             pos=rand()%(N-1);
 9         } while (dest[pos]!=0);
10 
11         dest[pos]=card;
12     }
13 }
14 
15 void main()
16 {
17     int dest[54]={0};
18     shuffle(dest,54);
19     for (int i=0;i<54;i++)
20     {
21         cout<<dest[i]<<" ";
22     }
23 }

    此方法有个缺点就是很耗时间,因为随着空位置越来越少,寻找会越来越困难。

   方法二:就是先对数组进行初始化,然后随机交换数组中任意两个元素。交换的次数越多就越随机。此方法也很简单,而且时间复杂度也比较低,计算量也不大。

      代码实现如下:

                 

 1 void shuffle ( int a[], int n ) 
 2 {
 3     int tmp = 0, p1, p2;
 4     int cnt = rand() % 1023;
 5     while (cnt--)
 6     {
 7         p1 = rand() % n;
 8         p2 = rand() % n;           
 9         tmp = a[p1];
10         a[p1] = a[p2];
11         a[p2] = tmp;
12     }
13 }

   

     方法三:它的基本思想是初始化一个vector,顺序加入所有牌,即1-54个数,然后从这个vector中随机抽取一个到另一个vector中,将这个过程执行54次即可完成。

       代码的实现如下:

                

 1 void vectorShuffle(vector<int> &unshuffle,vector<int> &shuffled)
 2 {
 3     unsigned int temp,len=unshuffle.size();
 4     while(len)
 5     {
 6         temp=rand()%(len--);
 7         shuffled.push_back(unshuffle[temp]);
 8         unshuffle.erase(unshuffle.begin()+temp);
 9     }
10 }
11 
12 
13 void main()
14 {
15     vector<int> uncard,carded;
16     for (int i=0;i<54;i++)
17     {
18         uncard.push_back(i+1);
19     }
20     vectorShuffle(uncard,carded);
21     for (int j=0;j<54;j++)
22     {
23         cout<<carded[j]<<" ";
24     }
25 }

    PS:STL中也有一个封装好了的洗牌算法-random_shuffle。使用方法:如果定义有 vector<int> datas,那么直接调用该函数。例如:random_shuffle(datas.begin(),datas.end()); 还可以定义起始迭代器和末尾迭代器来对序列中的某一部分进行洗牌,并且所耗费的时间也较少。

 

 

[code=html]

 

本程序实现了一般扑克牌游戏的洗牌、发牌和理牌过程,程序模拟了对四个玩家的发牌,且能让各自玩家按大小顺序整理自己的手牌。牌的大小顺序按斗地主的规则(但无大小王)。
   本程序定义了一个牌的结构体,其成员变量是两个字符指针。一个指向点数的字符数组,另一个指向花色的字符数组。考虑到牌的整理需要比较两张牌的大小,而字符不太好比较,从而构造了一个辅助函数Value来实现将字符转换为整数。程序得最后还对桌牌和手牌进行了检测,看是否有重复的牌。

 

算法说明:

发牌算法

Void Deal(CARD *Deck,CARD (*player)[13]){

     for (i = 0;i < 4; i++){

        // 遍历四个玩家

for (j = 0;j < 13; j++){

// 洗牌第i个玩家的第j张牌是手牌中的第4*j+i张(轮流发牌)

   player[i][j] = Deck[4*j+i];

    }

}

}

   排序算法

void  InsertSort ( CARD *R) { // 对某一玩家R作直接插入排序,有13张牌
     for  ( i=1; i<n; ++i ) {
  temp = R[i]; // 复制为监视哨
  for  ( j=i-1; j>=0; --j )

if(Value(R[j].face)<Value(temp.face))break;// 如果R[j]的牌比temp的小则调出循环,找到比temp小的牌          else if (Value(R[j].face) == Value(temp.face)  // 若face 相同 则比较suit

? Value(R[j].suit) < Value(temp.suit) ? 1 : 0 : 0) break;

for  (k = j-1; k > j;k--)
       R[j+1] = R[j]; // 记录后移
        R[k+1] = temp; // 插入到正确位置
  }
  } // InsertSort

         测试算法

测试桌牌和手牌是否有重复的牌。其思想是从第一张开始与后面的牌一次比较,直到找到一张与待比较的牌相同的或者倒数第二张与最后一张牌比较后终止。

算法描述:

       For(I = 0; I < 13; I++ ){

           Temp = R[I]; // 将待检测的牌放入temp中

           If( Locat(Temp,R)){

            Print :ERROR! 

break; // 如果Temp在R[I+1…13]中则返回1 

}

// 若没有重复的牌不提示任何信息
         变量说明:

一.  张牌(Card)都用一个 strcut card 结构体类型来表示具体定义如下 struct card{

char *face;  // 指针 face 指向不同纸牌的点数

    char *suit;  // 指针 suit 指向不同纸牌的花色

} CARD;


再定义两个字符数组分别存储牌的点数和花色:

char *face[] = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K","A", "2"};
char *suit[] = {"/004", "/005", "/003", "/006"};
定义两个CARD型数组 deck[52],player[4][13],deck用与存储桌牌,player用于存储玩家手牌。

[/code]

 

 

  1. // 扑克牌发牌游戏 -- 第一次上机作业   
  2. /* 整个程序由三部分组成 
  3.    1.扑克牌初始化 
  4.    2.洗牌 
  5.    3.发牌 
  6.    4.玩家各自将手牌排序(按黑红紫坊从小到大的排序,2点最大) 
  7.    */  
  8. #include <stdio.h>   
  9. #include <stdlib.h>   
  10. #include <time.h>   
  11. #include <iostream>   
  12. typedef struct card{  
  13.     // 每张牌(Card)都用一个 strcut card 结构体类型来表示  
  14.     char *face;  // 指针 face 指向不同纸牌的点数  
  15.     char *suit;  // 指针 suit 指向不同纸牌的花色  
  16. } CARD;   
  17. CARD deck[52], player[4][13];    
  18.      char *face[] = {"3""4""5""6""8""8""9""10""J""Q""K","A""2"};  
  19.      char *suit[] = {"/004""/005""/003""/006"};  
  20.  // 比较时用的牌值   
  21. void InitDeck (CARD * , char *[] , char *[]);  
  22. void Shuffle (CARD *);  
  23. void Deal (CARD * , CARD (*)[13]);  
  24. void Sort (CARD (*)[13]);  
  25. int  Value (char *);  
  26. void Disply(void );  
  27. int Locat(CARD *, int , CARD , int (*)(CARD, CARD));  
  28. int Equl(CARD, CARD);  
  29. void Testcard(CARD *, CARD (*)[13]);  
  30. int main(){  
  31.     srand(time(NULL));    
  32.     InitDeck (deck, face, suit);  // 填新牌   
  33.     Shuffle (deck);  // 洗牌   
  34.     Deal (deck, player); // 发牌   
  35.     Sort (player);  // 对玩家的手牌进行排序  
  36.     Disply();  
  37.     Testcard(deck, player);  
  38.     return 0;  
  39. }  
  40. void InitDeck (CARD *pDeck, char *pface[], char *psuit[]){  
  41.     /* wDeck 结构体指针,指向待初始化桌牌 deck[52] 
  42.        wface 字符数组指针,指向点数 
  43.        wsuit 字符数组指针,指向花色 
  44.        该函数用于初始化桌牌 deck[52] 
  45.        */  
  46.     int i;  
  47.     for (i = 0; i <= 51; i++){  
  48.         pDeck[i].face = pface[i%13];  // 点数初始化  
  49.         pDeck[i].suit = psuit[i/13];  // 花色初始化  
  50.     }  
  51. }  
  52. void Shuffle (CARD *pDeck){  
  53.     // 用产生的随机数 j 依次与前面的牌交换   
  54.     int i, j;  
  55.     CARD temp;  
  56.     for (i = 0; i <= 51; i++){  
  57.         // 洗牌   
  58.         j = rand()%52;  // 产生0到51之间的随机数   
  59.         temp = pDeck[i];  // 交换纸牌  
  60.         pDeck[i] = pDeck[j];  
  61.         pDeck[j] = temp;  
  62.     }  
  63. }  
  64. void Deal (CARD *pDeck , CARD (*pplayer)[13]) {  
  65.     int i, j;  // i为玩家编号,j为手牌编号   
  66.     for (i = 0;i < 4; i++){  
  67.         // 遍历四个玩家   
  68.         for (j = 0;j < 13; j++){  
  69.         // 洗牌第i个玩家的第j张牌是手牌中的第4*j+i张(轮流发牌)  
  70.         pplayer[i][j] = pDeck[4*j+i];  
  71.         }  
  72.     }  
  73. }  
  74. void Sort (CARD (*pplayer)[13]){  
  75.     // 运用插入排序法分别对四个玩家的手牌排序   
  76.     int i, j, p, q;  // i为玩家编号,j为手牌编号,p, q 为工作指针  
  77.     CARD temp;  
  78.     for (i = 0;i < 4; i++){  
  79.         // 外层循环,对四个玩家遍历   
  80.         for (j = 1;j < 13; j++){  
  81.             // 内层循环,开始排序   
  82.             // 先比较face 再比较suit   
  83.             temp = pplayer[i][j];  // 待插入的牌  
  84.             for (p = j-1; p >= 0; p--){  
  85.                 // 从后往前找出第一个小于temp的牌的序号  
  86.             if (Value(pplayer[i][p].face) < Value(temp.face))  // 找到比temp小的牌  
  87.                    break;  
  88.             else if (Value(pplayer[i][p].face) == Value(temp.face)  // 若face 相同 则比较suit  
  89.                 ? Value(pplayer[i][p].suit) < Value(temp.suit) ? 1 : 0 : 0) break;  
  90.             }  
  91.             for (q = j-1; q > p; q--){  // 插入操作  
  92.                 pplayer[i][q+1] = pplayer[i][q];  
  93.             }  
  94.             pplayer[i][q+1] = temp;  
  95.         }  
  96.     }  
  97. }  
  98. int Value(char *str){  
  99.     // 字符映射函数   
  100.     int i = 0;  
  101.       
  102.     while(i < 4 && *str - *suit[i++]) ;  
  103.     if (i == 4) {  
  104.     i = 0;  
  105.     while(i < 13 && *str - *face[i++]) ;  
  106.     }  
  107.     return i;  
  108. }  
  109. void Disply(){  
  110.     using namespace std;  
  111.     int i, j;  
  112.       
  113.     cout << "player1" << "player2" << "player3" << "player4" << endl;  
  114.     for (j = 0; j < 13; j++){  
  115.         // j为第 j 行   
  116.         for (i = 0; i < 4; i++){  
  117.             // i为第 i 位玩家   
  118.             cout << player[i][j].suit << player[i][j].face << "/t";  
  119.             if (i == 3) cout << endl;  
  120.         }  
  121.     }  
  122. }  
  123. void Testcard(CARD *pdeck, CARD (*pplayer)[13]){  
  124.     using namespace std;  
  125.     int i, j;  
  126.     CARD temp;  
  127.    
  128.     for (i = 0; i < 51; i++){  
  129.         temp = pdeck[i];  
  130.         if (Locat(&deck[i+1],52,temp,Equl)){  
  131.             cout << "error! the deckcard are same"<< endl;  
  132.             break;  
  133.         }  
  134.     }  // 测试桌牌是否重复   
  135.     for (i = 0; i < 4; i++){  
  136.         for (j = 0; j < 13; j++){  
  137.             temp = pplayer[i][j];  
  138.             if(Locat(&pplayer[i][j+1],13,temp,Equl)){  
  139.                 cout << "error! the player's card are same" << endl;  
  140.                 break;  
  141.             }  
  142.         }  // 测试手牌是否重复   
  143.     }  
  144. }  
  145. int Locat(CARD *pdecks, int len, CARD deck, int (*compare)(CARD , CARD )){  
  146.     // 若牌堆中有满足 compare() 的牌则返回1,没有则返回0   
  147.     // len牌堆的长度 有13和52   
  148.     CARD *p;  
  149.     int i = 0;  // 第一张牌  
  150.     p = pdecks;  // 第一张牌的地址   
  151.     while (i < len && compare(*p++ , deck))   
  152.         ++i;  
  153.     if(i == len)  
  154.         return 0;  
  155.     else  
  156.         return 1;  
  157. }  
  158. int Equl(CARD card1, CARD card2){  
  159.     // 比较card1 和 card2 是否相同,相同则返回0  
  160.     // 不同返回1   
  161.     int fval, sval;  
  162.     // fval 为点数字符差,sval 为花色字符差   
  163.     fval = *card1.face - *card2.face;  
  164.     sval = *card1.suit - *card2.suit;  
  165.     if(fval || sval)  
  166.         return 1;  // 有一个不同就不相同  
  167.     else   
  168.         return 0;  
  169. }  

 

 

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 下面是一个示例代码: ``` #include <stdio.h> #include <stdlib.h> #include <time.h> #define CARDS 52 #define FACES 13 #define SUITS 4 void shuffle(unsigned int wDeck[][FACES]); void deal(unsigned int wDeck[][FACES], const char *wFace[], const char *wSuit[]); int main(void) { unsigned int deck[SUITS][FACES] = {0}; const char *face[] = {"Ace", "Deuce", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King"}; const char *suit[] = {"Hearts", "Diamonds", "Clubs", "Spades"}; srand(time(NULL)); shuffle(deck); deal(deck, face, suit); return 0; } void shuffle(unsigned int wDeck[][FACES]) { size_t row; size_t column; size_t card; for (card = 1; card <= CARDS; ++card) { row = rand() % SUITS; column = rand() % FACES; while (wDeck[row][column] != 0) { row = rand() % SUITS; column = rand() % FACES; } wDeck[row][column] = card; } } void deal(unsigned int wDeck[][FACES], const char *wFace[], const char *wSuit[]) { size_t card; size_t row; size_t column; for (card = 1; card <= CARDS; ++card) { for (row = 0; row < SUITS; ++row) { for (column = 0; column < FACES; ++column) { if (wDeck[row][column] == card) { printf("%5s of %-8s%c", wFace[column], wSuit[row], card % 2 == 0 ? '\n' : '\t'); } } } } } ``` 这段代码实现了洗牌发牌的功能。它首先定义了一副扑克牌的数组,然后通过随机数生成来洗牌,最后按顺序发牌。 ### 回答2: 下面是一个使用C语言写的洗牌发牌的简单代码。 ```c #include <stdio.h> #include <stdlib.h> #include <time.h> void shuffle(int *deck, int size); void deal(int *deck, int size); int main() { int deck[52]; // 初始化一副牌 for (int i = 0; i < 52; i++) { deck[i] = i + 1; } // 洗牌 srand(time(NULL)); shuffle(deck, 52); // 发牌 deal(deck, 52); return 0; } // 洗牌函数 void shuffle(int *deck, int size) { for (int i = size - 1; i > 0; i--) { int j = rand() % (i + 1); int temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } } // 发牌函数 void deal(int *deck, int size) { char *suits[] = {"♠", "♥", "♦", "♣"}; char *ranks[] = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}; for (int i = 0; i < size; i++) { int suit = (deck[i] - 1) / 13; int rank = (deck[i] - 1) % 13; printf("%s%s ", ranks[rank], suits[suit]); if ((i + 1) % 13 == 0) { printf("\n"); // 每行输出13张牌 } } } ``` 这段代码首先会初始化一副牌,然后使用`shuffle()`函数对牌进行洗牌操作。`shuffle()`函数采用了Fisher-Yates洗牌算法,通过随机交换数组中的元素来实现洗牌。随后,`deal()`函数会根据洗好的牌进行发牌操作,并输出每个人的手牌。这里将牌的花色和数字分别用字符数组`suits[]`和`ranks[]`表示,然后根据牌的数字进行索引打印。最后,`main()`函数调用了洗牌发牌函数。运行这段代码后,将会输出一副洗好并发到玩家手上的扑克牌。 ### 回答3: 洗牌发牌扑克牌类游戏中常见的操作,我们可以用C语言编写一个简单的洗牌发牌的代码。 首先,我们需要一个数组来表示一副扑克牌,可以使用整数表示不同的牌面和花色,例如1到13表示不同的牌面,1到4表示不同的花色。我们可以定义一个大小为52的一维数组来表示一副扑克牌,其中数组元素的值对应着扑克牌的编号。 接下来,我们需要实现一个洗牌的函数,该函数将随机打乱扑克牌顺序,使得每张牌出现的概率相等。可以使用rand()函数来生成一个随机的整数,然后将这个整数对52取余,得到一个在0到51之间的随机数作为索引,将该索引对应的牌与当前遍历到的牌进行交换,从而完成洗牌操作。 最后,我们可以编写一个发牌函数来模拟发牌的过程。可以用一个循环来依次将牌发给玩家,可以使用一个变量来表示当前发到的位置,每次发牌时将该位置自增1,同时将该位置对应的牌分配给当前玩家。 综上,我们可以编写如下的C代码来实现洗牌发牌的操作: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> void shuffle(int *cards, int size) { srand(time(NULL)); for (int i = 0; i < size; i++) { int j = rand() % size; int temp = cards[i]; cards[i] = cards[j]; cards[j] = temp; } } void deal(int *cards, int size, int players, int cardsPerPlayer) { int position = 0; for (int i = 0; i < players; i++) { printf("Player %d: ", i + 1); for (int j = 0; j < cardsPerPlayer; j++) { printf("%d ", cards[position++]); } printf("\n"); } } int main() { int cards[52]; for (int i = 0; i < 52; i++) { cards[i] = i + 1; } shuffle(cards, 52); deal(cards, 52, 4, 13); return 0; } ``` 以上代码创建一个包含52个牌的数组,先进行洗牌操作,然后将洗好的牌发给4个玩家,每个玩家发到13张牌。输出结果类似于: ``` Player 1: 42 8 19 50 35 3 47 51 40 14 7 28 52 Player 2: 12 38 23 41 2 15 24 26 21 10 13 43 48 Player 3: 45 27 33 18 22 36 30 11 44 20 32 34 29 Player 4: 46 9 5 49 31 4 25 39 1 6 37 17 16 ``` 这样我们就成功地使用C语言编写了一个简单的洗牌发牌的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值