斗地主游戏代码

代码!:

#include<bits/stdc++.h>
#define PLAYERCOUNT 3
#define CARDSCOUNT 54
#define CURRENTPLAYER 0
#define VALUECOUNT 17
#define ERROR -1

using namespace std;
const char toFigure[]="34567890JQKA 2YZ";
enum COLOR{  //花色显示ASCII: 3~6
	eHEART=3,//红桃
	eDIAMOND,//方片
	eCLUB,   //草花
	eSPADE   //黑桃
};

class Card;
class CardsType;
class CardGroup;
class Player;
class Landlords;
class LastCards;
bool makeChoice(string tip);
bool cmp(Card* a,Card* b);

class Card{
	
public:
	char figure;
	COLOR color;
	int value;
	Card(char _figure,COLOR _color){
		figure=_figure;
		color=_color;
		value=calValue();
	}
	int calValue(){
		for(int i=0;toFigure[i];i++){
			if(toFigure[i]==figure){
				return i;
			}
		}
		return ERROR;
	}
	void print(){
		assert(value!=ERROR);
		if(figure=='Z'){
			cout<<"ZZ";
		}else if(figure=='Y'){
			cout<<"YY";
		}else{
			cout<<figure<<(char)color;
		}
		cout<<' ';
	}
};

class CardsType{
public:
	//为了规范查找对应牌的方法
	//统一为3个参数cnt1、isContinuous、cnt2
	int typeId;
	string typeStr;
	int cnt1,cnt2;
	bool isContinuous;
	CardsType(){
		typeId=ERROR;
	}
	bool operator ==(const CardsType& other)const{
		return this->typeId==other.typeId;
	}
	void init(char* _typeStr,int _typeId,int _cnt1,bool _isContinuous,int _cnt2){
		cnt1=_cnt1;
		isContinuous=_isContinuous;
		cnt2=_cnt2;
		typeStr=_typeStr;
		typeId=_typeId;
	}
};

