实验目标:
实现两个人可以一起玩21点游戏
设计流程:
整体以main函数为主体,然后在黑杰克cpp文件里进行函数具体代码来被调用;
在基础框架之上,后续通过各种测试,调试进行了补充
(1)洗牌函数
问题一:定义字符型char牌数组还是整型int牌数组?
答:整型int牌数组。因为定义int牌型数组相较于定义char型牌数组可以用循环赋值,且方便后续计算,故采用了int型1-13牌数组。
问题二:定义整型int牌数组不能显示出A,J,Q,K。
答:在需要进行转化在需要向外输出的步骤中,采用了switch来进行转化输出,如下
Begin
switch()
case 1 printf A
case 2-10 printf 2-10
case 11 printf J
case 12 printf Q
case 13 printf K
End
问题三(核心):如何实现随机性洗牌
答:通过时间函数srand来实现,交换通过一个从0开始计数增加,与随机数产生的位置来进行交换,就达到了洗牌的目的
#include<time.h>
srand((unsigned)time(NULL))
问题四:某些位置可能被交换多次,如何避免?
答:临时定义了一个记录位置数组:place [52]通过对交换时的随机数位置记录,而在下次交换之前,判断是否重复,如若重复则顺序增加数继续++,直到+到不重复的位置
for(int t = 0;place[t]!=0; t++)
if (i == place[t])i++
(2)回合归零函数
①在运行过程中,对回合分数计算不能延续到第(5)部分,所以加入一个新的量:
m_bScore[2]
来存储两玩家当前回合总分数。
②将每个回合运行过程中的存牌数组 m_cRoundCards[i][j] 归零。
③因为每个回合,一个玩家有五个回合拿牌,所以定义一个数组计存回合数
Local[i]
确保在五回合后可以退出。
(3)发牌函数
发牌时因为两个人手里没有牌,而任何两张牌都不会爆掉,所以为了简化拿牌过程,则在一开始则为每个人轮流发两张牌
(4)拿牌函数
①提示是否要牌,记录键盘输入字符,利用switch判断真假,并改变要牌权m_bTakeCardRights[IPlayerID]。
②依据输入要牌权是否为真,发牌并将发出的牌记录到牌数组m_cRoundCards[i][j]里
③显示所拿到的牌,展示(通过洗牌函数中的switch)
(5)计算本回合分函数
①统计每个人各拿了多少A(即是1)
定义 n 暂存A个数
for (i=0 i<5 i++)
if m_cRoundCards[ID][i]==1
i++
n++
②将J,Q,K(即11,12,13)替换为10,方便后续计算,依次比较每个数,大于10则替换
③输入n依据A个数,匹配不同情况
i.0个A,则直接累加
ii.含有A(即A!=0),则先累加,再加10,判断是否超21,如若超过,则在减10恢复。
注:因为不可能有两个A同时等于11,这样必超过21,所以只要有即实验一次是否超过21,其余A均按1加
(6)裁决本回合谁赢了
分为三种情况:两个人都爆了,两个人都没爆,一个人爆一个人没有爆
在这三种情况下分别讨论:都没爆比较点数大小
一个爆一个没有,没有爆的获胜
都爆了则比较谁的接近21,接近21获胜
(胜利同时计分器加点)
(7)计算总分函数
比较iTotalScore[0]和 iTotalScore[1]
谁大即谁最终赢了
并显示比分
iTotalScore[0] : iTotalScore[1]
测试结果:
- 输出结果问题:输完发牌函数,屏幕上显示每个人的发牌结果显示了两次。
分析:可能相关函数代码调用了两次,被运行两次
- 输出结果:第一次运行,输入第一位玩家回答无论Y或者N,第二位玩家都被忽略
分析:可能输入有问题,上网搜索输入的注意
- 输出结果:不能正常退出,会显示发放最后一张牌是52
分析:退出条件多样,没有考虑全,可能一步步调试来确定位置所在
解决问题的过程:
1.对测试结果1的问题:
在检查洗牌函数时,问题出在构造体调用一次,而在主函数里也调用了一次,最后删除构造体中的调用,了解了主函数和构造体关系
2. 对测试结果2的问题:
学习到在循环输入时,应当在%c前加入空格。
3.对测试结果3的问题:
通过思考、语法推断和反复多次调试,判断大概位置出现在发牌函数发牌,不严谨的问题有:余牌不足4张,发4张牌错误;拿牌时,牌已尽,错误;局数已经超五局,错误。
最后在发牌时和拿牌时增加判断条件,增加局数数组,解决了退出问题。
工程文件:
链接:https://pan.baidu.com/s/1V9lDNT6KRxVkvTI6-35vFw?pwd=yjki
提取码:yjki