cocos2dx《单机斗地主》源码解剖之八 电脑玩家出牌与跟牌(结束)

cocos2dx《单机斗地主》源码解剖之八 电脑玩家出牌与跟牌(结束),第1张

概述上一篇文章对玩家手中的牌进行分析归类,下面就该实现电脑玩家出牌与跟牌的策略了。首先我们来看看出牌的策略,代码如下: void GameScene::update(float delta){ switch (m_iState) { case 0: SendPk(); break; case 1:

上一篇文章对玩家手中的牌进行分析归类,下面就该实现电脑玩家出牌与跟牌的策略了。首先我们来看看出牌的策略,代码如下:

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_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_npcOneOut);            }            else                NpcGenPoker(m_npcOne,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;    }}

首先介绍一下这个状态机,我们看头文件对m_IoUtCard变量的定义:int m_IoUtCard;//论到谁出牌,0为玩家出牌与跟牌的策略,1和2为电脑玩家出牌与跟牌的策略。他们的意义已在代码里添加注释。

在上面代码中你一定发现了有些令人费解的函数(ClearOutPk(),NpcOutPoker(m_npcTwo,m_npcTwoOut),NpcGenPoker(m_npcTwo,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_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(),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;        }    }}

NpcGenPoker(m_npcTwo,m_npcTwoOut),IsOutPkFinish())跟牌策略:
voID GameScene::NpcGenPoker(Player* npc,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,out1))        return;    //四带单或四带双    //飞机带单或带双    if(FeiJIDaiChiBang(npc,out1))        return;    /************************************************************************/    /*如果除炸d还剩一手牌                                                  */    /************************************************************************/    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,out1))        return;    /************************************************************************/    /*拆双牌跟之                                                        */    /************************************************************************/    if(NpcChaIDui(npc,out1))        return;    /************************************************************************/    /*拆三张牌跟之                                                        */    /************************************************************************/    if(NpcChaiSan(npc,out1))        return;    /************************************************************************/    /*拆飞机牌跟之                                                        */    /************************************************************************/    if(NpcChaifeiJi(npc,out1))        return;    /************************************************************************/    /*拆连牌跟之                                                        */    /************************************************************************/    if(NpcChailianPai(npc,out1))        return;    /************************************************************************/    /*拆双顺跟之                                                        */    /************************************************************************/    if(NpcChaiShuangShun(npc,out1))        return;    //炸之    for (std::vector<PaiXing>::iterator iter=npc->m_vecPX.begin(); iter!=npc->m_vecPX.end(); ++iter)    {        if(iter->type == BOMB_CARD)        {            //如果出牌方出的不是炸d就炸之,否则比较大小炸之            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《单机斗地主》源码解剖之八 电脑玩家出牌与跟牌(结束)全部内容,希望文章能够帮你解决cocos2dx《单机斗地主》源码解剖之八 电脑玩家出牌与跟牌(结束)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1043852.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存