斗地主文本

斗地主源码下载

链接:https://pan.baidu.com/s/1b_ADdWrLE8di1SSlFfuYPQ  密码:uavm


1创建一副扑克牌,写代码首先创建一张牌的类。如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

class Poker : public Sprite  

{  

    public:  

        Poker();  

        ~Poker();  

        static Poker* create(const char *pszFileName, const CCRect& rect);  

        virtual void onEnter();  

        virtual void onExit();  

        virtual bool onTouchBegan(CCTouch *pTouch, CCEvent *pEvent);  

        virtual void onTouchMoved(CCTouch *pTouch, CCEvent *pEvent);  

        virtual void onTouchEnded(CCTouch *pTouch, CCEvent *pEvent);  

        virtual void onTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);  

        void showFront();//显示正面  

        void showLast();//显示背面  

        Poker* copy();//拷贝  

        void setTouchPriority(int num);  

        void SelectPkLuTou();//如果选择了牌就露出头  

        void SelectPkSuoTou();//如果选择了牌就缩头  

    private:  

        CC_SYNTHESIZE(bool,m_isSelect,Select);//是否已选  

        CC_SYNTHESIZE(GameScene*,m_gameMain,GameMain);  

        CC_SYNTHESIZE(bool,m_isDianJi,DianJi);//是否能被点击  

        CC_SYNTHESIZE(int,m_huaSe,HuaSe);//花色  

        CC_SYNTHESIZE(int,m_num,Num);//牌值  

        EventListenerTouchOneByOne* touchListener;  

};


然后我们用这个类写了一个函数来生成一张牌,该函数如下(位于源码GameScene中):

1

2

3

4

5

6

7

8

9

10

11

Poker* GameScene::selectPoker(int huaSe,int num){  

    Poker* pk;  

    if(huaSe != Gui)  

        pk = Poker::create("poker.png",CCRect(num*pkWidth,huaSe*pkHeight,pkWidth,pkHeight));  

    else  

        pk = Poker::create("poker.png",CCRect((num-XiaoGui)*pkWidth,huaSe*pkHeight,pkWidth,pkHeight));  

    pk->setHuaSe(huaSe);  

    pk->setNum(num);   牌值

    pk->setGameMain(this);  

    return pk;  

}



2接下来我们就用来创建一副扑克牌了,请看代码(在GameScene文件中)GameScene

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

bool GameScene::createPokers(){  

    bool isRet = false;  

    do   

    {  

        Size size = Director::sharedDirector()->getVisibleSize();  

        Poker* pk;  

        //创建52个除大鬼小鬼外的牌  

        for (int i=0; i<4; ++i)  

        {  

            for (int j=0; j<13; ++j)  

            {  

                pk = selectPoker(i,j);  

                pk->setPosition(ccp(size.width/2/*+j*20*/,size.height/2/*-i*20*/));  

                pk->showLast();  

                this->addChild(pk);  

                this->m_arrPokers->addObject(pk);  

            }  

        }  

        //创建小鬼  

        pk = selectPoker(Gui,XiaoGui);  

        pk->setPosition(ccp(size.width/2,size.height/2/*-4*20*/));  

        pk->showLast();  

        this->addChild(pk);  

        this->m_arrPokers->addObject(pk);  

        //创建大鬼  

        pk = selectPoker(Gui,DaGui);  

        pk->setPosition(ccp(size.width/2/*+20*/,size.height/2/*-4*20*/));  

        pk->showLast();  

        this->addChild(pk);  

        this->m_arrPokers->addObject(pk);  

        isRet = true;  

    } while (0);  

    return isRet;  

}

3洗牌

bool GameScene::xiPai(){  

    bool isRet = false;  

    do   

    {  

        for(int i=0; i<54; ++i)  

        {  

            Poker* pk1 = (Poker*)m_arrPokers->randomObject();  

            Poker* pk2 = (Poker*)m_arrPokers->randomObject();  

            m_arrPokers->exchangeObject(pk1,pk2);  

        }  

        isRet = true;  

    } while (0);  

    return isRet;  

}

随机取两张牌并使之交换,进行54次,这样就把原先顺序打乱了。

牌洗完之后,下面就该一个一个向玩家发牌了,请看下面代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