class CardGroup{
public:
	vector<Card*> cards;
	CardsType type;
	void calType(){
		int i,n=cards.size();
		//init(typeStr,typeId,cnt1,isContinuous,cnt2)
		if(n==0){
			type.init("不出",14,0,0,0);
			return;
		}
		if(n==2&&cards[0]->value==15&&cards[1]->value==14){
			type.init("王炸",0,0,0,0);
			return;
		}
		//统计同点数牌有多少张
		int cntFlag[VALUECOUNT]={0};
		for(i=0;i<n;i++){
			cntFlag[cards[i]->value]++;
		}
		//统计点数最多和最少的牌
		int maxCnt=0,minCnt=4;
		for(i=0;i<VALUECOUNT;i++){
			if(maxCnt<cntFlag[i]){
				maxCnt=cntFlag[i];
			}
			if(cntFlag[i]&&minCnt>cntFlag[i]){
				minCnt=cntFlag[i];
			}
		}
		if(n==4&&maxCnt==4){
			type.init("炸蛋",1,4,0,0);
			return;
		}
		if(n==1){
			type.init("单牌",2,1,0,0);
			return;
		}
		if(n==2&&maxCnt==2){
			type.init("对子",3,2,0,0);
			return;
		}
		if(n==3&&maxCnt==3){
			type.init("三张 ",4,3,0,0);
			return;
		}
		if(n==4&&maxCnt==3){
			type.init("三带一",5,3,0,1);
			return;
		}
		if(n==5&&maxCnt==3&&minCnt==2){
			type.init("三带一对",6,3,0,2);
			return;
		}
		if(n==6&&maxCnt==4){
			type.init("四带二",7,4,0,1);
			return;
		}
		if(n==8&&maxCnt==4&&minCnt==2){
			type.init("四带二",8,4,0,2);
			return;
		}
		if(n>=5&&maxCnt==1&&cards[0]->value==cards[n-1]->value+n-1){
			type.init("顺子",9,1,1,0);
			return;
		}
		if(n>=6&&maxCnt==2&&minCnt==2&&cards[0]->value==cards[n-1]->value+n/2-1){
			type.init("连对",10,2,1,0);
			return;
		}
		int fjCnt;//统计连续且大于3三张的牌
		for(i=0;i<VALUECOUNT &&cntFlag[i]<3;i++);
		for(fjCnt=0;i<VALUECOUNT &&cntFlag[i]>=3;i++,fjCnt++);
		if(fjCnt>1){
			if(n==fjCnt*3)
				type.init("飞机",11,3,1,0);
			else if(n==fjCnt*4)
				type.init("飞机",12,3,1,1);
			else if(n==fjCnt*5&&minCnt==2)
				type.init("飞机",13,3,1,2);
		}
	}
	void init(string inputStr, vector<Card*> &cardsHolded){
		this->cards.clear();
		//不出
		if(inputStr=="N"){
			this->calType();
			return;
		}
		int i,j;
		//输入合法性判断
		for(i=0;i<inputStr.size();i++){
			bool find=false;
			for(j=0;toFigure[j];j++){
				if(inputStr[i]==toFigure[j]){
					find=true;
					break;
				}
			}
			if(find==false){
				//输入字符不在toFigure中
				return;
			}
		}
		//查找手中有没有这些牌
		int visitFlag[20]={0};
		for(i=0;i<inputStr.size();i++){
			Card *find=NULL;
			for(j=0;j<cardsHolded.size();j++){
				if(!visitFlag[j]&&cardsHolded[j]->figure==inputStr[i]){
					visitFlag[j]=1;
					find=cardsHolded[j];
					break;
				}
			}
			if(find){
				this->cards.push_back(find);
			}else{
				cout<<inputStr[i];
				cout<<"没有找到\t";
				this->cards.clear();
				return;
			}
		}//end for(i=0;i<inputStr.size();i++)
		this->arrange();
	}
	void init(vector<Card*> newCards){
		this->cards=newCards;
		this->arrange();
	}
	bool isCanBeat(CardGroup &cardGroup){
		if(cardGroup.type.typeStr=="王炸"){
			return false;
		}else if(this->type.typeStr=="王炸"){
			return true;
		}else if(cardGroup.type==this->type &&this->type.typeStr=="炸dan"){
			return value()>cardGroup.value();
		}else if(cardGroup.type.typeStr=="炸蛋"){
			return false;
		}else if(this->type.typeStr=="炸蛋"){
			return true;
		}else if(cardGroup.type==this->type &&this->cards.size()==cardGroup.cards.size()){
			return this->value()>cardGroup.value();
		}else{
			return false;
		}
	}
	int value(){
		//计算牌组权值
		int i;
		if(type.typeStr=="三带一"||type.typeStr=="三带一对"||type.typeStr=="飞机"){
			for(i=2;i<cards.size();i++){
				if(cards[i]->value==cards[i-2]->value){
					return cards[i]->value;
				}
			}
		}
		if(type.typeStr=="四带二"){
			for(i=3;i<cards.size();i++){
				if(cards[i]->value==cards[i-3]->value){
					return cards[i]->value;
				}
			}
		}
		return cards[0]->value;
	}
	void arrange(){
		//整理:排序、计算类型
		sort(this->cards.begin(),this->cards.end(),cmp);
		this->calType();
	}
};
class LastCards{
	static LastCards *lastCards;
public:
	Player *player;
	CardGroup cardGroup;
	static LastCards* inst(){//单例模式
		if(lastCards==NULL){
			lastCards=new LastCards();
		}
		return lastCards;
	}
	vector<Card*> findCanBeatFrom(vector<Card*> &cardsHolded){
		//查找能打得过的牌
		int i,j,k,n=cardsHolded.size(),m=cardGroup.cards.size();
		string typeStr=cardGroup.type.typeStr;
		vector<Card*> ret;
		if(typeStr=="王炸"||n<m){
			//打不过,返回空数组
			return ret;
		}
		int value=cardGroup.value();
		//统计各点牌出现的次数
		int cntFlag[VALUECOUNT]={0};
		for(i=0;i<n;i++){
			cntFlag[cardsHolded[i]->value]++;
		}
		int continuousCount=1;
		if(cardGroup.type.isContinuous){
			continuousCount=m/(cardGroup.type.cnt1+cardGroup.type.cnt2);
		}
		bool findFirstFigure;
		//cout<<"continuousCount="<<continuousCount<<endl;
		for(i=value+1;i<VALUECOUNT;i++){
			findFirstFigure=true;
			for(j=0;j<continuousCount;j++){
				if(cntFlag[i-j]<cardGroup.type.cnt1){
					findFirstFigure=false;
					break;
				}
			}
			if(findFirstFigure){
				ret.clear();
				int firstFigure=i;
				//cout<<"查找"<<cardGroup.type.cnt1<<"个"<<firstFigure+3<<endl;
				for(k=0,j=0;k<cardsHolded.size() &&j<continuousCount;k++){
					if(cardsHolded[k]->value==firstFigure-j){
						for(int kk=0;j>=0&&kk<cardGroup.type.cnt1;kk++){
							ret.push_back(cardsHolded[k+kk]);
						}
						j++;
					}
				}
				if(cardGroup.type.cnt2>0){
					int SecondFigures[5];
					int SecondCount=continuousCount;
					if(cardGroup.type.typeStr=="四带二")
						SecondCount=2;
					bool findSecondFigure=true;
					for(j=0,k=-1;j<SecondCount &&findSecondFigure;j++){
						findSecondFigure=false;
						for(k++;k<VALUECOUNT;k++){
							SecondFigures[j]=k;
							if(cntFlag[k]>=cardGroup.type.cnt2 &&cntFlag[k]<cardGroup.type.cnt1){
								findSecondFigure=true;
								break;
							}
						}
					}
					if(findSecondFigure){
						//cout<<"查找SecondFigure "<<cardGroup.type.cnt2<<"个"<<SecondFigures[0]+3<<endl;
						//cout<<"SecondCount= "<<SecondCount<<endl;
						//for(i=0;i<SecondCount;i++)cout<<"SecondFigures["<<i<<"]="<<SecondFigures[i]<<endl;
						for(i=0;i<SecondCount;i++){
							for(j=0;j<cardsHolded.size();){
								if(cardsHolded[j]->value==SecondFigures[i]){
									for(k=0;k<cardGroup.type.cnt2;k++){
										//cout<<"添加"<<cardsHolded[j]->value+3<<endl;
										ret.push_back(cardsHolded[j+k]);
									}
									do{
										j++;
									}while(j<cardsHolded.size()&&cardsHolded[j]->value==SecondFigures[i]);
								}else{
									j++;
								}
							}
						}
						return ret;
					}//if(findSecondFigure)
				}//end if(cardGroup.type.cnt2>0)
				else{
					return ret;
				}
			}//end if(findFirstFigure)
		}//end for(i=value+1;i<VALUECOUNT;i++)
		ret.clear();
		//没牌打得过时查找有没有炸dan
		if(typeStr!="炸dan"){
			for(i=cardsHolded.size()-1;i>=3;i--){
				if(cardsHolded[i]->value==cardsHolded[i-3]->value){
					for(j=0;j<4;j++){
						ret.push_back(cardsHolded[i-j]);
					}
					break;
				}
			}
		}
		return ret;  
	}//end vector<Card*> findCanBeatFrom()
};
LastCards* LastCards::lastCards = NULL;

