我以前用过的一个洗牌算法
生活随笔
收集整理的這篇文章主要介紹了
我以前用过的一个洗牌算法
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
前兩天和幾個(gè)做在線棋牌游戲的朋友聚會(huì),聊到了洗牌算法,正好以前寫(xiě)過(guò)一些撲克牌的游戲,中間做了一個(gè)洗牌算法,就寫(xiě)了個(gè)例子給他們做試驗(yàn)。 基本思路很簡(jiǎn)單,就是交換法,54張牌排好,隨機(jī)選擇兩張牌交換,一般說(shuō)來(lái),只要交換次數(shù)足夠多,比如54張牌就交換54次,牌就已經(jīng)洗得很爛了,呵呵,可以打牌了。如果還不放心,那double,洗108次好了。 程序還是比較簡(jiǎn)單的,大家應(yīng)該一目了然,我花了差不多半個(gè)小時(shí)左右寫(xiě)出來(lái),又測(cè)試了一下。 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???//大王的點(diǎn)數(shù) ?? #define?POKER_KING_POINT_LITTLE?0???//小王的點(diǎn)數(shù) ?? ?? ?? typedef?struct?_POKER_CARD_ ?? { ?? ????short?m_sID;????????//全序列排列時(shí)的ID(0~53) ?? ????char?m_cColor;??????//撲克花色 ?? ????char?m_cPoint;??????//撲克點(diǎn)數(shù) ?? }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(){} ?? ????//一般說(shuō)來(lái),按牌總數(shù)決定洗牌次數(shù),已經(jīng)洗得很爛了 ?? ????void?Wash(int?nTime=POKER_MAX) ?? ????{ ?? ????????int?i=0; ?? ????????for(i=0;i<nTime;i++) ?? ????????????Random(); ?? ????} ?? ????//實(shí)際的游戲,從此處取洗好的牌張數(shù)據(jù) ?? ????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); ?? ????} ?? ????//隨機(jī)選取兩張牌張交換洗牌 ?? ????//如果隨機(jī)數(shù)相等,發(fā)生碰撞,則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]; ?? };?? 其實(shí)主要就是Wash這個(gè)函數(shù),默認(rèn)是洗54遍,當(dāng)然,調(diào)用者如果高興,多洗幾遍也沒(méi)問(wèn)題,呵呵。 用Get函數(shù)拿指定的撲克張子來(lái)用。 我試了一下,沒(méi)什么問(wèn)題,呵呵,刺激一下大家哈,從我測(cè)試代碼看,又是0bug。 不過(guò),這段代碼有個(gè)問(wèn)題,就是不是多線程安全的,起碼,一個(gè)線程洗牌,另外一個(gè)線程拿牌,會(huì)出錯(cuò)。所以,我根據(jù)《0bug-C/C++商用工程之道》里面的“資源鎖”概念,又封裝了一個(gè)加鎖的線程安全版。 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++商用工程之道》里面的跨平臺(tái)安全鎖,見(jiàn)6.2小節(jié),P226頁(yè) ?? };?? 嗯,這個(gè)加鎖版本不是必須的,只有當(dāng)多線程環(huán)境時(shí)才需要。CMutexLock這個(gè)類我這里就懶得提供了,有書(shū)的朋友,自己去查書(shū)吧。 嗯,最后,給段測(cè)試代碼,大家可以看看效果。 Code: inline?void?TestCPoker(void) ?? { ?? ????CPokerWithLock?Poker; ?? ????srand((unsigned?int)time(NULL)); ?? ????Poker.PrintInfo(); ?? ????Poker.Wash(); ?? ????Poker.PrintInfo(); ?? ????Poker.Wash(); ?? ????Poker.PrintInfo(); ?? }?? 上述代碼在VS2008下測(cè)試成功。有興趣的朋友,可以自己試試。嗯,如果沒(méi)有書(shū)的朋友,CPokerWithLock Poker;這句話可以改為CPoker Poker;,直接用非線程安全版本就好了。 大家看看,有什么問(wèn)題歡迎討論哈。 =======================================================
在線底價(jià)購(gòu)買(mǎi)《0bug-C/C++商用工程之道》
(直接點(diǎn)擊下面鏈接或拷貝到瀏覽器地址欄)
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 肖舸
在線底價(jià)購(gòu)買(mǎi)《0bug-C/C++商用工程之道》
(直接點(diǎn)擊下面鏈接或拷貝到瀏覽器地址欄)
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 肖舸
總結(jié)
以上是生活随笔為你收集整理的我以前用过的一个洗牌算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Mozilla 扩展开发环境设置
- 下一篇: Yik-Chung Wu ---Time