void GameScene::SendPk(){  

    Poker* pk;  

    if(m_iSendPk<51 && m_isSend)//前51张牌发给玩家  

    {  

        pk = (Poker*)m_arrPokers->objectAtIndex(m_iSendPk);  

        if(m_iSendPk%3 == 0)//给玩家发牌  

            MovePk(m_player,pk);  

        else if(m_iSendPk%3 == 1)//给电脑1发牌  

            MovePk(m_npcOne,pk);  

        else if(m_iSendPk%3 == 2)//给电脑2发牌  

            MovePk(m_npcTwo,pk);  

        ++m_iSendPk;  

        m_isSend = false;  

    }else if (m_iSendPk>50 && m_iSendPk<54 && m_isSend)//留下三张地主牌  

    {  

        pk = (Poker*)m_arrPokers->objectAtIndex(m_iSendPk);  

        pk->showFront();  

        MovePk(m_Three,pk);  

        ++m_iSendPk;  

        m_isSend = false;  

    }  

    else if(m_iSendPk>53)//牌发完分析电脑玩家的牌型  

    {  

        FenChaiNpcPai(m_npcOne);  

        FenChaiNpcPai(m_npcTwo);  

        m_iSendPk = 0;  

        m_iState = 1;  

    }  

}

m_isSend的变量了,这个变量就是指发给某一个玩家的牌动画是否完成。我们再来看一下MovePk()的代码就有些明白了:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

void GameScene::MovePk(Player* play,Poker* pk)  

{  

    CCMoveTo* move;  

    CCCallFuncND* func;  

    float time = 0.05;  

    play->getArrPk()->addObject(pk);//从一副牌中选择pk这张牌  

    move = CCMoveTo::create(time,play->getPoint());  

    func = CCCallFuncND::create(this,callfuncND_selector(GameScene::func),play);  

    CCSequence* sequence = CCSequence::create(move,func,NULL);  

    pk->runAction(sequence);  

}  

   

void GameScene::func(CCNode* pSender, void* pData){  

    Player* play = (Player*)pData;  

    play->updatePkWeiZhi();//整理一个玩家手中的牌  

    m_isSend = true;  

}

4

头文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

class Player : public CCObject  

{  

public:  

    Player();  

    ~Player();  

    void updatePkWeiZhi();//设置牌的位置  

       

private:  

    CC_SYNTHESIZE(bool,m_isDiZhu,IsDiZhu);//是否为地主  

    CC_SYNTHESIZE(bool,m_isCall,Call);//是否已叫地主  

    CC_SYNTHESIZE(int,m_iCallNum,CallNum);//叫地主的分数  

    CC_SYNTHESIZE(CCArray*,m_arrPk,ArrPk);//手里拥有的扑克牌  

    CC_SYNTHESIZE(CCPoint,m_point,Point);//牌在桌面的初始位置  

    CC_SYNTHESIZE(int,m_iPlayerClass,PlayerClass);//玩家种类:0为玩家,1为电脑,2为显示的三张牌,3为玩家要出的牌,4为电脑1要出的牌,5为电脑2要出的牌  

    std::vector<PaiXing> m_vecPX;//保存牌型  

    CC_SYNTHESIZE(bool,m_isOutPk,IsOutPk);//玩家是否出牌true: false:不出  

};

源文件

1

2

3

