扑克牌游戏程序设计与测试
你好!此博客用于uestc学生计算机编程实验二:扑克牌游戏程序设计与测试参考!
实验目的
1.熟悉程序开发环境,熟悉程序的编辑、编译、连接和运行的过程。
2.掌握计算机综合程序设计过程,学习分析问题并将其用程序的方式进行转化。
3.学会综合运用编程语言中的各种知识完成程序设计。
4.掌握较复杂程序的编译调试。
5.掌握循环、函数调用、数组、指针等知识。
6.学习通过算法优化来降低程序运算量。
实验流程
1、编写函数newcard,利用随机数产生函数任意发出5张牌(不包括大王和小王),必须满足在一副牌里的花色和点数,也就是说花色只能是:“红heart、黑spade、梅club、方diamond”四种,点数只能为:1~13;需要设计全局数据结构存放这5张牌,要求尽可能简洁。
2、编写函数analyze,分析5张牌的情况,包括7种情况:同花顺flush(5张点数连续、花色相同的牌)、顺子straight(5张点数连续、花色不同的牌)、四炸four(有4张点数相同、花色不同的牌)、三拖二full_house(5张牌中有3张点数相同和1个对子)、三炸three(3张点数相同、花色不同的牌)、两对two_paires(有2个对子)、一对pair(有1个对子);分析结果以英文字符串存放,以字符指针返回。
3、编写测试函数:
a)调用newcard()发牌,调用analyze()分析,然后输出分析结果;
b)设计简单的交互,使程序运行时可以按输入多次运行或结束运行;
c)测试主函数能够测试到各种情况,包括小概率的同花顺等情况;
d)可设置多名玩家,给出每个玩家的分析结果;(选作)
e)可比较玩家牌的结果,按概率给出胜利情况(选作)
实验代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#pragma warning(disable:4996)
struct POKER {
int num; //
A:1 , J:11 , Q:12 , K:13
int color;
//红3,方4,梅5,黑6
}s[52];//定义一个结构体存储52张扑克牌的点数和花色
void sort(int* a, int len);//声明排序函数sort(),功能:冒泡法,从小到大排序
void newcard();//声明发牌函数newcard(),功能:先对52张扑克牌进行洗牌操作,然后选取前五张扑克牌作为玩家的牌,因为已经进行了洗牌,所以,选取任意5张都是可以的
void analyze();//声明分析函数analyze(),功能:判断玩家手中的牌属于哪种组合方式(flush, straight,
four, full_house, three, two_pairs, pair, normal)
//定义全局变量
int i, num, color;
int flush = 0, straight = 0, four = 0, full_house = 0,
three = 0, two_pairs = 0, pair = 0, normal = 0;
int Num[5];
int Color[5];
char* result;
int add = 0;
int main()
{
int k = 1;
int K = 1;
int
player_num;//该变量存储玩家数量
char
choice;//该变量存储玩家是否继续游戏的选择
memset(s, 0,
sizeof(struct POKER) * 52);//分配内存并初始化
srand((unsigned)time(NULL));//调用srand(time(NULL))是把当前的时间作为种子,是程序每次运行产生不同的随机数序列
int times =
20000;//设置游戏总次数,可以用来测试主函数能够测试到各种情况
for (int k =
1; k <= times; k++)
{
printf("\nROUNDR%6d : ", k);//打印第k次游戏
printf("\n");
printf("\n");
printf("Set the number of players:\n");
printf("\n");
scanf("%d", &player_num);//选择玩家数量,最多10人,最少1人
int I =
i + add;
newcard();//进行洗牌操作,将52张牌随机打乱存储到s[52]中
for (add
= 0; add < 5*player_num; add = add + 5)//由于s[52]是进行了洗牌操作了,所以将前五张发给玩家一,次五张发给玩家二,......
{
printf("\n");
printf("\nPLAYER%6d : ", add/5+1);
for
(i = 0; i < 5; i++)//打印第k次游戏的扑克牌组合(包括花色和点数)
{
switch (s[i+add].num)
{
case 1: printf("%4c",
'A'); break;
case 11: printf("%4c", 'J'); break;
case 12: printf("%4c", 'Q'); break;
case 13: printf("%4c", 'K'); break;
default: printf("%4d", s[i + add].num);
}
switch (s[i + add].color)
{
case 3: printf("%2c", 3); break;
case 4: printf("%2c", 4); break;
case
5: printf("%2c", 5); break;
case 6: printf("%2c", 6); break;
default: printf(" ");
}
printf(" ");
}
printf("\n");
for
(i = 0; i < 5; i++)
{
Num[i] = s[i + add].num;//把玩家的五张牌点数赋给数组Num[]
Color[i] = s[i + add].color;//把玩家的五张牌花色赋给数组Color[]
}
printf("\n");
sort(Num, 5);//对点数和花色排序,点数排序用于分析顺子、对子
sort(Color, 5);//对点数和花色排序,花色排序用于分析同花
analyze();//分析玩家手中的牌属于哪种组合方式
printf("%10s", result);//打印玩家手牌的组合方式
printf("\n");
}
printf("\n");
printf("\n");
printf("Would you like to play again?\n");
printf("\n");
printf("A.YES\n");
printf("B.NO\n");
printf("\n");
scanf("%d", &choice);//读取玩家的选择
choice =
getchar(choice);//直接调用scanf输入时,\n也一并读入,会导致循环多运行一次,因此调用getchar去掉\n
if
(choice == 'A')//若玩家选择再玩一次,则continue
K++;
if
(choice == 'B')//若玩家选择结束,则直接break跳出for循环
break;
}
printf("\n");
//输出k次游戏后,各种组合方式出现的次数,由于flush出现次数太少,因此打印的是次数而不是概率
printf("\n");
printf(" flush :%5d\n", flush);
printf(" straight :%5d\n", straight);
printf(" four :%5d\n", four);
printf("full_house:%5d\n", full_house);
printf(" three :%5d\n", three);
printf("two_pairs :%5d\n", two_pairs);
printf(" pair :%5d\n", pair);
printf(" normal :%5d\n", normal);
return 0;
}
//冒泡法从小到达排序
void sort(int* a, int len)
{
int i = 0;
int j;
int t;
for (i = 0;
i < len; i++)
{
for (j = 0; j < len - i - 1; j++)
{
if
(a[j] > a[j + 1])
{
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
}
void newcard()
{
int count =
0;
//洗牌
for (i = 0;
i < 52; i++)
{
s[i].num
= 0;//初始化结构体s,使得每次发牌之前都洗牌一次,如果不初始化,会导致后序生成的新牌无法覆盖旧牌,洗牌失败
}
while (count
< 52)
{
num =
rand() % 13 + 1;//随机产生1~13:代表A~K
color =
rand() % 4 + 3;//随机产生3~6,其ASCⅡ码对应红3,方4,梅5,黑6
int
flag_skip = 0, flag_end = 0;
for (i =
0; i < 52; i++)
{
if
(s[i].num == num && s[i].color == color)//判断生成的牌是否已经在牌堆s[52]里出现过,若在,则跳出for循环,若不在,则将该牌任意放在牌堆的一个无牌的位置
{
flag_skip = 1;
break;
}
}
if
(flag_skip == 1)//生成的牌已经在牌堆s[52]里,跳出for循环,但继续进行while循环
{
continue;
}
while
(1)
{
i =
rand() % 52;//重新随机生成牌堆s[52]的一个位置,判断该位置是否有牌,若无牌,则将生成的牌放入该位置
if
(s[i].num == 0)
{
s[i].num = num;
s[i].color = color;
count++;
break;
}
else
{
continue;
}
}
}
}
void analyze()
{
if (((Num[0]
< Num[1]) && (Num[1] < Num[2]) && (Num[2] < Num[3])
&& (Num[3] < Num[4]) && ((Num[4] - Num[0]) == 4)) &&
(Color[0] == Color[4]))//判断是否是是flushu
{
result =
"flush";//将玩家牌的分析结果以字符串的形式存入result中
flush++;//统计flush出现次数
}
else
if
((Num[0] < Num[1]) && (Num[1] < Num[2]) && (Num[2] <
Num[3]) && (Num[3] < Num[4]) && ((Num[4] - Num[0]) == 4)
&& (Color[0] != Color[4]))//判断是否是是straight
{
result = "straight";
straight++;
}
else
if
(((Num[0] == Num[3]) && (Num[3] < Num[4])) || ((Num[1] == Num[4])
&& (Num[0] < Num[1])))//判断是否是是four
{
result = "four";
four++;
}
else
if (((Num[0] == Num[2]) && (Num[2] < Num[3]) &&
(Num[3] == Num[4])) || ((Num[2] == Num[4]) && (Num[1] < Num[2])
&& (Num[0] == Num[1])))//判断是否是是full_house
{
result = "full_house";
full_house++;
}
else
if (((Num[0] == Num[2]) && (Num[2] < Num[3]) &&
(Num[3] < Num[4])) || ((Num[2] == Num[4]) && (Num[1] < Num[2])
&& (Num[0] < Num[1])) || ((Num[1] == Num[3]) && (Num[0] <
Num[1]) && (Num[3] < Num[4])))//判断是否是是three
{
result = "three";
three++;
}
else
if (((Num[0] == Num[1]) && (Num[1] < Num[2]) &&
(Num[2] == Num[3]) && (Num[3] < Num[4])) || ((Num[0] == Num[1])
&& (Num[1] < Num[2]) && (Num[2] < Num[3]) &&
(Num[3] == Num[4])) || ((Num[0] < Num[1]) && (Num[1] == Num[2])
&& (Num[2] < Num[3]) && (Num[3] == Num[4])))//判断是否是是two_pairs
{
result =
"two_pairs";
two_pairs++;
}
else
if (((Num[0] ==
Num[1]) && (Num[1] < Num[2]) && (Num[2] < Num[3])
&& (Num[3] < Num[4])) || ((Num[0] < Num[1]) && (Num[1] ==
Num[2]) && (Num[2] < Num[3]) && (Num[3] < Num[4])) ||
((Num[0] < Num[1]) && (Num[1] < Num[2]) && (Num[2] ==
Num[3]) && (Num[3] < Num[4])) || ((Num[0] < Num[1]) && (Num[1]
< Num[2]) && (Num[2] < Num[3]) && (Num[3] == Num[4])))//判断是否是是pair
{
result =
"pair";
pair++;
}
else//若以上组合方式都不是,则为normal
{
result =
"normal";
normal++;
}
return
result;//返回字符串指针
}
/***************
修改main函数,用于统计各种组合方式的概率:(统计200000次发牌)
int main()
{
int k = 1;
int K = 1;
int
player_num;//该变量存储玩家数量
char
choice;//该变量存储玩家是否继续游戏的选择
memset(s, 0,
sizeof(struct POKER) * 52);//分配内存并初始化
srand((unsigned)time(NULL));//调用srand(time(NULL))是把当前的时间作为种子,是程序每次运行产生不同的随机数序列
int times =
2000;//设置游戏总次数,可以用来测试主函数能够测试到各种情况
for (int k =
1; k <= times; k++)
{
printf("\nROUNDR%6d : ", k);//打印第k次游戏
newcard();//进行洗牌操作,将52张牌随机打乱存储到s[52]中
printf("\n");
printf("\nPLAYER%6d : ", add/5+1);
for
(i = 0; i < 5; i++)//打印第k次游戏的扑克牌组合(包括花色和点数)
{
switch (s[i].num)
{
case 1: printf("%4c",
'A'); break;
case 11: printf("%4c", 'J'); break;
case 12: printf("%4c", 'Q'); break;
case 13: printf("%4c", 'K'); break;
default: printf("%4d", s[i].num);
}
switch (s[i].color)
{
case 3: printf("%2c", 3); break;
case 4: printf("%2c", 4);
break;
case 5: printf("%2c", 5); break;
case 6: printf("%2c", 6); break;
default: printf(" ");
}
printf(" ");
}
printf("\n");
for
(i = 0; i < 5; i++)
{
Num[i] = s[i].num;//把玩家的五张牌点数赋给数组Num[]
Color[i] = s[i].color;//把玩家的五张牌花色赋给数组Color[]
}
printf("\n");
sort(Num, 5);//对点数和花色排序,点数排序用于分析顺子、对子
sort(Color, 5);//对点数和花色排序,花色排序用于分析同花
analyze();//分析玩家手中的牌属于哪种组合方式
printf("%10s", result);//打印玩家手牌的组合方式
printf("\n");
}
printf("\n");
//输出k次游戏后,各种组合方式出现的次数,由于flush出现次数太少,因此打印的是次数而不是概率
printf("\n");
printf(" flush :%5d\n", flush);
printf(" straight :%5d\n", straight);
printf(" four :%5d\n", four);
printf("full_house:%5d\n", full_house);
printf(" three :%5d\n", three);
printf("two_pairs :%5d\n",
two_pairs);
printf(" pair :%5d\n", pair);
printf(" normal :%5d\n", normal);
return 0;
}
******/