课题背景概述
21 点扑克是牌类游戏中的比较基础游戏,其基本打法为双人共玩一副洗好的 52 张牌(大小王拿走),采用回合制比每回合输赢,直至打完一副牌算总积分决出胜负。
每回合双方轮流拿牌,每人牌数 2-5 张,每回合拿牌结束时统计两人手上牌的总点数,并裁决本回合输赢。如果轮到一方拿牌而放弃,则本回合此人不能再拿牌;如果手上牌的点数超过 21 点,则算爆。如果双方都没爆,则点数较高者获胜;如果一方爆另一方没爆,则没爆者获胜;如果双方都爆,则爆的少的人(点数超过 21 点较少者)获胜。
牌点计算方式:牌面 10、J、Q、K 均算 10 点;牌面 2-9 的点数同数字;花牌 A 既可以当 1 点用,也可以当 11 点用,具体当什么用,由持有花牌者按有利于自己的策略决定,但是计算机裁决程序总是会按最有利于持花牌者的算法自动进行点数计算。
本课题是课内上机综合实验的延续,由于课题需要基于类框架建立双人对战和人机对战的整体游戏功能,因此会对前期建立的 CBlackJack 类(实现双人对战)进行进一步规划类成员变量和成员函数,从而实现整个双人对战游戏功能;在双人对战基础上,延伸出人机对战类 CAI21,实现单人和计算机智能的博弈,显然,人机对战是人的智慧和计算机智能算法之间的比拼,良好的设计应该使得计算机的赢率至少不低于人的赢率,因此,算法设计上只有更好,没有最好,颇具挑战性。然而不用急,21 点双人对战做好,人机对战就差不多了,人机对战所需的知识其实很少,主要是一个概率算法。
数据结构
typedef enum
{
//牌面A,J=10,Q=10,K=10
A = 1, two, three, four, five, six, seven, eight, nine, ten, J, Q, K
}numtype;
typedef enum
{
//扑克牌的花色:clubs(梅花),diamonds(方块),hearts(红桃)和spades(黑桃)
clubs, diamonds, hearts, spades
}shapetype;
struct Card
{
numtype num;//面值数字
shapetype shape;//花色形状
};
//定义一副牌的结构体
项目结构
//声明21点的游戏类
class cblcakjack :public cporkgame
{
//公共变量
public:
//函数声明
cblcakjack(); //无参构造函数
virtual ~cblcakjack() {};//析构函数
int Game();
void Save();
//私有变量
private:
int startPosition;//发牌初始位
Card gamers[3][21];
//gamers[0]存放庄家的牌,gamers[1]到[2]存放玩家的牌
//庄家即是电脑
int numcards[8]; //庄家(numcards[0])及玩家的牌数
char name[3][max_length]; //庄家及玩家姓名
int numgamer;//玩家数
int gameround; //局数
int gamesave[20]; //保存每次结果 0 前面的玩家负 1 平局 2 胜利
int ifTakeCard(); // 电脑是否拿牌
int GetTotalScore(Card gamer[21], int n); //返回目前手牌的总分值
void ShowStatus(int num, bool hideFirstCard = false);
//显示庄家(对应num=0)或玩家(对应num>0)的当前状态,要隐藏庄家机器人的第一次发的牌和分数
Card FirstCard()
{
return PK[startPosition++];
}//发一张扑克牌
};
// 声明洗牌的类
class cporkgame {
public:
Card PK[52];//54张牌减去大小王
cporkgame();
void Shuffle(); //洗牌函数
};
主函数
#include"game.h"
#include"card.h"
#include"shuff.h"
//重载运算符<<
//运用了const
ostream& operator<<(ostream& output, const Card& card)
{
//输出花色
if (card.shape == clubs) output << "梅花";
if (card.shape == diamonds) output << "方块";
if (card.shape == hearts) output << "红桃";
if (card.shape == spades) output << "黑桃";
//输出面值
if (card.num == A)
{
output << "A";
}
else if (card.num == J)
{
output << "J";
}
else if (card.num == Q)
{
output << "Q";
}
else if (card.num == K)
{
output << "K";
}
else cout << (int)card.num;//强制转化面值为int型
return output;
}
int main()
{
char AgainGame;
do
{
cblcakjack newGame;
int gamecontinue = 1;
while (gamecontinue <= 45)
{
gamecontinue = newGame.Game();
}
cout << endl << endl << "*********************游戏结束******************************";
cout << endl << "你想再玩一次请输入1, 复盘请输入2, 输入其他内容将直接退出:";
cin >> AgainGame;
if (AgainGame == '2') {
newGame.Save();
}
cout << endl << "***************************************************";
} while (AgainGame == '1');
return 0;
}
效果截图
每局游戏会将全部牌发完才结束
结束后可以查看复盘
数据同时会保存在文件里