void Player::updatePkWeiZhi(){  

    CCSize size = CCDirector::sharedDirector()->getVisibleSize();  

    int x,y;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

    //计算玩家牌和出的牌的初始位置  

    if(m_iPlayerClass == 0 || m_iPlayerClass == 3)  

    {  

        x = size.width/2-((m_arrPk->count()-1)*pkJianJu+pkWidth)/2;  

        y = m_point.y;  

    }  

    else if(m_iPlayerClass == 1 || m_iPlayerClass == 4 || m_iPlayerClass == 5)  

    {  

        x = m_point.x;  

        y = m_point.y;  

    }  

    else if(m_iPlayerClass == 2)  

    {  

        x = size.width/2-(m_arrPk->count()*pkWidth+(m_arrPk->count()-1)*pkJianJu)/2;  

        y = m_point.y;  

    }  

    int num = 0;  

    CCObject* object;  

    //对牌进行排序  

    if(m_iPlayerClass != 3 && m_iPlayerClass != 4 && m_iPlayerClass != 5)  

        for(int i=0; m_arrPk->count()!=0 && i<m_arrPk->count()-1; ++i)  

        {  

            for(int j=0; j<m_arrPk->count()-1-i; ++j)  

            {  

                Poker* pk1 = (Poker*)m_arrPk->objectAtIndex(j);  

                Poker* pk2 = (Poker*)m_arrPk->objectAtIndex(j+1);  

                if(pk1->getNum() < pk2->getNum())  

                    m_arrPk->exchangeObject(pk1,pk2);  

            }  

        }  

    //更新位置  

    CCARRAY_FOREACH(m_arrPk,object){  

        Poker* pk = (Poker*)object;  

        if (m_iPlayerClass == 0 || m_iPlayerClass == 3)  

        {  

            pk->showFront();  

            pk->setPosition(ccp(x+num*pkJianJu+pkWidth/2,y));  

        }  

        else if(m_iPlayerClass == 1 || m_iPlayerClass == 4 || m_iPlayerClass == 5)  

        {  

            pk->showFront();  

            if(m_iPlayerClass == 1)  

                pk->showLast();  

            pk->setPosition(ccp(x,y-num*pkJianJu));  

        }  

        else if(m_iPlayerClass == 2)  

        {  

            pk->setPosition(ccp(x+num*pkJianJu+num*pkWidth+pkWidth/2,y));  

        }  

        ++num;  

    }  

    //改变牌的z值或牌的触摸优先  

    int i=m_arrPk->count()-1;  

    CCARRAY_FOREACH(m_arrPk,object){  

        Poker* pk = (Poker*)object;  

        //改变z  

        if (m_iPlayerClass == 1 || m_iPlayerClass == 4 || m_iPlayerClass == 5)  

            pk->setZOrder(size.height - pk->getPositionY());  

        if (m_iPlayerClass == 0 || m_iPlayerClass == 3)  

            pk->setZOrder(pk->getPositionX());  

        //改变优先级  

    /*  Poker* pk1 = (Poker *)m_arrPk->objectAtIndex(i--); 

        pk->setTouchPriority(pk1->getPositionX());*/  

    }  

}

这个类最主要的是 updatePkWeiZhi(),它是为了把玩家手中的牌从大到小排序并居中显示。请注意最后一块代码改变牌的z值或牌的触摸优先级,为什么要这么做呢?这是因为牌的顺序换了之后,底下的牌有的会覆盖到另一个牌之上,改变触摸优先级也是同理。


发完牌,下面就该叫地主了,首先从玩家(人)开始叫地主,下一回合所有玩家(包括电脑玩家)按逆时针顺序叫地主。我们来看一下叫地主的模块:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

