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: shyworm@sina.com *
17 ***************************************************************/
18
19 #include <stdio.h>
20
21 int Hu(int PAI[38]); //判定是否和牌的函数
22
23 int Remain(int PAI[38]); //判定还剩下多少张牌
24
25 int QIDUI(int PAI[38]);//七小对的判定
26
27 int SHISANYAO(int PAI[38]);//十三幺的判定
28
29 int main()
30 {
31 // 把一副牌放在下面的数组里,可以任意填入数字来测试函数正确与否。
32 // 为了方便,PAI[0],PAI[10],PAI[20],PAI[30]都弃之不用,并且必须
33 // 置为0,千万注意!这里是随意的一些数据,因为没有设置输入函数,可以在这里改进的
34 int PAI[38] = { 0,
35 1,1,1,0,1,1,1,0,0, // PAI[ 1- 9] 壹万~玖万的个数
36 0,
37 0,0,0,0,0,3,0,0,0, // PAI[11-19] 壹铜~玖铜的个数
38 0,
39 0,0,0,0,0,0,0,0,0, // PAI[21-29] 壹条~玖条的个数
40 0,
41 0,1,1,1,0,0,0 // PAI[31-37] 东南西北中发白的个数
42 };
43 // 请务必先排除“七对” 和“十三幺”,由于简单,所以不提供了
44 // if( QIDUI(PAI) )...
45 // if( SHISANYAO(PAI) )...
46 //这里吴昊已经给出了具体的办法,并设置在Hu(int PAI[38])函数中
47 if( Hu(PAI) )
48 printf("win\n");
49 else
50 printf("not win\n");
51 return 1;
52 }
53
54 // 判断和牌的递归函数,不考虑“七对” 和“十三幺”。因为如果
55 // 把“七对” 和“十三幺”的判断放在递归函数里,将得不偿失。
56
57 int Hu(int PAI[38])
58 {
59 QIDUI(PAI);
60 SHISANYAO(PAI);
61 int i;
62 static int JIANG = 0; // 将牌标志
63 if( !Remain(PAI) ) return 1; // 递归退出条件:如果没有剩牌,则和牌返回。
64 for(i=1;!PAI[i]&&i<38;i++); // 找到有牌的地方,i就是当前牌, PAI[i]是个数
65
66 // 4张组合(杠子)
67 if ( PAI[i] == 4 ) // 如果当前牌数等于4张
68 {
69 PAI[i] = 0; // 除开全部4张牌
70 if( Hu(PAI) ) return 1; // 如果剩余的牌组合成功,和牌
71 PAI[i] = 4; // 否则,取消4张组合
72 }
73 // 3张组合(大对)
74 if ( PAI[i] >= 3 ) // 如果当前牌不少于3张
75 {
76 PAI[i] -= 3; // 减去3张牌
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 += PAI[i];
113 return sum;
114 }
115
116 int QIDUI(int PAI[38])
117 {
118 int count=0;
119 for(int i=0;i<38;i++)
120 {
121 if(PAI[i]>=2) count++;
122 }
123 if(count==7) return 1;
124 else return 0;
125 }
126
127 int SHISANYAO(int PAI[38])
128 {
129 if(PAI[1]==1&&PAI[9]==1&&PAI[11]==1&&PAI[19]==1&&PAI[21]==1&&PAI[29]==1)
130 {
131 int count=0;
132 for(int i=31;i<38;i++)
133 {
134 if(PAI[i]==1)
135 {
136 count++;
137 }
138 }
139 if(count==7)
140 {
141 return 1;
142 }
143 }
144 return 0;
145 }