cocos2dx《單機鬥地主》源碼解剖之八 電腦玩家出牌與跟牌(結束)

來源:互聯網
上載者:User

標籤:

上一篇文章對玩家手中的牌進行分析歸類,下面就該實現電腦玩家出牌與跟牌的策略了。首先我們來看看出牌的策略,代碼如下:

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

其中代碼就不一一分析了,請自行到前三章下載源碼閱讀。本文章到此結束了!感謝大家的支援!!!

cocos2dx《單機鬥地主》源碼解剖之八 電腦玩家出牌與跟牌(結束)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.