void GameScene::Call(float dt){  

    //是否都叫过地主  

    if(!m_player->getCall() || !m_npcOne->getCall() || !m_npcTwo->getCall())  

    {  

        m_iCallTime%=3;  

        switch (m_iCallTime)  

        {  

        case 0://玩家选择地主分数  

            m_menu->setVisible(true);  

            if (m_bCall[0])//1  

            {  

                CCMenuItemFont* itemFont = (CCMenuItemFont*)m_menu->getChildByTag(1);  

                itemFont->setEnabled(false);  

            }  

            else  

            {  

                CCMenuItemFont* itemFont = (CCMenuItemFont*)m_menu->getChildByTag(1);  

                itemFont->setEnabled(true);  

            }  

            if (m_bCall[1])//2  

            {  

                CCMenuItemFont* itemFont = (CCMenuItemFont*)m_menu->getChildByTag(2);  

                itemFont->setEnabled(false);  

            }  

            else  

            {  

                CCMenuItemFont* itemFont = (CCMenuItemFont*)m_menu->getChildByTag(2);  

                itemFont->setEnabled(true);  

            }  

            if (m_bCall[2])//3  

            {  

                CCMenuItemFont* itemFont = (CCMenuItemFont*)m_menu->getChildByTag(3);  

                itemFont->setEnabled(false);  

            }  

            else//不叫  

            {  

                CCMenuItemFont* itemFont = (CCMenuItemFont*)m_menu->getChildByTag(3);  

                itemFont->setEnabled(true);  

            }  

            break;  

        case 1://电脑1选择地主分数  

            ++m_iCallTime;  

            NpcCall(m_npcTwo,m_npcOne);//电脑玩家叫地主  

            ShowFenShu(ccp(m_npcTwo->getPoint().x-88,m_npcTwo->getPoint().y),m_npcTwo->getCallNum());  

            break;  

        case 2://电脑2选择地主分数  

            ++m_iCallTime;  

            NpcCall(m_npcOne,m_npcTwo);  

            ShowFenShu(ccp(m_npcOne->getPoint().x+88,m_npcOne->getPoint().y),m_npcOne->getCallNum());  

            break;  

        }  

    }  

    else//判断谁是地主并把三张牌给他  

    {  

        //如果都没叫地主,把地主给一开始选地主那个  

        if(m_player->getCallNum() == 0 && m_npcOne->getCallNum() == 0 && m_npcTwo->getCallNum() == 0)  

        {  

            switch (m_iCall%3)  

            {  

            case 0:  

                m_player->setCallNum(3);  

                break;  

            case 1:  

                m_npcTwo->setCallNum(3);  

                break;  

            case 2:  

                m_npcOne->setCallNum(3);  

                break;  

            default:  

                break;  

            }  

        }  

        //谁的值大谁当地主  

        CCObject* object;  

        if(m_player->getCallNum() > m_npcOne->getCallNum() && m_player->getCallNum() > m_npcTwo->getCallNum()){  

            CCArray* arrTem = CCArray::create();  

            CCARRAY_FOREACH(m_Three->getArrPk(),object){  

                Poker* pk = (Poker *)object;  

                Poker* pkCopy = pk->copy();  

                arrTem->addObject(pkCopy);  

                addChild(pkCopy);  

                m_player->getArrPk()->addObject(pk);  

                m_player->setIsDiZhu(true);  

                m_npcOne->setIsDiZhu(false);  

                m_npcTwo->setIsDiZhu(false);  

                m_iOutCard = 0;  

            }  

            m_Three->getArrPk()->removeAllObjects();  

            m_Three->getArrPk()->addObjectsFromArray(arrTem);  

            m_Three->updatePkWeiZhi();  

            m_player->updatePkWeiZhi();  

            //显示地主标签  

            m_lableDiZhu->setPosition(playerDiZhuLablePt);  

            m_lableDiZhu->setVisible(true);  

        }  

        if(m_npcOne->getCallNum() > m_player->getCallNum() && m_npcOne->getCallNum() > m_npcTwo->getCallNum()){  

               

            CCArray* arrTem = CCArray::create();  

            CCARRAY_FOREACH(m_Three->getArrPk(),object){  

                Poker* pk = (Poker *)object;  

                Poker* pkCopy = pk->copy();  

                arrTem->addObject(pkCopy);  

                addChild(pkCopy);  

                m_npcOne->getArrPk()->addObject(pk);  

                m_player->setIsDiZhu(false);  

                m_npcOne->setIsDiZhu(true);  

                m_npcTwo->setIsDiZhu(false);  

                m_iOutCard = 2;  

            }  

            m_Three->getArrPk()->removeAllObjects();  

            m_Three->getArrPk()->addObjectsFromArray(arrTem);  

            m_Three->updatePkWeiZhi();  

            //重新分拆牌  

            m_npcOne->m_vecPX.clear();  

            m_npcOne->updatePkWeiZhi();  

            FenChaiNpcPai(m_npcOne);  

            //显示地主标签  

            m_lableDiZhu->setPosition(npcOneDiZhuLablePt);  

            m_lableDiZhu->setVisible(true);  

        }  

        if(m_npcTwo->getCallNum() > m_npcOne->getCallNum() && m_npcTwo->getCallNum() > m_player->getCallNum()){  

            CCArray* arrTem = CCArray::create();  

            CCARRAY_FOREACH(m_Three->getArrPk(),object){  

                Poker* pk = (Poker *)object;  

                Poker* pkCopy = pk->copy();  

                arrTem->addObject(pkCopy);  

                addChild(pkCopy);  

                m_npcTwo->getArrPk()->addObject(pk);  

                m_player->setIsDiZhu(false);  

                m_npcOne->setIsDiZhu(false);  

                m_npcTwo->setIsDiZhu(true);  

                m_iOutCard = 1;  

            }  

            m_Three->getArrPk()->removeAllObjects();  

            m_Three->getArrPk()->addObjectsFromArray(arrTem);  

            m_Three->updatePkWeiZhi();  

            //重新分拆牌  

            m_npcTwo->m_vecPX.clear();  

            m_npcTwo->updatePkWeiZhi();  

            FenChaiNpcPai(m_npcTwo);  

            //显示地主标签  

            m_lableDiZhu->setPosition(npcTwoDiZhuLablePt);  

            m_lableDiZhu->setVisible(true);  

        }  

        m_iState = 2;  

        ++m_iCall;  

        m_iCallTime = m_iCall;  

        unschedule(schedule_selector(GameScene::Call));  

        //选定地主后显示三张牌  

        CCARRAY_FOREACH(m_Three->getArrPk(),object){  

            Poker* pk = (Poker*)object;  

            pk->showFront();  

        }  

        //移除叫地主分数的显示  

        this->removeChildByTag(FenShu);  

        this->removeChildByTag(FenShu);  

        this->removeChildByTag(FenShu);  

        //使主玩家的牌为可点击状态  

        CCARRAY_FOREACH(m_player->getArrPk(),object){  

            Poker* pk = (Poker *)object;  

            pk->setDianJi(true);  

        }  

    }  

}

