c语言关于21点游戏人机对战人人对战设计及源代码

本文介绍了21点游戏的人机对战设计,重点讲解了如何实现电脑玩家的智能决策,包括洗牌、发牌、计算爆牌概率等功能。代码以C++实现,包括AI决策函数IfTakeCard、RobotTakeCard等,展示了电脑玩家如何判断是否要牌以及A牌点数的选择策略。
摘要由CSDN通过智能技术生成

21点游戏要求做到设计出人和电脑对战的21点游戏,同时电脑既然作为另一个玩家,也就必须具备自主选择的意识,那么在21点中,需要电脑做出选择的也就是几个选项,一是牌点的比较,二是根据目前形势是否要牌的判断,三是自主判断A点作为几点更加合适,只有实现这三个目标,电脑玩家才能被成为比较智能的进行游戏,而不同情况下,电脑玩家如何选择是否要牌也就是一大难点。

关于设计

  1. 首先是在洗牌程序中避免繁杂洗牌,只用分别定义两个数组来进行“牌”和“空位”的交换就可以以此达到随机的目的,并且简洁易懂。
  2. 然后是在发牌亮牌函数中,要让记牌器随发牌移动,同时要统计玩家手牌,这里我采用了for循环来达到目的,也就是在每次发牌之后自动让记牌器顺沿一位,这样就避免了多次书写记牌器移动,而玩家手上亮牌也可以用for循环,直接在i<5的情况下,不断自加然后亮出每一张现有的手牌(玩家手牌小于等于5)。
  3. 还有在电脑判断是否要牌的情况,在主函数里加入true和false两个声明,分别定义要牌和不要牌,这样就大量减少了代码重复,同时也非常简洁明了,只需要判断当前状况后加上return true or false某一种情况即可。

最后是在程序中设计到的计算概率,直接在计算概率中引入了数组,每一个数组空位用来计算一张牌的剩余量,通过switch的结构让循环剩余牌不断在数组中自加,也就计算出了剩余牌各自的张数,再通过一个for循环,让小于爆牌点数的牌数全部相加,这样做不仅减少了很大的工作量,同时也让对剩余牌的计算更加简洁,效率更高

对于A牌点数的选择

Int point,a;

//a为A牌数量

Int A=11;

//将所有a牌先当做11计算

if (a > 0)

 { for (int i = 0; i < a; i++)

{

if(point>21)

{

point -= 10;//将a一律先当做11计算,如果爆牌则不断自减10,也就是把a再看为1点,直到不爆牌为止

}

}

return(point);

}

else return(point);

}

以下是未进行封装的各个文件源代码:

AI21.Cpp:

#include "StdAfx.h"

#include "AI21.h"

CAI21::CAI21(void)

{

}

CAI21::~CAI21(void)

{

}

//函数作用:判断玩家是否应该拿牌的决策函数

//输入参数:id—玩家ID(0或1),cards—洗好的52张牌数组,roundCards—两玩家回合存牌数组,roundCardCnts—两玩家回合存牌计数器数组,topIndex—牌数组中当前面上的牌序号

//返回值:是否应该拿下一张牌

//函数说明:本函数被机器人拿牌函数RobotTakeCard所调用,RobotTakeCard大体上是与人类拿牌函数TakeCard差不多的,而主要的核心差别就是对本函数的调用取代了玩家1的TakeCard

bool CAI21::IfTakeCard(int id, char cards[52], char roundCards[2][5], int roundCardCnts[2], int topIndex)