class Player{
public:
	string name;
	vector<Card*> cards;
	void arrange(){
		sort(cards.begin(),cards.end(),cmp);
	}
	void print(){
		cout<<this->name<<":\t";
		for(int i=0;i<cards.size();i++){
			cards[i]->print();
		}
		cout<<"["<<cards.size()<<"]\n";
	}
	vector<Card*> tip(){
		//提示功能,使自己最小一张连最长
		CardGroup ret;
		string temp;
		int j,k,m=cards.size();
		for(j=0;j<m;j++){
			temp="";
			for(k=j;k<m;k++){
				temp+=cards[k]->figure;
			}
			ret.init(temp,cards);
			if(ret.type.typeId!=ERROR){
				return ret.cards;
			}
		}
		ret.cards.clear();
		return ret.cards;
	}
	void chupai(CardGroup &cardGroup){
		//出牌
		cout<<this->name<<":\t";
		cout<<cardGroup.type.typeStr<<' ';
		for(int i=0;i<cardGroup.cards.size();i++){
			cardGroup.cards[i]->print();
			this->cards.erase(find(this->cards.begin(),this->cards.end(),cardGroup.cards[i]));
		}
		cout<<"\t["<<this->cards.size()<<"]\n";
		if(cardGroup.type.typeStr!="不出"){
			//记录到 LastCards 中
			LastCards::inst()->player=this;
			LastCards::inst()->cardGroup.init(cardGroup.cards);
		}
	}
};