上面判断其实很简单:首先判断各玩家是否都已经叫分,如果是就判断谁是斗地主并把三张牌给他,如果都没有叫斗地主的话,我这里的逻辑是把斗地主判给第一个叫分的玩家。


接下来我们看看电脑玩家是如何叫分的,为了简单,我让电脑玩家随机选择分数,代码如下:

void GameScene::NpcCall(Player* npc,Player* npc1){  

    int i = rand()%4;  

    if(i == 3) //3表示不叫  

    {  

        npc->setCall(true);//设置已叫地主  

        npc->setCallNum(0);//分数设置为0  

    }  

    else  

    {  

        while (m_bCall[i] == true)//bool m_bCall[3];分数是否被叫 m_bCall[0]:1 m_bCall[1]:2 m_bCall[2]:3  

            i = rand()%3; //重新选择分数  

        m_bCall[i] = true;  

        npc->setCall(true);  

        npc->setCallNum(i+1);  

        //如果叫3分,设置其他玩家已叫地主状态  

        if(i == 2)  

        {  

            m_player->setCall(true);  

            npc1->setCall(true);  

        }  

    }  

}  

5

当玩家选择好要出的牌,首先判断该牌型是否合法,如果合法就高亮显示出出牌按钮,否则显示灰色出牌按钮,表示不可出。那么怎么判断玩家所选择的牌型是合法呢?请看下面代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

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是玩家选出的牌。先看以下代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

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

    }  

}

1

2

3

4

5

6

7

//记数 排序出的牌用  

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;是指什么呢,他们是一个枚举变量,分别代表一个牌型,请看下面代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

//斗地主共有13种牌型  

enum CARD_TYPE  

{  

    SINGLE_CARD = 1,        //单牌-  

    DOUBLE_CARD,            //对子-  

    THREE_CARD,             //3不带-  

    BOMB_CARD,              //炸弹  

    THREE_ONE_CARD,         //31-  

    THREE_TWO_CARD,         //32-  

    BOMB_TWO_CARD,          //四个带2张单牌  

    BOMB_TWOOO_CARD,        //四个带2  

    CONNECT_CARD,           //连牌-  

    COMPANY_CARD,           //连队-  

    AIRCRAFT_CARD,          //飞机不带-  

    AIRCRAFT_SINGLE_CARD,   //飞机带单牌-  

    AIRCRAFT_DOBULE_CARD,   //飞机带对子-  

    ERROR_CARD              //错误的牌型  

} ;

下面分析//牌的张数大于等于5张的类型判断,原代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

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.下面贴上代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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,41

接下来放上判断是否是连对 IsLianDui() 代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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值,所以很抱歉:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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为一种结构体:

1

2

3

4

5

6

7

struct CRAD_INDEX//分析飞机  

{  

    std::vector<int> single_index;//单张  

    std::vector<int> duble_index;//双张  

    std::vector<int> three_index;//三张  

    std::vector<int> four_index;//四张  

};

以上的结构体是为了对出的牌进行分类用,下面看看是如何对牌分类的,下面是FenXiFeiJi()的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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)  

            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;  

}

本章至此结束,下面就可以判断玩家(人)出的牌是否合法了。

6、

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

oiy372152015-03-06 10:32:541988 次阅读

在电脑玩家跟牌和出牌之前首先对电脑玩家的牌进行拆分:

根据文档需求(见斗地主规则)拆分牌按以下顺序,先分析炸弹---飞机---连对---连牌--三带,对子,单张。请看如下代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

