当游戏玩家选择好要出的牌以后,首先需要判断该牌型是否符合游戏规则,即合法。如果合法就高亮显示出“出牌”按钮,否则显示灰色“出牌”按钮,表示不可出。怎样判断玩家所选择的牌型是否合法呢?请看下面的代码:
int GameScene::PaiDuanPaiXing(){ //对出的牌进行排序 PlayerOutPaiXu(m_arrPlayerOut); //牌型判断 int lengh = m_arrPlayerOut->count(); PaiXing px; //牌的张数少于5张类型判断 单,对,三张,四张 if(lengh<5 && lengh>0){ Poker* pk = (Poker *)m_arrPlayerOut->objectAtIndex(0); Poker* pk1 = (Poker *)m_arrPlayerOut->objectAtIndex(lengh-1); if(pk->getNum() == pk1->getNum()) return lengh; //三带一 pk1 = (Poker *)m_arrPlayerOut->objectAtIndex(lengh-2); if(pk->getNum() == pk1->getNum() && lengh == 4) return THREE_ONE_CARD; //双鬼 if(pk->getHuaSe()==Gui && pk1->getHuaSe()==Gui) return BOMB_CARD; } //牌的张数大于等于5张的类型判断 if(lengh>=5) { //是否为连牌牌型(单) if(IsLianPai()) return CONNECT_CARD; if(IsLianDui()) //判断连对 return COMPANY_CARD; //判断飞机类型 return IsFeiJi(); } return ERROR_CARD; }
你一定注意到上面的PlayerOutPaiXu(m_arrPlayerOut);这个函数了,它的作用正是注释所说对出的牌进行排序,以方便分析它的牌型,m_arrPlayerOut是玩家选出的牌。先看以下代码:
void GameScene::PlayerOutPaiXu(CCArray* m_arrPlayerOut){ //对出的牌进行分离 std::vector<JiShu> vec;//JiShu是一个结构体,下面显示代码 while(m_arrPlayerOut->count() > 0) { JiShu js; js.arr = CCArray::create(); //取出第一个 Poker* pk = (Poker*)m_arrPlayerOut->objectAtIndex(0); m_arrPlayerOut->removeObjectAtIndex(0); js.num = 1; js.pkZhi = pk->getNum(); js.arr->addObject(pk); //找出与第一个相同的牌 int i=0; while (i<m_arrPlayerOut->count()) { Poker* pk1 = (Poker*)m_arrPlayerOut->objectAtIndex(i++); if(pk1->getNum() == pk->getNum()) { ++js.num; js.arr->addObject(pk1); m_arrPlayerOut->removeObject(pk1); --i; } } //把js存储起来用于排序 vec.push_back(js); } //对vec进行排序,按牌值从小到大排序 for(int i=0; i<vec.size()-1 && !vec.empty(); ++i){ for(int j=0; j<vec.size()-i-1; ++j){ if(vec[j].pkZhi > vec[j+1].pkZhi) { JiShu temp = vec[j]; vec[j] = vec[j+1]; vec[j+1] = temp; } } } stable_sort(vec.begin(),vec.end(),isShorter);//按牌的数量从小到大再排一次 //将排序好的牌重新放入m_playerOut中 for(std::vector<JiShu>::iterator it = vec.begin(); it!=vec.end(); ++it){ m_arrPlayerOut->addObjectsFromArray(it->arr); } }
//记数 排序出的牌用 struct JiShu { int pkZhi;//牌值 int num; //牌数量 CCArray* arr; //集合牌 };
上面综合思想是:判断出的牌“m_arrPlayerOut”里有几个相同的牌并通过JiShu结构体记录下来并保存在std::vector<JiShu> vec中,然后按他们牌值和相同牌的数量进行一次排序,然后再把排序好的牌一个一个放回m_arrPlayerOut中去,这样就会方便以后用来分析牌型了。打个比方:比如出的牌 66633,经过排序会变成33666, 665543经过排序变成345566.
那么上面代码中return BOMB_CARD; return THREE_ONE_CARD;是指什么呢,他们是一个枚举变量,分别代表一个牌型,请看下面代码:
//斗地主共有13种牌型 enum CARD_TYPE { SINGLE_CARD = 1, //单牌- DOUBLE_CARD, //对子- THREE_CARD, //3不带- BOMB_CARD, //炸弹 THREE_ONE_CARD, //3带1- THREE_TWO_CARD, //3带2- BOMB_TWO_CARD, //四个带2张单牌 BOMB_TWOOO_CARD, //四个带2对 CONNECT_CARD, //连牌- COMPANY_CARD, //连队- AIRCRAFT_CARD, //飞机不带- AIRCRAFT_SINGLE_CARD, //飞机带单牌- AIRCRAFT_DOBULE_CARD, //飞机带对子- ERROR_CARD //错误的牌型 } ;
下面分析//牌的张数大于等于5张的类型判断,原代码如下:
int GameScene::PaiDuanPaiXing(){ //对出的牌进行排序 PlayerOutPaiXu(m_arrPlayerOut); //牌型判断 int lengh = m_arrPlayerOut->count(); PaiXing px; //牌的张数少于5张类型判断 单,对,三张,四张 if(lengh<5 && lengh>0){ Poker* pk = (Poker *)m_arrPlayerOut->objectAtIndex(0); Poker* pk1 = (Poker *)m_arrPlayerOut->objectAtIndex(lengh-1); if(pk->getNum() == pk1->getNum()) return lengh; //三带一 pk1 = (Poker *)m_arrPlayerOut->objectAtIndex(lengh-2); if(pk->getNum() == pk1->getNum() && lengh == 4) return THREE_ONE_CARD; //双鬼 if(pk->getHuaSe()==Gui && pk1->getHuaSe()==Gui) return BOMB_CARD; } //牌的张数大于等于5张的类型判断 if(lengh>=5) { //是否为连牌牌型(单) if(IsLianPai()) return CONNECT_CARD; if(IsLianDui()) //判断连对 return COMPANY_CARD; //判断飞机类型 return IsFeiJi(); } return ERROR_CARD; }
首先看一下IsLianPai()这个代码,这个是判断是否为连牌,比如34567.下面贴上代码:
bool GameScene::IsLianPai(){ int lengh = m_arrPlayerOut->count(); CCArray * arr = m_arrPlayerOut; //所有牌值必须小于2 CCObject* object; CCARRAY_FOREACH(arr,object){ if (((Poker *)object)->getNum() >= 12)//12代表牌值2,下面解释为什么 return false; } //必须是连续的(前一张牌值加1是否等于后一张牌值) for(int i=0; i<lengh-1; ++i){ Poker* pk = (Poker *)arr->objectAtIndex(i); Poker* pk1 = (Poker *)arr->objectAtIndex(i+1); if(pk->getNum()+1 != pk1->getNum()) return false; } return true; }
大家一定会对上面的12数值感到疑惑,下面截个图来解释:
牌值我是从0开始设置的,比如3的牌值为0,4为1。
接下来放上判断是否是连对 IsLianDui() 代码:
bool GameScene::IsLianDui(){ int lengh = m_arrPlayerOut->count(); CCArray * arr = m_arrPlayerOut; //所有牌值必须小于2 CCObject* object; CCARRAY_FOREACH(arr,object){ if (((Poker *)object)->getNum() >= 12) return false; } //大于等于6张牌并且数量为偶数 if(lengh < 6 && lengh%2 != 0) return false; //必须是连续的 for(int i=0; i<lengh-2; i+=2){ Poker* pk = (Poker *)arr->objectAtIndex(i); Poker* pk1 = (Poker *)arr->objectAtIndex(i+2); if(pk->getNum()+1 != pk1->getNum()) return false; } return true; }
判断飞机类型 IsFeiJi()代码,函数名取的有点不合适,它返回的是一种飞机的类型,而不是bool值,所以很抱歉:
int GameScene::IsFeiJi(){ int lengh = m_arrPlayerOut->count(); CRAD_INDEX card_index = FenXiFeiJi();//分析牌是否是飞机,下面解释 //判断三带二 if(card_index.three_index.size()*3+card_index.duble_index.size()*2==lengh && card_index.three_index.size()==1 && card_index.duble_index.size()==1) return THREE_TWO_CARD; //判断飞机 if(card_index.three_index.size()>1 && card_index.four_index.empty() && IsFeiJiLian(card_index.three_index)){ //飞机不带 if(card_index.three_index.size()*3 == lengh && card_index.duble_index.size()+card_index.single_index.size() == 0) return AIRCRAFT_CARD; //飞机带单 if(card_index.three_index.size()*3+card_index.single_index.size() == lengh && card_index.duble_index.size() == 0) return AIRCRAFT_SINGLE_CARD; //飞机带双 if(card_index.three_index.size()*3+card_index.duble_index.size()*2 == lengh && card_index.single_index.size() == 0) return AIRCRAFT_DOBULE_CARD; } //判断四带 if(card_index.three_index.empty() && !card_index.four_index.empty() && lengh%2 == 0) { //四带单 if(card_index.four_index.size()*4+card_index.single_index.size() == lengh && card_index.four_index.size()==1 && card_index.single_index.size()==2) return BOMB_TWO_CARD; //四带对 if(card_index.four_index.size()*4+card_index.duble_index.size()*2 == lengh && card_index.four_index.size()==1 && card_index.duble_index.size()==1) return BOMB_TWOOO_CARD; } return ERROR_CARD; }
这里注意CRAD_INDEX card_index = FenXiFeiJi(); 这句代码。
CRAD_INDEX为一种结构体:
struct CRAD_INDEX//分析飞机 { std::vector<int> single_index;//单张 std::vector<int> duble_index;//双张 std::vector<int> three_index;//三张 std::vector<int> four_index;//四张 };
以上的结构体是为了对出的牌进行分类用,下面看看是如何对牌分类的,下面是FenXiFeiJi()的代码:
CRAD_INDEX GameScene::FenXiFeiJi(){ //分析牌型结构 CCArray* arr = m_arrPlayerOut; //飞机的类型 CRAD_INDEX m_cardIndex; for(int i=0; i<arr->count();) { int time = 0;//相同牌的个数 Poker* pk = (Poker *)arr->objectAtIndex(i); //找出相同牌 for(int j=i; j<arr->count(); ++j) { Poker* pk1 = (Poker *)arr->objectAtIndex(j); if(pk->getNum() == pk1->getNum()){ ++time; ++i; } } //单张 if(time == 1) nbsp; m_cardIndex.single_index.push_back(pk->getNum()); else if(time == 2) m_cardIndex.duble_index.push_back(pk->getNum()); else if(time == 3) m_cardIndex.three_index.push_back(pk->getNum()); else if(time == 4) m_cardIndex.four_index.push_back(pk->getNum()); } return m_cardIndex; }
本章至此结束,下面我们就可以判断玩家(人)出的牌是否合法了。