class Landlords{
	Player *player[PLAYERCOUNT];
	bool finished,youWin,landlordWin;
	int landlordIndex;
	Card *cards[CARDSCOUNT];
public:
	Landlords(){
		int i,j,k;
		for(i=0;i<PLAYERCOUNT;i++){
			this->player[i]=new Player();
		}
		//54张牌初始化
		for(k=i=0;i<14;i++){
			if(toFigure[i]==' '){
				continue;
			}
			for(COLOR color=eHEART;color<=eSPADE;color=(COLOR)(color+1)){
				this->cards[k++]=new Card(toFigure[i],color);
			}
		}
		this->cards[k++]=new Card('Y',eSPADE);
		this->cards[k]=new Card('Z',eHEART);
	}
	~Landlords(){
		for(int i=0;i<PLAYERCOUNT;i++){
			delete this->player[i];
		}
		for(int i=0;i<CARDSCOUNT;i++){
			delete this->cards[i];
		}
	}
	void init(){
		player[CURRENTPLAYER]->name="Bice";
		player[1]->name="玩家2";
		player[2]->name="玩家3";
		finished=false;
		youWin=false;
		landlordWin=false;
		//抢地主
		landlordIndex=ERROR;
		while(landlordIndex==ERROR){
			srand((int)time(0));
			shuffle();
			landlordIndex=chooseLandlord();
		}
		cout<<player[landlordIndex]->name<<"\t成为地主\n\n";
		this->add3Cards();
		LastCards::inst()->player=player[landlordIndex];
	}
	void startGame(){
		string inputSrt;
		CardGroup inputCards;
		for(int iTurns=landlordIndex;!finished;iTurns++){
			if(iTurns>=PLAYERCOUNT){
				iTurns=0;
			}
			if(iTurns==CURRENTPLAYER){
				cout<<endl;
				player[iTurns]->print();
				cout<<"输入提示:两个Z=大王 两个Y=小王 0=10 输入可无序 N=不出 例如:JKQ0A9\n请出牌:\t";
				do{
					cin>>inputSrt;
					inputCards.init(inputSrt,player[iTurns]->cards);
				}while(check(&inputCards)==false);
			}else{
				if(player[iTurns]==LastCards::inst()->player){
					//若是上次出牌的是自己,启用提示功能
					inputCards.init(player[iTurns]->tip());
				}else{
					//查找能打得过上家的牌
					inputCards.init(LastCards::inst()->findCanBeatFrom(player[iTurns]->cards));
				}
			}
			player[iTurns]->chupai(inputCards);//出牌
			
			if(player[iTurns]->cards.size()==0){
				//玩家手中没牌了,游戏结束
				finished=true;
				landlordWin=iTurns==landlordIndex;
				if(landlordWin){
					youWin=landlordIndex==CURRENTPLAYER;
				}else{
					youWin=landlordIndex!=CURRENTPLAYER;
				}
			}
		}
		cout<<"\n_________________________ "<<(youWin?"You Win!":"You Lose!")<<" _________________________\n\n";
	}
	void add3Cards(){
		cout<<"地主3张牌:\t";
		for(int i=PLAYERCOUNT*17;i<CARDSCOUNT;i++){
			this->cards[i]->print();
			player[landlordIndex]->cards.push_back(cards[i]);
		}
		cout<<endl;
		player[landlordIndex]->arrange();
	}
	int chooseLandlord(){
		cout<<"\n_________________________ 抢地主 _________________________\n\n";
		int first=-1,last,cnt=0,i,j=rand()%PLAYERCOUNT;
		bool decision;
		for(i=0;i<PLAYERCOUNT;i++,j==2?j=0:j++){
			if(j==CURRENTPLAYER){
				decision=makeChoice("是否抢地主?(Y=抢/N=不抢):");
			}else{
				decision=rand()%2;
			}
			if(decision){
				cnt++;
				last=j;
				if(first==-1){
					first=j;
				}
				cout<<this->player[j]->name<<"\t抢地主\n";
			}else{
				cout<<this->player[j]->name<<"\t没有抢\n";
			}
		}
		if(cnt==0){
			cout<<"没人抢,重新发牌\n";
			return ERROR;
		}
		if(cnt==1){
			//第一轮只有一人抢地主
			return first;
		}
		else{
			//最后一次争抢
			if(first==CURRENTPLAYER){
				decision=makeChoice("是否抢地主?(Y=抢/N=不抢):");
			}else{
				decision=rand()%2;
			}
			if(decision){
				cout<<this->player[first]->name<<"\t抢地主\n";
				return first;
			}else{
				cout<<this->player[first]->name<<"\t没有抢\n";
				return last;
			}
		}
	}
	void shuffle(){
		int i,j,k;    
		//洗牌
		for(i=0;i<CARDSCOUNT;i++){
			swap(this->cards[i],this->cards[rand()%CARDSCOUNT]);
		}
		//分牌
		for(k=i=0;i<PLAYERCOUNT;i++){
			this->player[i]->cards.clear();
			for(j=0;j<17;j++){
				this->player[i]->cards.push_back(this->cards[k++]);
			}
			this->player[i]->arrange();//整理
			this->player[i]->print();
		}
	}
	bool check(CardGroup *cardGroup){
		if(cardGroup->type.typeId==ERROR){
			cout<<"出牌错误,重新输入\n";
			return false;
		}else if(cardGroup->type.typeStr=="不出"){
			return true;
		}else if(LastCards::inst()->player!=player[CURRENTPLAYER]&&!cardGroup->isCanBeat(LastCards::inst()->cardGroup)){
			cout<<"打不过,重新输入\n";
			return false;
		}else{
			return true;
		}
	}
};