void GameScene::FenChaiNpcPai(Player* npc){  

    /************************************************************************/  

    /* 1.首先分析出来牌的类型(如:四张,三张,两张,一张)                                              */  

    /************************************************************************/  

    std::vector<PaiXing> vec;  

    PaiXing xing;  

    CCArray* arr = CCArray::create();//临时数组  

    arr->addObjectsFromArray(npc->getArrPk());  

    //提取双鬼  

    Poker* pk = (Poker *)arr->objectAtIndex(0);  

    Poker* pk1 = (Poker *)arr->objectAtIndex(1);  

    if(pk->getHuaSe() == Gui && pk1->getHuaSe() == Gui){  

        xing.type = BOMB_CARD;  

        xing.vec.push_back(pk);  

        xing.vec.push_back(pk1);  

        arr->removeObject(pk);  

        arr->removeObject(pk1);  

        vec.push_back(xing);  

    }  

    //分析牌型  

    for(int i=0; i<arr->count();)  

    {  

        pk = (Poker*)arr->objectAtIndex(i);  

        xing.vec.clear();//清除数组  

        //找出与pk相同的牌  

        for (int j=i; j<arr->count(); ++j)  

        {  

            pk1 = (Poker*)arr->objectAtIndex(j);  

            if(pk->getNum() == pk1->getNum())  

            {  

                ++i;  

                xing.vec.push_back(pk1);  

            }  

            else  

            {  

                break;  

            }  

        }  

        if(xing.vec.size() == 4)  

            xing.type = BOMB_CARD;  

        if(xing.vec.size() == 3)  

            xing.type = THREE_CARD;  

        if(xing.vec.size() == 2)  

            xing.type = DOUBLE_CARD;  

        if(xing.vec.size() == 1)  

            xing.type = SINGLE_CARD;  

        vec.push_back(xing);  

    }  

    /************************************************************************/  

    /* 2.按优先级(先分析炸弹---飞机---连对---连牌--三带,对子,单张)提取牌型并保存用于出牌或跟牌                               */  

    /************************************************************************/  

    //提取炸弹  

    for(std::vector<PaiXing>::iterator iter = vec.begin(); iter != vec.end(); )  

    {  

        if(iter->type == BOMB_CARD)  

        {  

            xing.type = BOMB_CARD;  

            xing.vec.clear();  

            xing.vec = iter->vec;  

            npc->m_vecPX.push_back(xing);//把牌型保存到用户数组中  

            iter = vec.erase(iter);  

        }  

        else  

        {  

            ++iter;  

        }  

    }  

    //提取飞机  

    TiQuFeiJi(npc,THREE_CARD,vec);  

    //提取连对  

    TiQuLianDui(npc,vec);  

    //提取连牌  

    TiQuLianPai(npc,vec);  

    //剩余的是三带,对子,单张 全部加入npc牌型中  

    for(std::vector<PaiXing>::iterator iter = vec.begin(); iter != vec.end();)  

    {  

        npc->m_vecPX.push_back(*iter);  

        iter = vec.erase(iter);  

    }  

    //排序  

    stable_sort(npc->m_vecPX.begin(),npc->m_vecPX.end(),isShorter1);  

}

最后按每个牌型的值从小到大进行排序。

提取飞机代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

void GameScene::TiQuFeiJi(Player* npc,CARD_TYPE type,std::vector<PaiXing> &vec){  

    Poker * pk = NULL;  

    PaiXing xing;  

    for (std::vector<PaiXing>::iterator iter=vec.begin(); iter != vec.end();)  

    {  

        if(pk == NULL && iter+1 == vec.end())  

            break;  

        if(pk == NULL && iter->type == type && (iter+1)->type == type)  

        {  

            Poker* pk1 = iter->vec.front();  

            Poker* pk2 = (iter+1)->vec.front();  

            if(pk1->getNum()-1 == pk2->getNum())  

            {  

                pk = pk2;  

                xing.type = AIRCRAFT_CARD;  

                xing.vec.clear();  

                xing.vec = iter->vec;  

                iter = vec.erase(iter);  

                xing.vec.insert(xing.vec.end(),iter->vec.begin(),iter->vec.end());  

                iter = vec.erase(iter);  

            }  

        }  

        if(pk != NULL)  

        {  

            if(iter == vec.end())  

            {  

                npc->m_vecPX.push_back(xing);  

                break;  

            }  

               

            Poker* pk1 = iter->vec.front();  

            if(iter->type == type && pk->getNum()-1 == pk1->getNum())  

            {  

                pk = pk1;  

                xing.vec.insert(xing.vec.end(),iter->vec.begin(),iter->vec.end());  

                iter = vec.erase(iter);  

                if(iter == vec.end())  

                {  

                    npc->m_vecPX.push_back(xing);  

                    break;  

                }  

            }  

            else  

            {  

                npc->m_vecPX.push_back(xing);  

                pk = NULL;  

            }  

        }  

        else  

        {  

            ++iter;  

        }  

    }  

}

提取连对代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

