编辑
- 头文件和命名空间:代码包含了一些基本的头文件,如
iostream
、vector
、algorithm
等,并使用了标准命名空间std
。 - 宏定义:定义了一些宏,如
PLAYERCOUNT
(玩家数量)、CARDSCOUNT
(牌的总数)、VALUECOUNT
(牌面值的数量)等。 - 颜色枚举:定义了一个
COLOR
枚举,表示牌的花色。 Card
类:表示单张牌,包含牌面值、花色和牌的值。有一个print
方法用于打印牌的信息。CardsType
类:用于表示牌型的类型,如单牌、对子、炸弹等。CardGroup
类:表示一组牌,可以是单张牌、对子、顺子等。包含牌的数组和牌型的类型。有方法来计算牌型、初始化牌组、判断是否能打过另一组牌等。LastCards
类:用于记录上一次出的牌,使用单例模式实现。Player
类:表示玩家,包含玩家的名字、手中的牌、出牌方法等。Landlords
类:是游戏的主类,包含玩家数组、牌数组、是否结束游戏等状态。有方法来初始化游戏、开始游戏、洗牌、发牌、抢地主、检查出牌是否合法等。main
函数:程序的入口点,创建Landlords
对象,循环进行游戏。- 辅助函数:
makeChoice
用于获取用户的选择,cmp
用于比较两张牌的大小。
#include <iostream> #include<vector> #include<assert.h> #include<string> #include<stdio.h> #include<algorithm> #include<time.h> using namespace std; #define PLAYERCOUNT 3 #define CARDSCOUNT 54 #define CURRENTPLAYER 0 #define VALUECOUNT 17 #define ERROR -1 using namespace std; int scnt=0; const char toFigure[]="34567890JQKA 2YZ"; enum COLOR{ //花色显示ASCII: 3~6 eHEART=3,//红桃 eDIAMOND=4,//方片 eCLUB=5, //草花 eSPADE=6 //黑桃 }; 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); switch (color) { case eHEART: cout << "♥"; // 红桃 break; case eDIAMOND: cout << "♦"; // 方片 break; case eCLUB: cout << "♣"; // 草花 break; case eSPADE: cout << "♠"; // 黑桃 break; default: cout << "?"; // 未知花色 break; } cout << figure << ' '; } }; 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=="炸弹"){ 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(); //没牌打得过时查找有没有炸弹 if(typeStr!="炸弹"){ 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=0,j=0,k=0; 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 i1=0;i1<CARDSCOUNT;i1++){ delete this->cards[i1]; } } 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; } }