int main(){
	Landlords *landlords=new Landlords();
	do{
		landlords->init();//发牌、抢地主
		landlords->startGame();//游戏开始
	}while(makeChoice("\n是否继续游戏?(Y=继续/N=结束): "));
	delete landlords;
	return 0;
}

bool makeChoice(string tip){
	cout<<tip;
	string input;
	cin>>input;
	return input=="Y"||input=="y";
}

bool cmp(Card* a,Card* b){
	//比较两张牌大小
	if(a->value==b->value){
		return a->color>b->color;
	}else{
		return a->value>b->value;
	}
}

用C++写的基于MFC界面的斗地主游戏源码,内含详细注释,附带了简单的AI出牌规则,放出来供大家参考交流。vs2010编写,vs2015测试可用,理论上vs05及以上都可正常编译运行。 void Judge::MainFlow() { switch(DataCenter::Instance().GetPlayState()) { case EM_LandHolderBorn_PlayState: { //先检查是否已经问完了 //遍历玩家检查是否已经询问过了,如果已经都问过了,则设置叫分最高的为地主 BOOL bAllAsked = TRUE;//是否已经询问完了 vector & vecPlayer = DataCenter::Instance().GetPlayerList(); for (UINT i = 0; i m_nCurHighstScore) { m_nCurHighstScore = vecPlayer[i].GetLandOwerScore(); m_pToBeLandOwer = &vecPlayer;[i]; } if (vecPlayer[i].GetLandOwerScore() SetLandOwer(TRUE); } //然后根据情况执行询问流程 //如果地主已经产生,则跳入下一阶段 if (NULL != DataCenter::Instance().GetLandOwner()) { m_pCurPlayer = NULL; DataCenter::Instance().SetPlayState(EM_WaitPlayer_PlayState); MainFlow(); return; } //如果当前player为空,设置当前player为地主牌得主 if (m_pCurPlayer == NULL) { m_pCurPlayer = DataCenter::Instance().GetLandOwnerCardHolder(); } //对当前玩家执行地主问询 ASSERT(m_pCurPlayer); m_pCurPlayer->ExcuteCallLandOwer(); } break; case EM_WaitPlayer_PlayState: { //如果游戏已经结束,则执行结束逻辑 BOOL bLandOwerWin = FALSE; if (DataCenter::Instance().IsOver(bLandOwerWin)) { if (bLandOwerWin) { AfxMessageBox(_T("地主赢了!")); } else { AfxMessageBox(_T("佃户赢了!")); } DataCenter::Instance().SetPlayState(EM_WaitToStart_PlayState); //将所有玩家明牌 DataCenter::Instance().ShowAllPlayerCard(); RefreshView(); return; } //如果是出牌阶段而当前player为空,设置当前player为地主,并发予底牌 if (m_pCurPlayer == NULL) { m_pCurPlayer = DataCenter::Instance().GetLandOwner(); DataCenter::Instance().SendOutBottomCard(); RefreshView(); } ASSERT(m_pCurPlayer); m_pCurPlayer->ExcuteCallCardPlay(); } break; } } void Judge::CurPlayerCallScore(int nScore) { if (m_pCurPlayer == NULL) { ASSERT(FALSE); return; } //将玩家选择的分数设置给玩家 m_pCurPlayer->SetLandOwerScore(nScore); //如果当前玩家为空,直接返回 if(m_pCurPlayer == NULL) { return; } if (nScore == 3) { //如果玩家叫了三分,直接设为地主 m_pCurPlayer->SetLandOwer(TRUE); } else { //玩家叫的不是三分,则记下玩家叫的分数 m_pCurPlayer->SetLandOwerScore(nScore); } if (nScore == 0) { CString strWord; strWord.Format(_T("不叫")); m_pCurPlayer->Say(strWord); } else { CString strWord; strWord.Format(_T("%d分"), nScore); m_pCurPlayer->Say(strWord); } //玩家叫分后隐藏叫地主按钮 Judge::Instance().ShowCallLandOwerBtn(FALSE); //切换到下一个玩家,流程继续 SwitchToNextPlayer(); MainFlow(); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值