void GameScene::TiQuLianDui(Player* npc,std::vector<PaiXing> &vec){  

    std::vector<PaiXing> vecTem;//临时数组  

    std::vector<PaiXing> vecFan;//存放要重新返还vec里的牌  

    Poker* pk = NULL;  

    for(std::vector<PaiXing>::iterator iter = vec.begin(); iter != vec.end();)  

    {  

        //将相连的牌加入临时数组中  

        Poker* pk1 = iter->vec.front();  

        if((iter->type == THREE_CARD || iter->type == DOUBLE_CARD) && (pk == NULL || (pk->getNum()-1 == pk1->getNum() && pk->getNum() < Er)))  

        {  

            pk = pk1;  

            vecTem.push_back(*iter);  

            iter = vec.erase(iter);  

        }  

        else  

        {  

            if(pk == NULL)  

                ++iter;  

            pk = NULL;  

            if(vecTem.size() >= 3)  

            {  

                PaiXing xing;  

                xing.type = COMPANY_CARD;  

                for (int i=0; i<vecTem.size(); ++i)  

                {  

                    if(vecTem[i].type == THREE_CARD)  

                    {  

                        //将多余的一张保存返回数组vecFan  

                        PaiXing xing1;  

                        xing1.type = SINGLE_CARD;  

                        xing1.vec.push_back(vecTem[i].vec.back());  

                        vecTem[i].vec.pop_back();  

                        vecFan.push_back(xing1);  

                        //将剩余两张保存xing  

                        xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                    }  

                    if(vecTem[i].type == DOUBLE_CARD)  

                    {  

                        xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                    }  

                }  

                vecTem.clear();  

                npc->m_vecPX.push_back(xing);  

            }  

            else if(!vecTem.empty())  

            {  

                vecFan.insert(vecFan.end(),vecTem.begin(),vecTem.end());  

                vecTem.clear();  

            }  

        }  

    }  

    if(!vecTem.empty())  

    {  

        if(vecTem.size() >= 3)  

        {  

            PaiXing xing;  

            xing.type = COMPANY_CARD;  

            for (int i=0; i<vecTem.size(); ++i)  

            {  

                if(vecTem[i].type == THREE_CARD)  

                {  

                    //将多余的一张保存返回数组vecFan  

                    PaiXing xing1;  

                    xing1.type = SINGLE_CARD;  

                    xing1.vec.push_back(vecTem[i].vec.back());  

                    vecTem[i].vec.pop_back();  

                    vecFan.push_back(xing1);  

                    //将剩余两张保存xing  

                    xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                }  

                if(vecTem[i].type == DOUBLE_CARD)  

                {  

                    xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                }  

            }  

            vecTem.clear();  

            npc->m_vecPX.push_back(xing);  

        }  

        else if(!vecTem.empty())  

        {  

            vecFan.insert(vecFan.end(),vecTem.begin(),vecTem.end());  

            vecTem.clear();  

        }  

    }  

    //vecFan返回到vec数组中并从大到小排序  

    if(!vecFan.empty())  

    {  

        vec.insert(vec.end(),vecFan.begin(),vecFan.end());  

        stable_sort(vec.begin(),vec.end(),isDaDaoXiao);  

    }  

}

提取连牌代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

