天天看點

判斷麻将和牌的算法(轉載)

判斷麻将和牌的算法(轉載) 2007年05月22日 星期二 下午 05:59

#include <stdio.h> int Hu(int PAI[38]);

int Remain(int PAI[38]); int main()

{

     // 把一副牌放在下面的數組裡,可以任意填入數字來測試函數正确與否。

     // 為了友善,PAI[0],PAI[10],PAI[20],PAI[30]都棄之不用,并且必須

     // 置為0,千萬注意!

     int PAI[38] = { 0,

                     1,1,1,0,1,1,1,0,0,     // PAI[ 1- 9]   壹萬~玖萬的個數

                     0,

                     0,0,0,0,0,3,0,0,0,     // PAI[11-19]   壹銅~玖銅的個數

                     0,

                     0,0,0,0,0,0,0,0,0,     // PAI[21-29]   壹條~玖條的個數

                     0,

                     0,1,1,1,0,0,0          // PAI[31-37]   東南西北中發白的個數

                     };      // 請務必先排除“七對” 和“十三幺”,由于簡單,是以不提供了

     // if( QIDUI(PAI) )...

     // if( SHISANYAO(PAI) )...      if( Hu(PAI) )   

         printf("哈!我和啦!/n");

     else

         printf("哎,和不成!/n");      return 1;

} // 判斷和牌的遞歸函數,不考慮“七對” 和“十三幺”。因為如果

// 把“七對” 和“十三幺”的判斷放在遞歸函數裡,将得不償失。

int Hu(int PAI[38])

{

     static int JIANG = 0;             // 将牌标志,即牌型“三三三三二”中的“二”      if( !Remain(PAI) ) return 1;      // 遞歸退出條件:如果沒有剩牌,則和牌傳回。      for(int i=1;!PAI[i]&&i<38;i++);   // 找到有牌的地方,i就是目前牌, PAI[i]是個數      printf("i = %d/n",i);             // 跟蹤資訊      // 4張組合(杠子)

     if ( PAI[i] == 4 )                // 如果目前牌數等于4張

     {

         PAI[i] = 0;                   // 除開全部4張牌

         if( Hu(PAI) ) return 1;       // 如果剩餘的牌組合成功,和牌

         PAI[i] = 4;                   // 否則,取消4張組合

     }      // 3張組合(大對)

     if ( PAI[i] >= 3 )                // 如果目前牌不少于3張

     {

         PAI[i] -= 3;                  // 減去3張牌

         if( Hu(PAI) ) return 1;       // 如果剩餘的牌組合成功,和牌

         PAI[i] += 3;                  // 取消3張組合

     }      // 2張組合(将牌)

     if ( !JIANG && PAI[i] >= 2 )      // 如果之前沒有将牌,且目前牌不少于2張

     {

         JIANG = 1;                    // 設定将牌标志

         PAI[i] -= 2;                  // 減去2張牌

         if( Hu(PAI) ) return 1;       // 如果剩餘的牌組合成功,和牌

         PAI[i] += 2;                  // 取消2張組合

         JIANG = 0;                    // 清除将牌标志

     }      

     if ( i > 30 )     return 0;        // “東南西北中發白”沒有順牌組合,不和      // 順牌組合,注意是從前往後組合!

     if( i%10 != 8 && i%10 != 9   &&    // 排除數值為8和9的牌

          PAI[i+1] && PAI[i+2] )       // 如果後面有連續兩張牌

     {

         PAI[i]--;

         PAI[i+1]--;

         PAI[i+2]--;                   // 各牌數減1

         if( Hu(PAI) ) return 1;       // 如果剩餘的牌組合成功,和牌

         PAI[i]++;

         PAI[i+1]++;

         PAI[i+2]++;                   // 恢複各牌數

     }      // 無法全部組合,不和!

     return 0;

} // 檢查剩餘牌數

int Remain(int PAI[38])

{

     int sum = 0;

     for(int i=1;i<38;i++)

         sum += PAI[i];

     return sum;

}