这几天比較空,所以想写一点东西。
斗地主的程序一直以来都想写,但感觉规则推断比較复杂,一直没有较多的时间来写。
这次主要是把跟牌和牌型的推断写出来了。写了一个比較弱智的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 = '