1. 程式人生 > >麻將簡單胡牌演算法

麻將簡單胡牌演算法

  1/***************************************************************
  2  * 檔名:hu.cpp                                              *
  3  *                                                             *
  4  * 功  能:演示一個簡潔明瞭的遞迴函式——判斷[麻將]的和牌。    *
  5  *                                                             *
  6  * 說  明:1.  此函式不判斷七對和十三么(吳昊目前已經給出了),*
  7  *              讀者不難自行判斷;                             *
  8  *     同時由於麻將的規則各不相同,也請讀者自己新增和修改。*
  9  *                                                             *
 10  *     2.  其他與麻將類似的遊戲,如[字牌](又稱跑鬍子、    *
 11  *     二七十)等牌類遊戲,也可採用類似的判斷函式。        *
 12  *                                                             *
 13  * 環  境: VC 6.0,  但符合ANSI C標準,隨便移植 ^_^             *

 14  *                                                             *

 15  * 作  者:shyworm(怕怕蟲)&&haowu111(吳昊)                                     *
 16  * E_Mail: [email protected]                                    *
 17  **************************************************************

*/
 18
 19  #include <stdio.h>
 20
 21int Hu(int PAI[38]); //判定是否和牌的函式 22
 23int Remain(int PAI[38]); //判定還剩下多少張牌 24
 25int QIDUI(int PAI[38]);//七小對的判定 26
 27int SHISANYAO(int PAI[38]);//十三么的判定 28
 29int main()

30  {
 31// 把一副牌放在下面的數組裡,可以任意填入數字來測試函式正確與否。
 32// 為了方便,PAI[0],PAI[10],PAI[20],PAI[30]都棄之不用,並且必須
 33// 置為0,千萬注意!這裡是隨意的一些資料,因為沒有設定輸入函式,可以在這裡改進的 34int PAI[38] = { 0,
 351,1,1,0,1,1,1,0,0,    // PAI[ 1- 9]  壹萬~玖萬的個數 360,
 370,0,0,0,0,3,0,0,0,    // PAI[11-19]  壹銅~玖銅的個數 380,
 390,0,0,0,0,0,0,0,0,    // PAI[21-29]  壹條~玖條的個數 400,
 410,1,1,1,0,0,0// PAI[31-37]  東南西北中發白的個數 42                  };
 43// 請務必先排除“七對” 和“十三么”,由於簡單,所以不提供了
 44// if( QIDUI(PAI) )...

45// if( SHISANYAO(PAI) )...
 46//這裡吳昊已經給出了具體的辦法,並設定在Hu(int PAI[38])函式中 47if( Hu(PAI) )  
 48      printf("win\n");
 49else
 50      printf("not win\n");
 51return1;
 52  }
 53
 54// 判斷和牌的遞迴函式,不考慮“七對” 和“十三么”。因為如果
 55// 把“七對” 和“十三么”的判斷放在遞迴函式裡,將得不償失。 56
 57int Hu(int PAI[38])
 58  {
 59    QIDUI(PAI);
 60    SHISANYAO(PAI);

 61int i;
 62staticint JIANG = 0;            // 將牌標誌 63if( !Remain(PAI) ) return1;     // 遞迴退出條件:如果沒有剩牌,則和牌返回。 64for(i=1;!PAI[i]&&i<38;i++);  // 找到有牌的地方,i就是當前牌, PAI[i]是個數
 65 66// 4張組合(槓子) 67if ( PAI[i] == 4 )               // 如果當前牌數等於4張 68    {
 69      PAI[i] = 0;                  // 除開全部4張牌 70if( Hu(PAI) ) return1;      // 如果剩餘的牌組合成功,和牌 71      PAI[i] = 4;                  // 否則,取消4張組合 72    }
 73// 3張組合(大對) 74if ( PAI[i] >= 3 )               // 如果當前牌不少於3張 75    {
 76      PAI[i] -= 3;                 // 減去3張牌

 77      if( Hu(PAI) ) return 1;      // 如果剩餘的牌組合成功,和牌 78      PAI[i] += 3;                 // 取消3張組合 79    }
 80    // 2張組合(將牌) 81    if ( !JIANG && PAI[i] >= 2 )     // 如果之前沒有將牌,且當前牌不少於2張,這裡假定所有的牌都是可以作為將的 82    {
 83      JIANG = 1;                   // 設定將牌標誌 84      PAI[i] -= 2;                 // 減去2張牌 85      if( Hu(PAI) ) return 1;      // 如果剩餘的牌組合成功,和牌 86      PAI[i] += 2;                 // 取消2張組合 87      JIANG = 0;                   // 清除將牌標誌 88    }
 89    if ( i > 30 )    return 0;       // “東南西北中發白”沒有順牌組合,不和
 90  91 // 順牌組合,注意是從前往後組合! 92    if( i%10 != 8 && i%10 != 9  &&   // 排除數值為8和9的牌 93        PAI[i+1] && PAI[i+2] )      // 如果後面有連續兩張牌 94    {
 95      PAI[i]--;
 96      PAI[i+1]--;
 97      PAI[i+2]--;                  // 各牌數減1 98      if( Hu(PAI) ) return 1;      // 如果剩餘的牌組合成功,和牌 99      PAI[i]++;
100      PAI[i+1]++;
101      PAI[i+2]++;                  // 恢復各牌數102    }
103    // 無法全部組合,不和!104    return 0;
105  }
106  
107  // 檢查剩餘牌數108  int Remain(int PAI[38])
109  {
110    int sum = 0;
111    for(int i=1;i<38;i++)
112      sum +=