判斷麻将和牌的算法(轉載) 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; } |