{ //请在以下分段注释下空白处填写相应的实现代码

//1、排除必须拿和必须不拿的情况

//如果已经无牌可拿,则直接返回false

if (topIndex == 52)

return false;

else {

//计算自己和对方当前手上牌点

int cai = this->CalcuPoint(roundCards[0], roundCardCnts[0]);

int gou = this->CalcuPoint(roundCards[1], roundCardCnts[1]);

//如果自己已经爆了或者正好拿到21点满分,或者对方已经爆了,则肯定不再拿牌,返回false

if ((cai >= 21) || (gou > 21))

return false;

//在都未爆的情况下,如果自己牌点落后于对方,则无论如何都必须拿牌,返回true

else {

if ((cai < 21) && (cai < gou) && (gou < 21))

return true;

//2、在当前牌点领先或持平于对方的情况下,依据爆的概率大小决定是否拿牌

//统计13种面值的剩余牌张数(为避免记忆已经打过的牌,这里直接从topIndex开始统计剩余牌,但要清楚实际打牌的时候是一副牌扣除打过的牌得到剩余牌张及其数量的,即需要记牌)

else {

int c[13];

for (int i = topIndex; i <= 51; i++)

{

switch (cards[i])

{

case'A':c[0]++; break;

case'2':c[1]++; break;

case'3':c[2]++; break;

case'4':c[3]++; break;

case'5':c[4]++; break;

case'6':c[5]++; break;

case'7':c[6]++; break;

case'8':c[7]++; break;

case'9':c[8]++; break;

case'D':c[9]++; break;

case'J':c[10]++; break;

case'Q':c[11]++; break;

case'K':c[12]++; break;

}

}

//生成预测拿牌临时数组(该临时数组仅用于预测拿牌后是否会爆)

char myCards[5], myCnt = roundCardCnts[id];//我的预测拿牌数组和当前牌数

for (int i = 0; i < myCnt; i++)

myCards[i] = roundCards[id][i];//复制当前我手上的牌数组

//计算拿下一张牌后爆的总概率(可能性)

float percent = 0;//总爆率

if (cai <= 11)

return true;

else

{

int d=21 - cai, sum= 0;

for(int i= d;i< 13;i++)

{

sum+= c[i];

}

percent = sum / (51 - topIndex);

}

//依据爆率是否小于0.5决定是否拿牌,爆率小于0.5则返回true,否则返回false

if ((percent < 0.5))

{

return false;

}

else

return true;

}

}

}

}

//函数作用:机器人玩家的拿牌函数(包括提示拿牌、拿牌、亮牌三个过程)

//输入参数:id—机器人玩家ID(0或1),cards—洗好的52张牌数组

//输入输出参数:roundCards—两玩家回合存牌数组,roundCardCnts—两玩家回合存牌计数器数组,topIndex—牌数组中当前面上的牌序号

//返回值:执行本函数后,玩家是否还有要牌权

bool CAI21::RobotTakeCard(int id, char cards[52], char roundCards[2][5], int roundCardCnts[2],  int &topIndex)

{

//系统提示拿牌

std::cout << "玩家"<<id + 1<<":按下\'y\'键拿牌或按下\'n\'键放弃:" ;

//机器人自动决策拿牌并自动回应

bool bRet = IfTakeCard(id, cards, roundCards, roundCardCnts, topIndex);//确定是否有要牌权

std::cout << (bRet ? 'y' :

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
21是一种扑克牌游戏,既可以双人对战,也可以人机对战。下面我将用300字来介绍C语言中如何实现这两种对战方式。 首先,对于双人对战,我们可以创建一个双人模式的21游戏。首先,程序会随机发两张牌给每位玩家,然后玩家可以选择要继续拿牌还是停止。拿牌时,程序会再次随机给玩家一张牌,玩家的牌会自动计算和显示。当一位玩家选择停止或者牌总和超过21时,游戏结束,程序会计算双方牌总和并宣布获胜者。 其次,对于人机对战,我们可以创建一个与玩家对战21游戏。类似于双人对战,程序会发两张牌给玩家和AI,然后AI会根据一定的策略选择是否继续拿牌。AI可以根据牌总和来决定要不要继续拿牌,以增加赢的机会。当玩家选择停止或者牌总和超过21时,游戏结束,程序会宣布双方的牌总和并宣布胜利者。 无论是双人对战还是人机对战,在C语言中可以使用随机数函数来模拟发牌的过程,使用条件语句和循环语句来实现玩家选择拿牌或停止的功能,使用计算和判断语句来计算和判断牌总和。此外,还可以使用函数来封装不同的功能,增加代码的可读性和可维护性。 总之,C语言可以很好地实现21双人对战人机对战。通过创建一个简单易懂的游戏界面和实现相关的算法,玩家可以享受到与朋友或者AI对战的乐趣。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值