这几天比較空,所以想写一点东西。
斗地主的程序一直以来都想写,但感觉规则推断比較复杂,一直没有较多的时间来写。
这次主要是把跟牌和牌型的推断写出来了。写了一个比較弱智的AI,属于有牌就出的那种。对于AI算法,临时没有什么好的想法,所以打算临时放一放。
后期补上界面之后再进行优化。
在这就把基本的函数和算法列出来吧。
首先是主程序,主要控制显示和游戏的流程。
#include <iostream> #include "PokerDesk.h" using namespace std; int main() { cout<<"-------------------------------------------"<<endl; cout<<"-----welcome to the world of black box-----"<<endl; cout<<"-------------------------------------------"<<endl; char cContinue = 'n'; //初始化牌库 CPokerDesk pdPoker; do { pdPoker.Reset(); //自己主动洗牌 pdPoker.Shuffle(); //发牌 pdPoker.Deal(); pdPoker.ShowPokerDesk(); //抢地主 pdPoker.RobLord(); pdPoker.ShowPokerDesk(); while(pdPoker.GetGameState() == gsContinue) { //出牌 pdPoker.Discard(); pdPoker.ShowPokerDesk(); } cout<<"----------game over-----------"<<endl; cout<<"Left:"<<pdPoker.m_players[piLeft].m_nPoint; cout<<",Middle:"<<pdPoker.m_players[piMiddle].m_nPoint; cout<<",Right:"<<pdPoker.m_players[piRight].m_nPoint<<endl; //又一次開始或退出 cout<<"Do you want to continue(y,n)?初始化之后能够反复玩,统计积分。"<<endl; cin>>cContinue; } while (cContinue == 'Y' || cContinue == 'y'); return 1; }
接下来是牌桌的类。用到了boost库的format来控制string的格式。
头文件:
#pragma once #include "Card.h" #include "Player.h" #include <vector> #include <set> using namespace std; enum enPlayerId { piLeft, piMiddle, piRight }; enum enGameState { gsContinue, gsLordLose, gsLordWin }; class CPokerDesk { private: //上一手 enPlayerId m_piLastDiscard; //出牌人 enPlayerId m_piDiscard; //地主 enPlayerId m_piLord; //游戏状态 enGameState m_gsState; //该次分值 int m_nPoint; public: vector<CCard> m_lastCards; //玩家 vector <CPlayer> m_players; //牌库 vector<CCard> m_cards; //地主牌 vector<CCard> m_lordcards; CPokerDesk(void); ~CPokerDesk(void); void Reset(); void Shuffle(); void Deal(); bool Discard(); enGameState GetGameState(); void SetGameState(enGameState gsState); enPlayerId GetDiscardId(); void SetDiscardId(enPlayerId piTurn); void ShowPokerDesk(); void RobLord(); };
实现文件:
#include "PokerDesk.h" #include <iostream> #include <boost/format.hpp> using namespace boost; CPokerDesk::CPokerDesk(void) { for(int i = 0; i < 54; i++) { CCard a((enCardName)i); m_cards.push_back(a); } CPlayer p1("Left",true),p2("Middle",false),p3("Right",true); m_players.push_back(p1); m_players.push_back(p2); m_players.push_back(p3); srand(time(NULL)); enPlayerId pi = enPlayerId(rand()%3); m_piDiscard = m_piLastDiscard = m_piLord = pi; m_gsState = gsContinue; } CPokerDesk::~CPokerDesk(void) { } void CPokerDesk::Reset() { m_lordcards.clear(); m_lastCards.clear(); for(int i = 0; i < 3; i++) m_players[i].m_handcards.clear(); m_gsState = gsContinue; } void CPokerDesk::Shuffle() { srand(time(NULL)); /*srand(28);*/ random_shuffle(m_cards.begin(),m_cards.end()); } void CPokerDesk::Deal() { for(int i = 0; i < m_cards.size()/3-1; i++) { for(int j = 0; j < 3; j++) { m_players[j].m_handcards.push_back(m_cards[i*3+j]); } } for(int i = 0; i < 3; i++) sort(m_players[i].m_handcards.begin(),m_players[i].m_handcards.end()); for(int i = 0; i < 3; i++) m_lordcards.push_back(m_cards[m_cards.size()-i-1]); } bool CPokerDesk::Discard() { vector<CCard> cards; if(m_piDiscard == m_piLastDiscard) { // vector<CCard> cardnull; do { m_players[m_piDiscard].Discard(cardnull,cards); } while (cards.empty()); m_lastCards.assign(cards.begin(),cards.end()); if(m_players[m_piDiscard].m_handcards.empty()) { if(m_piDiscard == m_piLord) { m_gsState = gsLordWin; for(int i = 0; i < 3; i++) { if(i == m_piLord) { m_players[i].m_nPoint += 2*m_nPoint; } else { m_players[i].m_nPoint -= m_nPoint; } } } else { m_gsState = gsLordLose; for(int i = 0; i < 3; i++) { if(i == m_piLord) { m_players[i].m_nPoint -= 2*m_nPoint; } else { m_players[i].m_nPoint += m_nPoint; } } } } m_piLastDiscard = m_piDiscard; m_piDiscard = enPlayerId((m_piDiscard+1)%3); return true; } m_players[m_piDiscard].Discard(m_lastCards,cards); if(!cards.empty()) { m_lastCards.assign(cards.begin(),cards.end()); if(m_players[m_piDiscard].m_handcards.empty()) { if(m_piDiscard == m_piLord) { m_gsState = gsLordWin; for(int i = 0; i < 3; i++) { if(i == m_piLord) { m_players[i].m_nPoint += 2*m_nPoint; } else { m_players[i].m_nPoint -= m_nPoint; } } } else { m_gsState = gsLordLose; for(int i = 0; i < 3; i++) { if(i == m_piLord) { m_players[i].m_nPoint -= 2*m_nPoint; } else { m_players[i].m_nPoint += m_nPoint; } } } } m_piLastDiscard = m_piDiscard; } //下家 m_piDiscard = enPlayerId((m_piDiscard+1)%3); return true; } enGameState CPokerDesk::GetGameState() { return m_gsState; } void CPokerDesk::SetGameState(enGameState gsState) { m_gsState = gsState; } enPlayerId CPokerDesk::GetDiscardId() { return m_piDiscard; } void CPokerDesk::SetDiscardId(enPlayerId piTurn) { m_piDiscard = piTurn; } void CPokerDesk::ShowPokerDesk() { format fmt("%c%c %s %c%c"); format fmtm("| %2d |"); const string strHor = "--------------------"; const string strVer = "| |"; std::cout<<"-----------begin of the scene-------------"<<std::endl; std::cout<<" "; for(int i = 0; i < m_lordcards.size(); i++) std::cout<<m_lordcards[i].m_cCard; std::cout<<" "<<std::endl; for(int i = 0; i < 10; i++) { char c1,c2,c3,c4; if(2*i < m_players[0].m_handcards.size()) c1 = m_players[0].m_handcards[2*i].m_cCard; else c1 = ' '; if(2*i+1 < m_players[0].m_handcards.size()) c2 = m_players[0].m_handcards[2*i+1].m_cCard; else c2 = ' '; if(2*i < m_players[2].m_handcards.size()) c3 = m_players[2].m_handcards[2*i].m_cCard; else c3 = ' '; if(2*i+1 < m_players[2].m_handcards.size()) c4 = m_players[2].m_handcards[2*i+1].m_cCard; else c4 = ' '; string strDesk; if(i == 0 || i == 9)//最上和最下 { strDesk = strHor; } else if (i == 4 || i == 5) { strDesk = strVer; if(m_lastCards.size() <= 10) { if (i == 4) { int nBegin = (strVer.size() - m_lastCards.size())/2; for(int j = nBegin; j < nBegin+m_lastCards.size(); j++) strDesk[j] = m_lastCards[j-nBegin].m_cCard; } } else { if (i == 4) { int nBegin = (strVer.size() - 10)/2; for(int j = nBegin; j < nBegin+10; j++) strDesk[j] = m_lastCards[j-nBegin].m_cCard; } else { int nBegin = (strVer.size() - 10)/2; for(int j = nBegin; j < nBegin+m_lastCards.size()-10; j++) strDesk[j] = m_lastCards[j-nBegin+10].m_cCard; } } } else { strDesk = strVer; } std::cout<<fmt % c1 % c2 % strDesk % c3 % c4<<std::endl; } //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % (fmtm % m_cards.size()) % c % c<<std::endl; //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % strVer % c % c<<std::endl; //std::cout<<fmt % c % c % strHor % c % c<<std::endl; std::cout<<" "; for(int i = 0; i < 20; i++) { if(i < m_players[1].m_handcards.size()) std::cout<<m_players[1].m_handcards[i].m_cCard; else std::cout<<' '; } std::cout<<" "<<std::endl; std::cout<<"------------end of the scene--------------"<<std::endl; /*m_cards.size(); std::cout<<"33 -------------------- 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 | | 33"<<std::endl; std::cout<<"33 -------------------- 33"<<std::endl; std::cout<<" 33333333333333333333 "<<std::endl;*/ } //找下一个 enPlayerId FindNextPlayerId(vector<enPlayerId>& piUsers,enPlayerId pi) { for(vector<enPlayerId>::iterator it = piUsers.begin(); it != piUsers.end(); ++it) { if(*it == pi) { if(++it != piUsers.end()) { return *it; } else return piUsers[0]; } } return pi; } //移除一个 void RemovePlayerId(vector<enPlayerId>& piUsers,enPlayerId pi) { for(vector<enPlayerId>::iterator it = piUsers.begin(); it != piUsers.end(); ++it) { piUsers.erase(it); break; } } void CPokerDesk::RobLord() { m_nPoint = 1; vector<enPlayerId> piUsers; piUsers.push_back(piLeft); piUsers.push_back(piMiddle); piUsers.push_back(piRight); enPlayerId piNow,piNext; piNow = piNext = m_piDiscard; for(int i = 0; i < 5&&piUsers.size() > 1; i++) { piNow = piNext; if(m_players[piNow].RobLord()) { m_piDiscard = m_piLastDiscard = m_piLord = piNow; m_nPoint = m_nPoint<<1; piNext=FindNextPlayerId(piUsers,piNext); } else { i--; piNext=FindNextPlayerId(piUsers,piNext); RemovePlayerId(piUsers,piNow); } cout<<"now the point is "<<m_nPoint<<endl; } for(int i = 0; i < m_lordcards.size(); i++) m_players[m_piLord].m_handcards.push_back(m_lordcards[i]); sort(m_players[m_piLord].m_handcards.begin(),m_players[m_piLord].m_handcards.end()); }写完这个还要加上玩家。我设计的是两个机器人和一个玩家
头文件:
#pragma once #include "Card.h" #include <vector> using namespace std; enum{nInitPoint=1000}; class CPlayer { public: string m_strPlayerName; bool m_bAI; int m_nPoint; vector <CCard> m_handcards; CPlayer(string strName,bool bAI); CPlayer(void); ~CPlayer(void); void Discard(vector<CCard>& cardSet,vector<CCard>& cardResSet); void CreateCards(vector<CCard>& cardSet,vector<CCard>& cardResSet); bool RemovePart(vector<CCard>& cardSet); bool RobLord(); void CardTips(vector<CCard>& cardSet,vector<CCard>& cardResSet); };实现文件:
#include "Player.h" #include "CardSet.h" #include <iostream> #include <string> #include <time.h> CPlayer::CPlayer(void) { m_bAI = false; m_nPoint = nInitPoint; m_strPlayerName = "NoName"; } CPlayer::CPlayer(string strName,bool bAI) { m_bAI = bAI; m_strPlayerName = strName; m_nPoint = nInitPoint; } CPlayer::~CPlayer(void) { } //出牌推断 void CPlayer::Discard(vector<CCard>& cardSet,vector<CCard>& cardResSet) { //须要大于 CreateCards(cardSet,cardResSet); if(cardResSet.empty()) return; //输入 CCardSet csLastCards(cardSet); CCardSet csMyCards(cardResSet); while(! (csLastCards < csMyCards&&RemovePart(cardResSet))) { CreateCards(cardSet,cardResSet); if(cardResSet.empty()) return; csMyCards = CCardSet(cardResSet); } } void CPlayer::CreateCards(vector<CCard>& cardSet,vector<CCard>& cardResSet) { if (m_bAI) { CCardSet csCards(cardSet),csCardsRes; do { cout<<"AI testing"<<endl; CardTips(cardSet,cardResSet); csCardsRes = CCardSet(cardResSet); }while(!(csCards < csCardsRes || cardResSet.empty())); } else { CCardSet csCards(cardSet),csCardsRes; do { std::cout<<"please input cards you want to deal"<<std::endl; string strCards; std::cin>>strCards; //remove invalid char cardResSet.clear(); if(strCards.find('P')!= string::npos) { csCardsRes.m_cards.clear(); csCardsRes.m_ctCardType = ctInvalid; continue; } //将字符串改为向量 for(int i = 0; i < strCards.size(); i++) { CCard card(strCards[i]); cardResSet.push_back(card); } csCardsRes = CCardSet(cardResSet); }while(!(csCards < csCardsRes || cardResSet.empty())); } } //将已出的部分从手牌中删除 bool CPlayer::RemovePart(vector<CCard>& cardSet) { vector<CCard> dmCardSet; dmCardSet.assign(m_handcards.begin(),m_handcards.end()); for(vector<CCard>::iterator itc = cardSet.begin(); itc != cardSet.end(); ++itc) { bool bFind = false; for(vector<CCard>::iterator it = dmCardSet.begin(); it != dmCardSet.end(); ++it) { if(*it==*itc) { bFind = true; dmCardSet.erase(it); break; } } if(!bFind) { std::cout<<"error poker!"<<std::endl; return false; } } swap(m_handcards,dmCardSet); return true; } bool CPlayer::RobLord() { if(m_bAI) { srand(time(NULL)); int nRob = rand()%2; if(nRob) { cout<<m_strPlayerName<<" rob the lord"<<endl; return true; } else { cout<<m_strPlayerName<<" give up the lord"<<endl; return false; } } else { cout<<"Do you want to rob the lord(y,n)?"<<endl; char c; cin>>c; if(c == 'y'||c=='Y') { cout<<m_strPlayerName<<" rob the lord"<<endl; return true; } else { cout<<m_strPlayerName<<" give up the lord"<<endl; return false; } } } void CPlayer::CardTips(vector<CCard>& cardSet,vector<CCard>& cardResSet) { cardResSet.clear(); if(cardSet.empty()) { //double line //line //triple CCardSet csHandCard(m_handcards); if(CCardSet::FindLeastCards(csHandCard.m_mapcards,3,cardResSet)) { csHandCard.m_mapcards.erase(csHandCard.m_mapcards.find(cardResSet[0])); //double if(CCardSet::FindLeastCards(csHandCard.m_mapcards,2,cardResSet)) { return; } //single if(CCardSet::FindLeastCards(csHandCard.m_mapcards,1,cardResSet)) { return; } return; } //double if(CCardSet::FindLeastCards(csHandCard.m_mapcards,2,cardResSet)) { return; } //single if(CCardSet::FindLeastCards(csHandCard.m_mapcards,1,cardResSet)) { return; } cardResSet.push_back(m_handcards[0]); } else { CCardSet csCard(cardSet); CCardSet csHandCard(m_handcards); CCardSet csResCard; if(!csHandCard.FindBigger(csCard,csResCard)&&csCard.m_ctCardType!=ctBoom&&csCard.m_ctCardType!=ctRooket) { if(!csHandCard.FindBoom(csResCard)) csHandCard.FindRooket(csResCard); } swap(cardResSet,csResCard.m_cards); } }
对于每张牌。我定义了一个类进行管理,主要是控制显示和牌的值
头文件:
#pragma once enum enCardName { cnBlk3, cnRed3, cnFlr3, cnRct3, cnBlk4, cnRed4, cnFlr4, cnRct4, cnBlk5, cnRed5, cnFlr5, cnRct5, cnBlk6, cnRed6, cnFlr6, cnRct6, cnBlk7, cnRed7, cnFlr7, cnRct7, cnBlk8, cnRed8, cnFlr8, cnRct8, cnBlk9, cnRed9, cnFlr9, cnRct9, cnBlk10, cnRed10, cnFlr10, cnRct10, cnBlkJ, cnRedJ, cnFlrJ, cnRctJ, cnBlkQ, cnRedQ, cnFlrQ, cnRctQ, cnBlkK, cnRedK, cnFlrK, cnRctK, cnBlkA, cnRedA, cnFlrA, cnRctA, cnBlk2, cnRed2, cnFlr2, cnRct2, cnjoker, cnJoker, cnNull }; class CCard { private: enCardName m_cnCardId; public: char m_cCard; CCard(enCardName cnId); CCard(char cCard); CCard(void); ~CCard(void); bool operator<(const CCard& card)const; bool operator==(const CCard& card)const; bool IsNext(CCard card); };
实现文件:
#include "Card.h" CCard::CCard() { m_cnCardId = cnNull; m_cCard = '