注册 登录
编程论坛 数据结构与算法

歪胡子牌胡法

qunxingw 发布于 2013-04-07 10:56, 1583 次点击
湖南岳阳一带流行一种纸牌玩法,“歪胡子”,也叫“鬼胡子”是由一,二,三....十;及壹,贰,参.....拾,组成,共80支牌。手上牌打牌时牌数是3的倍数多一张牌,不超过19张,胡牌时是3的倍数多2张牌,不超过20张。有玩法与麻将有点类似,由三个连续的数或三个相同的数组合,但多了一个二,七,十的组合,大字与小字之间不能相混组合。胡牌时也和麻将有点不同,二个门子都可胡牌。
如以下都可胡牌:(1,2,3...代表: 一,二,三...; 11,12,13...代表:壹,贰,参)
1 2 3 2 7 10    15 16
1 2 3 2 7       15 16 17
1 2 3 2 7 10    15    17
1 2 3 2 7 10    15  15

以下完成了是否胡牌的程序,暂时没考虑“息”的情况,主要思路是,如果胡牌,则一定可以加张牌,使最后剩下的二张牌完成一句话或三个相同或二七十的组合,此思路多了很多重复的计算,主要是为了回避二七十组合的干扰。欢迎朋友们讨论。
程序代码:
#include<iostream>
using namespace std;
int _del(int* a) //處理函數21支牌(增加了1支)
{
    int i;
   
    for( i=0; i<20; i++)
    {
        if(a[i]>=3)   
        {
            a[i]-=3;
        }
        if(a[i]==1 && i<8)   //處理連續的小字
        {
            if(a[i+1]>0 && a[i+2]>0)
            { a[i]--; a[i+1]--;  a[i+2]--;}
            
        }
        
        if(a[i]==2 && i<8 )    //處理連續的小字
        {
            if(a[i+1]>1 && a[i+2]>1)
            { a[i]-=2; a[i+1]-=2; a[i+2]-=2;}
            
            
        }  
        
        if(a[i]==1  && i>=10 && i<18)  //處理連續的大字
        {
            if(a[i+1]>0 && a[i+2]>0)
            { a[i]--; a[i+1]--;  a[i+2]--;}
            
        }
        
        if(a[i]==2 && i>=10 && i<18 )  //處理連續的大字
        {
            if(a[i+1]>1 && a[i+2]>1)
            { a[i]-=2; a[i+1]-=2; a[i+2]-=2;}
            
            
        }
        
    }   
    int sum=0;
    for(i=0; i<20 ; i++)
        sum+=a[i];
   
    return sum;//sum==0,胡牌
}


int main()
{
   
    int min, MIN,b[20]={0}, a[20], i,j,flat2=0;
   
    bool endw;
    int pai_source[20]={1,2,3,2,7,10,11,12,13,12,12,20,17,17,20,17,15};//手上的原牌(牌数%3==2)
   
    for( i=0 ; i<20; i++)//統計每張牌的個數
        
        b[pai_source[i]-1]++;
   
    for(i=0 ; i<20; i++)
        cout<<b[i]<<" /";
    cout<<endl;
   
    for( j=0; j<20; j++)   //試探增加每張牌,看否能和其他組合成一句話                           
                             
//或三個相同的數,或2,7,10的组合。
    {
        for(i=0;i<20; i++)//更新牌
            a[i]=b[i];
        
        
        a[j]++;
        min=a[1]<a[6]? a[1]:a[6];
        min=min<a[9]? min:a[9];//求小字中二,七,十中最小的那個數

        MIN=a[11]<a[16]? a[11]:a[16];
        MIN=MIN<a[19]?MIN:a[19];      //求大字中二,七,十中最小的那個數
   
        int a1[20]={0};
        for(i=0; i<20; i++)//保存增加的牌的某种情况。
            a1[i]=a[i];
        
        for(int l=0; l<=min ; l++)// 以便處理考慮小字2 7 10 的情況。
            
        {
            for(i=0; i<20; i++)
                a[i]=a1[i];
            switch(l)
            {
            case  1 :     a[1]--; a[6]--; a[9]--;break;//2,7,10减一
            case  2 :    a[1]-=2; a[6]-=2; a[9]-=2;break;   
            default  :break;
            }

            int a2[20]={0};
            for(i=0; i<20; i++)
                a2[i]=a[i];
            
            for(int t=0; t<=MIN ; t++)
            {
               
                for(i=0; i<20; i++)
                    a[i]=a2[i];
               
                switch(t)
                {
                case  1 :     a[11]--; a[16]--; a[19]--;break;//大字2,7,10减一
                case  2 :    a[11]-=2; a[16]-=2; a[19]-=2;break;
                                                               
                default  :break;
                }
               
                if(  _del(a)==0 )
                {flat2=1;goto endw;}                                
            }                        
        }               
    }        
endw:
   
    if(flat2) cout<<"ok!"<<endl;
    else cout<<"no!"<<endl;
    return 0;
}
9 回复
#2
wp2319572013-04-07 10:57
楼主厉害
#3
wp2319572013-04-07 10:58
顺便问一下  你咋用的繁体字呢
#4
qunxingw2013-04-07 11:04
是公司里存的
#5
qunxingw2013-04-07 11:07
2,7,10的情况费了我很多心思,希望讨论下有没有其他好的方法
#6
zhangfudong2013-04-08 07:50
我们这叫“跑胡子”
#7
zhangfudong2013-04-08 07:51
我不会“算西”
#8
azzbcc2013-04-08 08:58
木看懂
#9
qunxingw2013-04-08 09:17
二七十的问题,如果玩过类似牌可知道,要胡牌要分情况讨论,不考虑二七十,考虑一个,考虑二个,又分大,小字,所以统一考虑会最多有九种情况,所以用二个循环。每次处理不成功时需要恢复到处理前状况。
#10
yuccn2013-04-08 12:13
不错,
1