2天时间敲了一个斗地主代码,觉得自己代码极不规范,决定重构,目标是用严格的面向对象思维、规范的代码风格、规范的命名方式重写一份。原以为这只是1小时的工作,终却断断续续花了好几天查重写后的bug。虽然代码还是很挫,但相比之前已经有了一点点可读性。大学时学了c++就以为懂了面向对象,现在回想学到的都是些渣渣,面向对象重要的是思维而不是语言规则。为提高自己代码质量不断努力。
#include <iostream> #include <vector> #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("炸dan",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=="炸dan"){ return false; }else if(this->type.typeStr=="炸dan"){ 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 输入可无序 例如: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; } }
求拍砖!
相关推荐
基于springboot教育资源共享平台源码数据库文档.zip
linux开发篇,配套视频:https://www.bilibili.com/list/474327672?sid=4493702&spm_id_from=333.999.0.0&desc=1
ReadEra 这个阅读应用能够打开下列任何格式的文档: EPUB, PDF, DOC, RTF, TXT, DJVU, FB2, MOBI, 和 CHM. 基本上来说,你可以用它阅读你的设备内存中的任何书籍或者文本文档。 这个应用与划分成章节的文档兼。,有一个书签功能,可以在你阅读的时候,自动保存你的进度。另外,它让你更改页面模式,从几种不同的主题中进行挑选(夜间,白天,棕黑色调,还有控制台)。
软件环境:KEIL4 硬件环境:STM32单片机+舵机 控制原理:通过控制输出信号的占空比调节舵机旋转的角度
基于springboot仓库管理系统源码数据库文档.zip
酒店管理系统源码C++实现的毕业设计项目源码.zip,个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分98.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 酒店管理系统源码C++实现的毕业设计项目源码.zip,酒店管理系统源码C++实现的毕业设计项目源码.zip个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分98.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。酒店管理系统源码C++实现的毕业设计项目源码.zip酒店管理系统源码C++实现的毕业设计项目源码.zip酒店管理系统源码C++实现的毕业设计项目源码.zip,个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分98.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。酒店管理系统源码C++实现的毕业设计项目源码.zip,个人大四的毕业设计、经导师指导并认可通过的高分设计项目,评审分98.5分。主要针对计算机相关专业的正在做毕
58商铺全新UI试客试用平台网站源码
springboot vue3前后端分离 基于SpringBoot+Vue的轻量级定时任务管理系统.zip
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过严格测试运行成功才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
4D毫米波雷达点云数据处理方法研究.caj
S M 2 2 5 8 X T 量产工具供大家下载使用
基于springboot的文物管理系统源码数据库文档.zip
基于springboot的电影院售票管理系统源码数据库文档.zip
基于Java web 实现的仓库管理系统源码,适用于初学者了解Java web的开发过程以及仓库管理系统的实现。
美容美发项目,使用django框架,前后端一体化项目
在线票务:2023年中国在线票务行业市场规模约为24.99亿元,挖掘市场蓝海新机遇 在数字浪潮的席卷下,传统的票务销售模式正经历着前所未有的变革。纸质门票逐渐淡出人们的视野,取而代之的是便捷、高效的数字和移动票务。这一转变不仅为消费者带来了前所未有的购票体验,更为在线票务平台开辟了广阔的发展空间和市场机遇。随着国民经济的持续增长和文体娱乐行业的蓬勃发展,中国在线票务行业正站在时代的风口浪尖,等待着每一位有志之士的加入。那么,这片蓝海市场究竟蕴藏着怎样的潜力?又该如何把握机遇,实现突破?让我们一同探索。 市场概况: 近年来,中国在线票务行业市场规模持续扩大,展现出强劲的增长势头。据QYResearch数据显示,2023年中国在线票务行业市场规模约为24.99亿元,尽管受到宏观经济的影响,市场规模增速放缓,但整体趋势依然向好。这一增长主要得益于国民人均收入的不断提高、电影及演出行业的快速发展以及政府政策的支持。例如,2023年财政部、国家电影局发布的《关于阶段性免征国家电影事业发展专项资金政策的公告》,为电影行业注入了强劲动力,进而推动了在线票务市场规模的扩大。 技术创新与趋势: 技术进步
基于SpringBoot的养老院管理系统源码数据库文档.zip
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过严格测试运行成功才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
内容概要:本文档是一份详细的Go语言教程,从基础概念介绍到高级主题均有覆盖。主要内容包括Go语言的基础语法、数据类型、控制结构、函数、结构体、接口和并发编程等方面。通过具体示例介绍了如何使用Go语言进行开发。 适合人群:初学者和有一定经验的程序员都可以从这篇教程中受益,特别是那些想要快速掌握Go语言并应用于实际项目的开发者。 使用场景及目标:适用于初学者系统学习Go语言的基础知识和常用功能;也可以作为已有开发经验者的参考资料,帮助他们解决具体的编程问题,提高开发效率。 其他说明:本教程不仅包含了Go语言的基本知识点,还重点讲解了其独特的并发编程模型。读者在学习过程中应该注重理论与实践相结合,通过实际编写代码来加深理解和记忆。
基于springboot计算机基础网上考试系统源码数据库文档.zip