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

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

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;
    }
}

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

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

NpcGenPoker(m_npcTwo,m_arrGenPk ,m_npcTwoOut),IsOutPkFinish())跟牌策略:

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);
}

其中代码就不一一分析了,请自行到前三章下载源码阅读。本文章到此结束了!感谢大家的支持!!!

时间: 2024-10-06 00:45:05

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

cocos2d-x 之 CCArray 源码分析

cocos2d-x 自己实现了一个数组CCArray ,下面我们来分析一下CCArray的源码 CCArray继承CCObject,所以,CCArray也具有引用计数功能和内存自动管理功能. 数组的源码如下: class CC_DLL CCArray : public CCObject { public: /************************************************************************/ /* 构造析构函数 */ /*******

C# 网络斗地主源码开源

C# 网络斗地主源码开源多线程 讨论交流及  下载地址 可以发送聊天消息

Cocos2d-X手游源码/iOS/Android/cocos2dx源码/AppStore/手游资源“集中营”

郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源码下载:点我传送 游戏开发程序猿加班熬夜伤脑筋伤身体,花钱买技术,不如买游戏源代码. 节省开发周期和大量资金投入(工资.测试.学习),可以腾出大量时间精力和女友约会聊天,放松心情! 现在放出多套精品游戏cocos2d-x源代码. 大小游戏可以换皮上线!可学习 二次开发! 完整可编译,游戏体验安装包在网盘里放着,需要的看看. 店铺

Cocos2dx 3.6源码编译错误:syntax error : missing &#39;)&#39; before &#39;{&#39;

在编译Cocos2dx 3.6版本时,发现编译错误: 定位代码行: debugForNormalSprite->drawPoints(positions, 4, 8, Color4F{0.0,1.0,1.0,1.0}); 修改如下: debugForNormalSprite->drawPoints(positions, 4, 8, Color4F<span style="color:#ff0000;">(</span>0.0,1.0,1.0,1.0&

自己收集的十几个cocos2d-x的游戏源码

====================问题描述==================== 自己收集的十几个cocos2d-x的游戏源码,想要的留下邮箱,每天晚上发送! ====================解决方案1==================== 向楼主学习,谢谢,[email protected] ====================解决方案2==================== 楼主好人 [email protected] ====================解决方案

cocos2d-x 手游源码站

尊重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/37829061 1.魔幻方块 链接:魔幻方块源码 关键词:魔幻方块源码 源代码 Cocos2d-x2.0 游戏源码 益智 休闲 游戏 游戏类型:休闲益智 游戏使用引擎:Cocos2d-x V2.0 代码平台:Windows VS2012 版权说明:该游戏由本人开发,买家购买后可任意使用代码(但不能转卖.不能使用相关资源文件用于商业用途). 游戏版本:V

cocos2dx《单机斗地主》源码解剖之七 对电脑玩家手中的牌进行分拆

在电脑玩家跟牌和出牌之前首先对电脑玩家的牌进行拆分: 根据文档需求(见本博客"斗地主规则")拆分牌按以下顺序,先分析炸弹---飞机---连对---连牌--三带,对子,单张.请看如下代码: void GameScene::FenChaiNpcPai(Player* npc){ /************************************************************************/ /* 1.首先分析出来牌的类型(如:四张,三张,两张,一张) *

cocos2dx《单机斗地主》源码解剖之六 玩家(人)的出牌(2)

下面分析//牌的张数大于等于5张的类型判断,原代码如下: int GameScene::PaiDuanPaiXing(){ //对出的牌进行排序 PlayerOutPaiXu(m_arrPlayerOut); //牌型判断 int lengh = m_arrPlayerOut->count(); PaiXing px; //牌的张数少于5张类型判断 单,对,三张,四张 if(lengh<5 && lengh>0){ Poker* pk = (Poker *)m_arrPl

5 cocos2dx 3.0源码分析 渲染 render

渲染,感觉这个挺重要了,这里代入一个简单的例子 Sprite 建立及到最后的画在屏幕上, 我们描述一下这个渲染的流程: 1 sprite 初始化(纹理, 坐标,及当前元素的坐标大小信息) 2 主循环调用sprite的draw(), 把绘制命令发送到系统的render的渲染队列中. 3 Render拿到渲染队列中的渲染命令, 分别对每个命令进行处理, 我们这里的QUAD_COMMAND, 把这个命令中的坐标信息复制到自己的渲染缓冲中, 之后通过调用OpenGL命令对当前的矩形进行绘制. 1 Spr