void GameScene::TiQuLianPai(Player* npc,std::vector<PaiXing> &vec){  

    std::vector<PaiXing> vecTem;//临时数组  

    std::vector<PaiXing> vecFan;//存放要重新返还vec里的牌  

    Poker* pk = NULL;  

    for(std::vector<PaiXing>::iterator iter = vec.begin(); iter != vec.end();)  

    {  

        //将相连的牌加入临时数组中  

        Poker* pk1 = iter->vec.front();  

        if((iter->type == THREE_CARD || iter->type == DOUBLE_CARD || iter->type == SINGLE_CARD) && (pk == NULL || (pk->getNum()-1 == pk1->getNum() && pk->getNum() < Er)))  

        {  

            pk = pk1;  

            vecTem.push_back(*iter);  

            iter = vec.erase(iter);  

        }  

        else  

        {  

            if(pk == NULL)  

                ++iter;  

            pk = NULL;  

            if(vecTem.size() >= 5)  

            {  

                PaiXing xing;  

                xing.type = CONNECT_CARD;  

                for (int i=0; i<vecTem.size(); ++i)  

                {  

                    if(vecTem[i].type == THREE_CARD)  

                    {  

                        //将多余的两张保存返回数组vecFan  

                        PaiXing xing1;  

                        xing1.type = DOUBLE_CARD;  

                        xing1.vec.push_back(vecTem[i].vec.back());  

                        vecTem[i].vec.pop_back();  

                        xing1.vec.push_back(vecTem[i].vec.back());  

                        vecTem[i].vec.pop_back();  

                        vecFan.push_back(xing1);  

                        //将剩余一张保存xing  

                        xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                    }  

                    if(vecTem[i].type == DOUBLE_CARD)  

                    {  

                        //将多余的一张保存返回数组vecFan  

                        PaiXing xing1;  

                        xing1.type = SINGLE_CARD;  

                        xing1.vec.push_back(vecTem[i].vec.back());  

                        vecTem[i].vec.pop_back();  

                        vecFan.push_back(xing1);  

                        //将剩余一张保存xing  

                        xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                    }  

                    if(vecTem[i].type == SINGLE_CARD)  

                        xing.vec.push_back(vecTem[i].vec.front());  

                }  

                vecTem.clear();  

                npc->m_vecPX.push_back(xing);  

            }  

            else if(!vecTem.empty())  

            {  

                vecFan.insert(vecFan.end(),vecTem.begin(),vecTem.end());  

                vecTem.clear();  

            }  

        }  

    }  

    if(!vecTem.empty())  

    {  

        if(vecTem.size() >= 5)  

        {  

            PaiXing xing;  

            xing.type = CONNECT_CARD;  

            for (int i=0; i<vecTem.size(); ++i)  

            {  

                if(vecTem[i].type == THREE_CARD)  

                {  

                    //将多余的两张保存返回数组vecFan  

                    PaiXing xing1;  

                    xing1.type = DOUBLE_CARD;  

                    xing1.vec.push_back(vecTem[i].vec.back());  

                    vecTem[i].vec.pop_back();  

                    xing1.vec.push_back(vecTem[i].vec.back());  

                    vecTem[i].vec.pop_back();  

                    vecFan.push_back(xing1);  

                    //将剩余一张保存xing  

                    xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                }  

                if(vecTem[i].type == DOUBLE_CARD)  

                {  

                    //将多余的一张保存返回数组vecFan  

                    PaiXing xing1;  

                    xing1.type = SINGLE_CARD;  

                    xing1.vec.push_back(vecTem[i].vec.back());  

                    vecTem[i].vec.pop_back();  

                    vecFan.push_back(xing1);  

                    //将剩余一张保存xing  

                    xing.vec.insert(xing.vec.end(),vecTem[i].vec.begin(),vecTem[i].vec.end());  

                }  

                if(vecTem[i].type == SINGLE_CARD)  

                    xing.vec.push_back(vecTem[i].vec.front());  

            }  

            vecTem.clear();  

            npc->m_vecPX.push_back(xing);  

        }  

        else if(!vecTem.empty())  

        {  

            vecFan.insert(vecFan.end(),vecTem.begin(),vecTem.end());  

            vecTem.clear();  

        }  

    }  

    //vecFan返回到vec数组中并从大到小排序  

    if(!vecFan.empty())  

    {  

        vec.insert(vec.end(),vecFan.begin(),vecFan.end());  

        stable_sort(vec.begin(),vec.end(),isShorter1);  

    }  

}



7

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

oiy372152015-03-06 10:46:393007 次阅读

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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函数的策略:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

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为玩家出牌与跟牌的策略,12为电脑玩家出牌与跟牌的策略。他们的意义已在代码里添加注释。

在上面代码中你一定发现了有些令人费解的函数(ClearOutPk()NpcOutPoker(m_npcTwo,m_arrGenPk,m_npcTwoOut)NpcGenPoker(m_npcTwo,m_arrGenPk ,m_npcTwoOut)IsOutPkFinish()),下面一一解释:

ClearOutPk()的代码:

1

2

3

void GameScene::ClearOutPk()  

{  

    CCObject* object;

1

//清除玩家出的牌

1

2

3

4

5

CCARRAY_FOREACH(m_playerOut->getArrPk(),object){  

    Poker* pk = (Poker*)object;  

    pk->setVisible(false);  

}  

m_playerOut->getArrPk()->removeAllObjects();

1

2

3

4

5

6

//清除电脑玩家出的牌  

    CCARRAY_FOREACH(m_npcTwoOut->getArrPk(),object){  

        Poker* pk = (Poker*)object;  

        pk->setVisible(false);  

    }  

    m_npcTwoOut->getArrPk()->removeAllObjects();

1

2

3

4

5

6

7

8

9

//同上  

    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) 电脑出牌策略:

电脑出牌策略我这里只是简单的判断,打出排在第一位置牌值最小的牌型。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

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())跟牌策略:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

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

}


猜你喜欢

转载自blog.csdn.net/qq_41939248/article/details/80542867
今日推荐