上一篇文章对玩家手中的牌进行分析归类,下面就该实现电脑玩家出牌与跟牌的策略了。首先我们来看看出牌的策略,代码如下:
void GameScene::update(float delta){
switch (m_iState)
{
case 0:
SendPk();
break;
case 1:
schedule(schedule_selector(GameScene::Call),1);
break;
case 2:
scheduleOnce(schedule_selector(GameScene::OutCard),0.5);
break;
case 3:
IsShengLi();
break;
default:
break;
}
}
首先解释下该函数,本函数为一个循环,每帧被调用一次。我们看一下头文件里m_iState的注释:
int m_iState;//当前状态 ,0:发牌状态 1:叫地主状态 2:出牌状态 3:结果状态
很明显,出牌和跟牌策略就在状态2,该函数延时0.5秒出牌。我们接下来看下OutCard函数的策略:
void GameScene::OutCard(float delta){
switch (m_iOutCard%3)
{
case 0:
m_chuPaiMenu->setVisible(true);//显示出牌菜单,包括”不出“,”出牌“
m_typeTem = PaiDuanPaiXing();//获得玩家出的牌的牌型,这个函数在cocos2dx《单机斗地主》源码解剖之六 玩家(人)的出牌中有解释。
if(!m_npcOne->getIsOutPk() && !m_npcTwo->getIsOutPk())//如果两个电脑玩家没出过牌,设”不出“按钮不可点,反应则然。
((CCMenuItemFont *)m_chuPaiMenu->getChildByTag(0))->setEnabled(false);
else
((CCMenuItemFont *)m_chuPaiMenu->getChildByTag(0))->setEnabled(true);
//出牌
if(!m_npcOne->getIsOutPk() && !m_npcTwo->getIsOutPk())
{
//清除所有出的牌
ClearOutPk();//下面贴代码
if (m_typeTem != ERROR_CARD)//ERROR_CARD为错误的牌型
((CCMenuItemFont *)m_chuPaiMenu->getChildByTag(1))->setEnabled(true);
else
((CCMenuItemFont *)m_chuPaiMenu->getChildByTag(1))->setEnabled(false);
}
else //跟牌
{
if(m_arrPlayerOut->count() != 0)
{
Poker* pk = (Poker*)m_arrGenPk->objectAtIndex(0);//要跟的牌
Poker* pk1 = (Poker*)m_arrPlayerOut->objectAtIndex(0);//玩家出的牌
if(m_typeTem == m_type && pk1->getNum()>pk->getNum() || (m_typeTem==BOMB_CARD && m_type!=BOMB_CARD))//m_type为跟的牌的牌型
((CCMenuItemFont *)m_chuPaiMenu->getChildByTag(1))->setEnabled(true);
else
((CCMenuItemFont *)m_chuPaiMenu->getChildByTag(1))->setEnabled(false);
}
else
((CCMenuItemFont *)m_chuPaiMenu->getChildByTag(1))->setEnabled(false);
}
break;
case 1:
m_chuPaiMenu->setVisible(false);
if(!m_player->getIsOutPk() && !m_npcOne->getIsOutPk())
{
//清除所有出的牌
ClearOutPk();
NpcOutPoker(m_npcTwo,m_arrGenPk,m_npcTwoOut);//电脑出牌策略,函数下面解释。
}
else
NpcGenPoker(m_npcTwo,m_arrGenPk ,m_npcTwoOut);//电脑跟牌策略,函数下面解释。
PlayerOutPaiXu(m_arrGenPk);//对要跟的牌进行排序,该函数在cocos2dx《单机斗地主》源码解剖之六 玩家(人)的出牌有解释。
PlayerOutPaiXu(m_npcTwoOut->getArrPk());//对电脑玩家出的牌进行排序
m_npcTwoOut->updatePkWeiZhi();//更新位置
m_npcTwo->updatePkWeiZhi();//同上
++m_iOutCard;
if(IsOutPkFinish())//判断游戏是否结束,下面解释。
m_iState = 3;
break;
case 2:
if(!m_player->getIsOutPk() && !m_npcTwo->getIsOutPk())
{
//清除所有出的牌
ClearOutPk();
NpcOutPoker(m_npcOne,m_arrGenPk,m_npcOneOut);
}
else
NpcGenPoker(m_npcOne,m_arrGenPk,m_npcOneOut);
PlayerOutPaiXu(m_arrGenPk);
PlayerOutPaiXu(m_npcTwoOut->getArrPk());
m_npcOneOut->updatePkWeiZhi();
m_npcOne->updatePkWeiZhi();
++m_iOutCard;
if(IsOutPkFinish())
m_iState = 3;
break;
default:
break;
}
}在上面代码中你一定发现了有些令人费解的函数(ClearOutPk(),NpcOutPoker(m_npcTwo,m_arrGenPk,m_npcTwoOut),NpcGenPoker(m_npcTwo,m_arrGenPk ,m_npcTwoOut),IsOutPkFinish()),下面一一解释:
ClearOutPk()的代码:
void GameScene::ClearOutPk()
{
CCObject* object;//清除玩家出的牌
CCARRAY_FOREACH(m_playerOut->getArrPk(),object){
Poker* pk = (Poker*)object;
pk->setVisible(false);
}
m_playerOut->getArrPk()->removeAllObjects();//清除电脑玩家出的牌
CCARRAY_FOREACH(m_npcTwoOut->getArrPk(),object){
Poker* pk = (Poker*)object;
pk->setVisible(false);
}
m_npcTwoOut->getArrPk()->removeAllObjects();//同上
CCARRAY_FOREACH(m_npcOneOut->getArrPk(),object){
Poker* pk = (Poker*)object;
pk->setVisible(false);
}
m_npcOneOut->getArrPk()->removeAllObjects();
this->getChildByTag(NpcOneBuChu)->setVisible(false);
this->getChildByTag(NpcTwoBuChu)->setVisible(false);
}NpcOutPoker(m_npcTwo,m_arrGenPk,m_npcTwoOut) 电脑出牌策略:
电脑出牌策略我这里只是简单的判断,打出排在第一位置牌值最小的牌型。
void GameScene::NpcOutPoker(Player* npc,CCArray* out,Player* out1){
//隐藏上一次出的牌
CCObject* object;
CCARRAY_FOREACH(out1->getArrPk(),object){ //out1为上一次出的牌
Poker* pk = (Poker*)object;
pk->setVisible(false);
}
out1->getArrPk()->removeAllObjects();
//打出牌值最小的一个牌型,也就是排在第一位置的牌型
PaiXing px = npc->m_vecPX.front();
out->removeAllObjects();
//三条出牌原则
if(px.type == THREE_CARD){
stable_sort(npc->m_vecPX.begin(),npc->m_vecPX.end(),isShorter1);
m_type = THREE_CARD;
//带单
for(std::vector<PaiXing>::iterator iter=npc->m_vecPX.begin();iter!=npc->m_vecPX.end();++iter)
{
//除非只剩两手牌,否则不能带王和2
Poker* pk = iter->vec.front();
if(pk->getNum() >= Er && npc->m_vecPX.size() != 1)
break;
if(iter->type == SINGLE_CARD)
{
out1->getArrPk()->addObject(iter->vec.front());
out->addObject(iter->vec.front());
npc->getArrPk()->removeObject(iter->vec.front());
npc->m_vecPX.erase(iter);
m_type = THREE_ONE_CARD;
break;
}
}
//带双
if(out1->getArrPk()->count() == 0)
{
for(std::vector<PaiXing>::iterator iter=npc->m_vecPX.begin();iter!=npc->m_vecPX.end();++iter)
{
//除非只剩两手牌,否则不能带王和2
Poker* pk = iter->vec.front();
if(pk->getNum() >= Er && npc->m_vecPX.size() != 1)
break;
if(iter->type == DOUBLE_CARD)
{
for(std::vector<Poker*>::iterator it=iter->vec.begin();it!=iter->vec.end();++it)
{
out1->getArrPk()->addObject(*it);
out->addObject(*it);
npc->getArrPk()->removeObject(*it);
}
npc->m_vecPX.erase(iter);
m_type = THREE_TWO_CARD;
break;
}
}
}
}
//三顺出牌原则
if(px.type == AIRCRAFT_CARD){
//有足够的单就带单
stable_sort(npc->m_vecPX.begin(),npc->m_vecPX.end(),isShorter1);
m_type = AIRCRAFT_CARD;
if(GetNpcPxNum(npc,SINGLE_CARD) >= px.vec.size()/3)
{
int num=0;
for (std::vector<PaiXing>::iterator it=npc->m_vecPX.begin(); it!=npc->m_vecPX.end()&&num<px.vec.size()/3;)
{
if(it->type == SINGLE_CARD)
{
++num;
out1->getArrPk()->addObject(it->vec.front());
out->addObject(it->vec.front());
npc->getArrPk()->removeObject(it->vec.front());
it = npc->m_vecPX.erase(it);
m_type = AIRCRAFT_SINGLE_CARD;
}
else
++it;
}
}
//有足够的双就带双
if(GetNpcPxNum(npc,DOUBLE_CARD) >= px.vec.size()/3 && out1->getArrPk()->count() == 0)
{
int num=0;
for (std::vector<PaiXing>::iterator it=npc->m_vecPX.begin(); it!=npc->m_vecPX.end()&&num<px.vec.size()/3;)
{
if(it->type == DOUBLE_CARD)
{
++num;
for(std::vector<Poker*>::iterator ite=it->vec.begin(); ite!=it->vec.end(); ++ite)
{
out1->getArrPk()->addObject(*ite);
out->addObject(*ite);
npc->getArrPk()->removeObject(*ite);
m_type = AIRCRAFT_DOBULE_CARD;
}
it = npc->m_vecPX.erase(it);
}
else
++it;
}
}
}
//连牌出牌原则,直接出,不做处理
if(px.type == CONNECT_CARD){
m_type = CONNECT_CARD;
}
//双顺出牌原则,直接出,不做处理
if(px.type == COMPANY_CARD){
m_type = COMPANY_CARD;
}
//对子和单子出牌原则
if(px.type == DOUBLE_CARD || px.type == SINGLE_CARD){
int threeNum = GetNpcPxNum(npc,THREE_CARD)+GetNpcPxNum(npc,AIRCRAFT_CARD);
int chiBangNum = GetNpcPxNum(npc,DOUBLE_CARD)+GetNpcPxNum(npc,SINGLE_CARD);
//所有三条<=所有对子+所有单牌-2,出对子,否则出三带对
if(threeNum <= chiBangNum-2 || threeNum == 0)
{
if(px.type == DOUBLE_CARD)
m_type = DOUBLE_CARD;
if(px.type == SINGLE_CARD)
m_type = SINGLE_CARD;
}
else
{
PaiXing px = npc->m_vecPX.front();
std::vector<PaiXing>::iterator dle = npc->m_vecPX.begin();
npc->m_vecPX.erase(dle);
npc->m_vecPX.push_back(px);
NpcOutPoker(npc,out,out1);
return;
}
}
for(std::vector<Poker*>::iterator iter=px.vec.begin(); iter!=px.vec.end(); ++iter)
{
out1->getArrPk()->addObject(*iter);
out->addObject(*iter);
npc->getArrPk()->removeObject(*iter);
npc->setIsOutPk(true);
}
m_lastOut = npc;
//从npc->m_vecPX中移除px
for(std::vector<PaiXing>::iterator it=npc->m_vecPX.begin();it!=npc->m_vecPX.end();++it)
{
if(it->type == px.type && it->vec.front()->getNum() == px.vec.front()->getNum())
{
npc->m_vecPX.erase(it);
break;
}
}
}
void GameScene::NpcGenPoker(Player* npc,CCArray* out ,Player* out1){
//隐藏上一次出的牌
if(m_isChiBang)
{
CCObject* object;
CCARRAY_FOREACH(out1->getArrPk(),object){
Poker* pk = (Poker*)object;
pk->setVisible(false);
}
out1->getArrPk()->removeAllObjects();
}
/************************************************************************/
/*找出对应牌型出牌 */
/************************************************************************/
for (std::vector<PaiXing>::iterator iter=npc->m_vecPX.begin(); iter!=npc->m_vecPX.end(); ++iter)
{
if(m_type == iter->type)
{
//对飞机、连牌进行判断
if(m_type == AIRCRAFT_CARD || m_type == CONNECT_CARD || m_type == COMPANY_CARD)
if(out->count() != iter->vec.size())
continue;
Poker* pk = (Poker*)out->objectAtIndex(out->count()-1);
Poker* pk1 = iter->vec.front();
//如果对方是自己人大于2的牌不出
if(!npc->getIsDiZhu() && !m_lastOut->getIsDiZhu())
{
if(pk1->getNum()>=Er || m_type == BOMB_CARD)
{
//pass
if(npc == m_npcOne)
this->getChildByTag(NpcOneBuChu)->setVisible(true);
if(npc == m_npcTwo)
this->getChildByTag(NpcTwoBuChu)->setVisible(true);
npc->setIsOutPk(false);
return;
}
}
if(pk1->getNum() > pk->getNum())
{
out->removeAllObjects();
for(std::vector<Poker*>::iterator it = iter->vec.begin(); it!=iter->vec.end(); ++it){
out1->getArrPk()->addObject(*it);
npc->getArrPk()->removeObject(*it);
out->addObject(*it);
}
npc->m_vecPX.erase(iter);
npc->setIsOutPk(true);
m_lastOut = npc;
return;
}
}
}
//三带一或三带二
if(SanDaiYiOrEr(npc,out,out1))
return;
//四带单或四带双
//飞机带单或带双
if(FeiJiDaiChiBang(npc,out,out1))
return;
/************************************************************************/
/*如果除炸弹还剩一手牌 */
/************************************************************************/
if(npc->m_vecPX.size() == 2)
{
for (std::vector<PaiXing>::iterator iter=npc->m_vecPX.begin(); iter!=npc->m_vecPX.end(); ++iter)
{
if(iter->type == BOMB_CARD && m_type != BOMB_CARD)
{
out->removeAllObjects();
for(std::vector<Poker*>::iterator it = iter->vec.begin(); it!=iter->vec.end(); ++it){
out1->getArrPk()->addObject(*it);
npc->getArrPk()->removeObject(*it);
out->addObject(*it);
}
npc->m_vecPX.erase(iter);
m_lastOut = npc;
return;
}
}
}
/************************************************************************/
/* 如果出牌方是自己人不拆牌跟 */
/************************************************************************/
if(!npc->getIsDiZhu() && !m_lastOut->getIsDiZhu())
{
//pass
if(npc == m_npcOne)
this->getChildByTag(NpcOneBuChu)->setVisible(true);
if(npc == m_npcTwo)
this->getChildByTag(NpcTwoBuChu)->setVisible(true);
npc->setIsOutPk(false);
return;
}
/************************************************************************/
/*拆单张牌跟之 */
/************************************************************************/
if(NpcChaiDan(npc,out,out1))
return;
/************************************************************************/
/*拆双牌跟之 */
/************************************************************************/
if(NpcChaiDui(npc,out,out1))
return;
/************************************************************************/
/*拆三张牌跟之 */
/************************************************************************/
if(NpcChaiSan(npc,out,out1))
return;
/************************************************************************/
/*拆飞机牌跟之 */
/************************************************************************/
if(NpcChaiFeiJi(npc,out,out1))
return;
/************************************************************************/
/*拆连牌跟之 */
/************************************************************************/
if(NpcChaiLianPai(npc,out,out1))
return;
/************************************************************************/
/*拆双顺跟之 */
/************************************************************************/
if(NpcChaiShuangShun(npc,out,out1))
return;
//炸之
for (std::vector<PaiXing>::iterator iter=npc->m_vecPX.begin(); iter!=npc->m_vecPX.end(); ++iter)
{
if(iter->type == BOMB_CARD)
{
//如果出牌方出的不是炸弹就炸之,否则比较大小炸之
if(m_type != BOMB_CARD)
{
out->removeAllObjects();
for(std::vector<Poker*>::iterator it = iter->vec.begin(); it!=iter->vec.end(); ++it){
out1->getArrPk()->addObject(*it);
npc->getArrPk()->removeObject(*it);
out->addObject(*it);
}
npc->m_vecPX.erase(iter);
m_type = BOMB_CARD;
npc->setIsOutPk(true);
m_lastOut = npc;
return;
}else
{
Poker* pk = (Poker*)out->objectAtIndex(0);
Poker* pk1 = iter->vec.front();
if(pk1->getNum()>pk->getNum())
{
out->removeAllObjects();
for(std::vector<Poker*>::iterator it = iter->vec.begin(); it!=iter->vec.end(); ++it){
out1->getArrPk()->addObject(*it);
npc->getArrPk()->removeObject(*it);
out->addObject(*it);
}
npc->m_vecPX.erase(iter);
m_type = BOMB_CARD;
npc->setIsOutPk(true);
m_lastOut = npc;
return;
}
}
}
}
//pass
if(npc == m_npcOne)
{
this->getChildByTag(NpcOneBuChu)->setVisible(true);
}
if(npc == m_npcTwo)
{
this->getChildByTag(NpcTwoBuChu)->setVisible(true);
}
npc->setIsOutPk(false);
}cocos2dx《单机斗地主》源码解剖之八 电脑玩家出牌与跟牌(结束)
原文:http://blog.csdn.net/oiy37215/article/details/44036405