最近练习C语言时发现了一个挺有趣的小练习,遂发上来与诸位分享。
题目: 编写一个C程序,模拟斗地主时扑克牌的随机分发。
思路: 定义一个整型数组来存储这54张扑克牌,并对每张牌进行初始化。
将每张扑克牌赋予 0~53 这个范围内的一个随机数,并将其打乱。
通过计算取出每张牌的花色和数值,按每行17张牌进行输出。
接下来上代码:
// Name= "C语言斗地主发牌器"
// Author: R6bandito
// Time: 24/7/26
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void Init(short *p); //声明初始化函数
void Mix(short *p); //声明混合扑克牌函数
void Show(); //声明显示函数
int main(int argc,const char* argv[])
{
short cards[54]; //定义数组cards来存储54张扑克牌
short *p = cards; //定义一个指针指向数组cards
srand(time(NULL)); //初始化随机数生成器
//函数调用
Init(p);
Mix(p);
Show(p);
return 0;
}
对于上述代码,数组cards可以将其定义为全局变量,供所有功能函数调用。但是此处不使用全局变量,将其在main函数中定义,通过指针在其余功能函数中进行访问。
void Init(short *p){ //定义扑克牌初始化函数,初始化54张空扑克牌
for(short i=0;i<54;i++){
*p = i;
p++;
}
}
void Mix(short *p){ //定义混合扑克牌函数
for(short i=0;i+1<53;i++){
//以下代码对两张相邻扑克牌取随机数,且两两交换
*(p+i) = rand()%54;
*(p+i+1) = rand()%54;
short temp = *(p+i);
*(p+i) = *(p+i+1);
*(p+i+1) = temp;
}
}
此代码中,其实对扑克牌的初始化(即Init()函数)是非必要的,不影响代码的正常运行。
原因在于Mix函数功能是相邻扑克牌两两取随机数后进行互换,当循环结束后每张牌都被赋予了对应的值,也就相当于初始化了。但是每个人有不同的混牌方式,如果你所采用的方式有遍及不到54张扑克牌的可能,则应当提前对54张牌进行初始化。这里我写上作为一个参考。
void Show(short *p){ //定义显示函数
unsigned char style[4][8] = {"♠️","♥️","♣️","♦️"}; //扑克牌花色
unsigned char Number[13][8] = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"}; //扑克牌数值
unsigned short count = 0; //定义计数器变量
for(short i=0;i<54;i++){
if(p[i] == 52){ //大小王单独拿出
printf("小王\t");
}
if(p[i] == 53){
printf("大王\t");
}
else{
printf("%s%s\t",style[p[i]/13],Number[p[i]%13]); //打印扑克牌
}
count++;
if(count == 17){ //每17张换行
count = 0;
printf("\n");
}
}
}
将大小王拿出单独讨论,其余空白扑克牌则分别对扑克牌的所有数值取整取余,分别得出花色和数值,打印即可。
到这里,细心的朋友可能已经发现了。这个程序仍然存在一个bug,即该程序只是简单模拟扑克牌的洗牌发牌,并不能做到完全模拟。由于随机数产生的局限性,因此生成的数据有时并不与现实逻辑相吻合,例如 有时54张扑克牌只有一张大王/小王 ,亦或出现两张大小及花色相同的扑克牌。
由于本人水平有限,目前仍然在寻找最佳解决办法。同时,也望有想法的朋友能不吝赐教,在评论区积极指出。