我以前用过的一个洗牌算法
生活随笔
收集整理的這篇文章主要介紹了
我以前用过的一个洗牌算法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前兩天和幾個做在線棋牌游戲的朋友聚會,聊到了洗牌算法,正好以前寫過一些撲克牌的游戲,中間做了一個洗牌算法,就寫了個例子給他們做試驗。 基本思路很簡單,就是交換法,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 肖舸
在線底價購買《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 肖舸
總結
以上是生活随笔為你收集整理的我以前用过的一个洗牌算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mozilla 扩展开发环境设置
- 下一篇: Yik-Chung Wu ---Time