網(wǎng)站轉(zhuǎn)化分析百度優(yōu)化怎么做
🌟 嗨,我是LucianaiB!
🌍 總有人間一兩風(fēng),填我十萬八千夢。
🚀 路漫漫其修遠(yuǎn)兮,吾將上下而求索。
?
C語言之斗地主游戲
目錄
- 程序概述
- 程序設(shè)計
- Card類
- CardGroup類
- Player類
- LastCards類
- Landlords類
- 游戲流程
- 特點與功能
- 牌型判斷
- AI提示
- 交互性
- 隨機性
- 測試與運行
- 總體評價
- 附錄代碼
本文介紹了一個基于C++實現(xiàn)的簡單斗地主游戲程序。該程序模擬了斗地主的基本規(guī)則和流程,包括發(fā)牌、搶地主、出牌以及勝負(fù)判定等功能。程序的核心由多個類組成,包括Card
(表示單張牌)、CardGroup
(表示一組牌)、Player
(表示玩家)、LastCards
(用于記錄上家出的牌)和Landlords
(用于管理整個游戲流程)。
程序設(shè)計
程序通過Card
類定義了牌的基本屬性,如牌面值、花色和顯示方法。CardGroup
類用于管理一組牌,并提供牌型判斷和大小比較的功能。Player
類則管理玩家手中的牌,并提供出牌和提示功能。LastCards
類用于記錄上家出的牌,并提供查找可打得過的牌的功能。Landlords
類作為游戲的核心,負(fù)責(zé)初始化游戲、發(fā)牌、搶地主、輪流出牌以及判斷游戲結(jié)束等邏輯。
游戲流程
游戲開始時,程序通過洗牌和分牌將54張牌隨機分配給三個玩家,并通過搶地主環(huán)節(jié)確定地主玩家。地主玩家獲得額外的三張底牌后,游戲正式開始。玩家按順序出牌,每次出牌需要比上家的牌大,或者選擇不出。當(dāng)某個玩家手中的牌全部出完時,游戲結(jié)束,程序會判斷地主是否獲勝。
特點與功能
- 牌型判斷:程序能夠準(zhǔn)確判斷牌型,如單牌、對子、三帶一、炸彈等,并根據(jù)牌型和牌的大小進(jìn)行比較。
- AI提示:非地主玩家在出牌時,程序會自動提示可打得過的牌,提高了游戲的流暢性。
- 交互性:程序通過控制臺輸入輸出與用戶交互,用戶可以選擇是否搶地主、出牌以及是否繼續(xù)游戲。
- 隨機性:通過隨機洗牌和搶地主環(huán)節(jié),增加了游戲的趣味性和不確定性。
測試與運行
程序在測試中表現(xiàn)出了良好的穩(wěn)定性和正確性。玩家可以自由選擇出牌策略,程序會根據(jù)規(guī)則判斷出牌是否合法,并在游戲結(jié)束后輸出勝負(fù)結(jié)果。用戶可以通過簡單的命令行交互體驗完整的斗地主游戲流程。
總體評價
本文介紹了一個基于C++實現(xiàn)的斗地主游戲程序,模擬了斗地主的基本規(guī)則和流程,包括發(fā)牌、搶地主、出牌和勝負(fù)判定等功能。程序的核心由多個類組成,如Card、CardGroup、Player、LastCards和Landlords,通過面向?qū)ο缶幊痰姆绞綄崿F(xiàn)了游戲的完整邏輯。
在程序設(shè)計中,Card類用于定義單張牌的基本屬性,如牌面值、花色和顯示方法。CardGroup類管理一組牌,并提供牌型判斷和大小比較的功能。Player類管理玩家手中的牌,并提供出牌和提示功能。LastCards類用于記錄上家出的牌,并提供查找可打得過的牌的功能。Landlords類作為游戲的核心,負(fù)責(zé)初始化游戲、發(fā)牌、搶地主、輪流出牌以及判斷游戲結(jié)束等邏輯。
游戲流程從洗牌和分牌開始,通過搶地主環(huán)節(jié)確定地主玩家。地主獲得額外三張底牌后,游戲正式開始。玩家按順序出牌,每次出牌需要比上家的牌大,或者選擇不出。當(dāng)某個玩家手中的牌全部出完時,游戲結(jié)束,程序會判斷地主是否獲勝。
該程序具有以下特點:
牌型判斷:能夠準(zhǔn)確判斷牌型,如單牌、對子、三帶一、炸彈等,并根據(jù)牌型和牌的大小進(jìn)行比較。
AI提示:非地主玩家在出牌時,程序會自動提示可打得過的牌,提高了游戲的流暢性。
交互性:通過控制臺輸入輸出與用戶交互,用戶可以選擇是否搶地主、出牌以及是否繼續(xù)游戲。
隨機性:通過隨機洗牌和搶地主環(huán)節(jié),增加了游戲的趣味性和不確定性。
在測試中,程序表現(xiàn)出良好的穩(wěn)定性和正確性,用戶可以通過簡單的命令行交互體驗完整的斗地主游戲流程。該程序不僅實現(xiàn)了斗地主的基本規(guī)則,還通過類的設(shè)計和封裝展示了面向?qū)ο缶幊痰乃枷?。代碼結(jié)構(gòu)清晰,易于理解和擴展,適合用于學(xué)習(xí)和研究C++編程以及游戲開發(fā)。
附錄代碼:
#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:
//為了規(guī)范查找對應(yīng)牌的方法
//統(tǒng)一為3個參數(shù)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;}//統(tǒng)計同點數(shù)牌有多少張int cntFlag[VALUECOUNT]={0};for(i=0;i<n;i++){cntFlag[cards[i]->value]++;}//統(tǒng)計點數(shù)最多和最少的牌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;//統(tǒng)計連續(xù)且大于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(){//計算牌組權(quán)值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){//打不過,返回空數(shù)組return ret;}int value=cardGroup.value();//統(tǒng)計各點牌出現(xiàn)的次數(shù)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){//玩家手中沒牌了,游戲結(jié)束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<<"沒人搶,重新發(fā)牌\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();//發(fā)牌、搶地主landlords->startGame();//游戲開始
}while(makeChoice("\n是否繼續(xù)游戲?(Y=繼續(xù)/N=結(jié)束): "));
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;
}
}
嗨,我是[LucianaiB](https://lucianaib.blog.csdn.net/ “LucianaiB”)。如果你覺得我的分享有價值,不妨通過以下方式表達(dá)你的支持:👍 點贊來表達(dá)你的喜愛,📁 關(guān)注以獲取我的最新消息,💬 評論與我交流你的見解。我會繼續(xù)努力,為你帶來更多精彩和實用的內(nèi)容。
點擊這里👉[LucianaiB](https://lucianaib.blog.csdn.net/ “LucianaiB”) ,獲取最新動態(tài),?? 讓信息傳遞更加迅速。