洗牌算法

    在此声明一下这不是

 

 

 

 

前两天和几个做在线棋牌游戏的朋友聚会,聊到了洗牌算法,正好以前写过一些扑克牌的游戏,中间做了一个洗牌算法,就写了个例子给他们做试验。

基本思路很简单,就是交换法,54张牌排好,随

 

机选择两张牌交换,一般说来,只要交换次数足够多,比如54张牌就交换54次,牌就已经洗得很烂了,呵呵,可以打牌了。如果还不放心,那double,洗108次好了。

程序还是比较简单的,大家应该一目了然,我花了差不多半个小时左右写出来,又测试了一下。

Code:
#define POKER_MAX 54            //54张扑克   
#define POKER_COLOR_MAX 4       //四种主花色   
#define POKER_POINT_MAX 13      //每种花色13张牌,J=11,Q=12,K=13   
  
#define POKER_COLOR_KING    4   //王的花色   
#define POKER_COLOR_0       0   //黑桃花色   
#define POKER_COLOR_1       1   //红桃花色   
#define POKER_COLOR_2       2   //樱花花色   
#define POKER_COLOR_3       3   //方块花色   
  
#define POKER_KING_POINT_BIG    1   //大王的点数   
#define POKER_KING_POINT_LITTLE 0   //小王的点数   
  
  
typedef struct _POKER_CARD_   
{   
    short m_sID;        //全序列排列时的ID(0~53)   
    char m_cColor;      //扑克花色   
    char m_cPoint;      //扑克点数   
}SCard;   
const unsigned long SCardSize=sizeof(SCard);   
class CPoker   
{   
public:   
    CPoker()   
    {   
        //先整齐排列54张牌,按黑红樱方顺序,每种花色按0~12顺序   
        int i=0;   
        int j=0;   
        int nIndex=0;   
        for(i=0;i<POKER_COLOR_MAX;i++)   
        {   
            for(j=0;j<POKER_POINT_MAX;j++)   
            {   
                SetPokerInfo(i,j,nIndex);   
                nIndex++;   
            }   
        }   
        //王放在最后两张   
        SetPokerInfo(POKER_COLOR_KING,POKER_KING_POINT_LITTLE,nIndex);  //小王   
        nIndex++;   
        SetPokerInfo(POKER_COLOR_KING,POKER_KING_POINT_BIG,nIndex); //大王   
    }   
    ~CPoker(){}   
    //一般说来,按牌总数决定洗牌次数,已经洗得很烂了   
    void Wash(int nTime=POKER_MAX)   
    {   
        int i=0;   
        for(i=0;i<nTime;i++)   
            Random();   
    }   
    //实际的游戏,从此处取洗好的牌张数据   
    bool Get(unsigned int nIndex,SCard* pCard)   
    {   
        if(POKER_MAX<=nIndex) return false;   
        memcpy((char*)pCard,(char*)&m_Poker[nIndex],SCardSize);   
        return true;   
    }   
    void PrintInfo(void)   
    {   
        int i=0;   
        SCard Card;   
        for(i=0;i<POKER_MAX;i++)   
        {   
            if(Get(i,&Card))   
            {   
                printf("%02d - ID=%02d, Color=%d, Point=%02d/n",   
                    i,Card.m_sID,Card.m_cColor,Card.m_cPoint);   
            }   
        }   
        printf("===============/n");   
    }   
private:   
    //给sID指定的牌张赋值   
    void SetPokerInfo(char cColor,char cPoint,short sID)   
    {   
        m_Poker[sID].m_cColor=cColor;   
        m_Poker[sID].m_cPoint=cPoint;   
        m_Poker[sID].m_sID=sID;   
    }   
    //交换两张牌   
    void Exchange(int a,int b)   
    {   
        char szTemp[SCardSize];   
        memcpy(szTemp,(char*)&m_Poker[a],SCardSize);   
        memcpy((char*)&m_Poker[a],(char*)&m_Poker[b],SCardSize);   
        memcpy((char*)&m_Poker[b],szTemp,SCardSize);   
    }   
    //随机选取两张牌张交换洗牌   
    //如果随机数相等,发生碰撞,则b=a+1,总之不一样就可以了。   
    void Random(void)   
    {   
        int a=GetRandomBetween(0,POKER_MAX);   
        int b=GetRandomBetween(0,POKER_MAX);   
        if(a==b)   
        {   
            b=a+1;   
            if(POKER_MAX<=b) b=0;   
        }   
        Exchange(a,b);   
    }   
private:   
    SCard m_Poker[POKER_MAX];   
};  
其实主要就是Wash这个函数,默认是洗54遍,当然,调用者如果高兴,多洗几遍也没问题,呵呵。

