天天看点

判断麻将和牌的算法(转载)

判断麻将和牌的算法(转载) 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;

}