用Get函数拿指定的扑克张子来用。

我试了一下,没什么问题,呵呵,刺激一下大家哈,从我测试代码看,又是0bug。

不过,这段代码有个问题,就是不是多线程安全的,起码,一个线程洗牌,另外一个线程拿牌,会出错。所以,我根据《0bug-C/C++商用工程之道》里面的“资源锁”概念,又封装了一个加锁的线程安全版。

Code:
class CPokerWithLock   
{   
public:   
    CPokerWithLock(){}   
    ~CPokerWithLock(){}   
    void Wash(int nTime=POKER_MAX)   
    {   
        m_Lock.Lock();   
            m_Poker.Wash(nTime);   
        m_Lock.Unlock();   
    }   
    bool Get(unsigned int nIndex,SCard* pCard)   
    {   
        bool bRet=false;   
        m_Lock.Lock();   
            bRet=m_Poker.Get(nIndex,pCard);   
        m_Lock.Unlock();   
        return bRet;   
    }   
    void PrintInfo(void)   
    {   
        m_Lock.Lock();   
            m_Poker.PrintInfo();   
        m_Lock.Unlock();   
    }   
private:   
    CPoker m_Poker;     //"资源锁"概念,私有聚合,所有公有方法加锁,确保安全性   
    CMutexLock m_Lock;  //这是《0bug-C/C++商用工程之道》里面的跨平台安全锁,见6.2小节,P226页   
};  
嗯,这个加锁版本不是必须的,只有当多线程环境时才需要。CMutexLock这个类我这里就懒得提供了,有书的朋友,自己去查书吧。

嗯,最后,给段测试代码,大家可以看看效果。

Code:
inline void TestCPoker(void)   
{   
    CPokerWithLock Poker;   
    srand((unsigned int)time(NULL));   
    Poker.PrintInfo();   
    Poker.Wash();   
    Poker.PrintInfo();   
    Poker.Wash();   
    Poker.PrintInfo();   
}  
上述代码在VS2008下测试成功。有兴趣的朋友,可以自己试试。嗯,如果没有书的朋友,CPokerWithLock Poker;这句话可以改为CPoker Poker;,直接用非线程安全版本就好了。

大家看看,有什么问题欢迎讨论哈。

=======================================================
在线底价购买《0bug-C/C++商用工程之道》
(直接点击下面链接或拷贝到浏览器地址栏)
http://s.click.taobao.com/t_3?&p=mm_13866629_0_0&n=23&l=http%3A%2F%2Fsearch8.taobao.com%2Fbrowse%2F0%2Fn-g%2Corvv64tborsvwmjvgawdkmbqgboq---g%2Cgaqge5lhebbs6qzlfmqmttgtyo42jm6m22xllqa-------------1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20---40--coefp-0-all-0.htm%3Fpid%3Dmm_13866629_0_0

肖舸
如果您对我的文章感兴趣,请点这里添加我为好友:http://student.csdn.net/invite.php?u=39028&c=42fcd4a519102d74
博客主站:http://blog.csdn.net/tonyxiaohome
CSDN学生大本营个人主页:http://student.csdn.net/?39028

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tonyxiaohome/archive/2010/04/21/5512086.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值