胡牌高手

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了胡牌高手相关的知识,希望对你有一定的参考价值。

技术分享

   玩过麻将 龙虎榜的人应该很熟悉这个画面,一般三连庄之后,会有个小游戏。这个游戏叫胡牌高手,就是给你十三张牌,都是清一色的万子,筒子或者条子,找出胡的那几张牌。

   我的电玩生涯中,有几个游戏一直陪伴着我,街霸,双截龙,拳皇,快打三和龙虎榜,也叫搓牌高手。其他的游戏起起落落,一段时间过去,都从各大游戏室里面消失,当然搓牌高手最后也不能幸免,但是它的时间跨度是其他游戏所不能比的。最早玩的游戏应该数名将,那个瘦的像芦材棒的选手是大家的最爱,那一招死的玩法是永远的经典,也是早期街机的著名bug。当时,格斗技能不行,和电脑玩玩还凑和,和人玩,心理素质极不过关,后来混久了,慢慢习惯了,成了菜鸟专杀。至今记得在烟雾缭绕的游戏室里面,一叠铜币,偶尔叼根同学给的烟,全神贯注的操作着方向杆,狠狠的按下游戏键,那是有钱的时候,没钱的时候,只能在旁欣赏着别人的表演,一面揣摩着如果是自己在操作会如何如何。那是我人生最堕落的时光,也是我人生最快乐的时候。小学五年,初中三年,快乐的背后,也为我的未来生活留下不少问题,但是年少怎能不轻狂呢,过去要省视,重要的是活在当下。

   麻将的规则挺多,除去特殊的牌型如十三幺,七对子等等,n*AAA+m*ABC+DD 是万变不离其宗的胡牌牌型。这里不研究通用的麻将胡牌算法,它比较啰嗦, 只考虑游戏里的这种情形。清一色的牌型。

  选出一张备选的牌型进入牌局,凑成14张牌 ,对十四张牌进行分解,12张牌和对子2张对子。

  对12张牌进行分解,将其分解为n*AAA+m*ABC的形式,如果分解成功,那么即为胡牌,否则失败。对于这十二张牌,每次从最左边的牌入手,该牌无非为顺子(ABC)或者刻(AAA),分别进行枚举,若匹配成功,将剩余的九张牌进行递归分解,方法同上。若失败则返回。

 

程序清单

#include <stdio.h>

#define INPUT_SIZE 13

int input[INPUT_SIZE] = {2,3,4,4,4,4,5,6,7,7,8,8,9};    
//int input[INPUT_SIZE] = {1,2,2,4,4,5,5,6,6,7,7,8,8};     
//int input[INPUT_SIZE] = {1,1,1,2,3,4,5,6,7,8,9,9,9}; //九莲宝灯     
int data[9] = {0};

void getdata(int *in,int *out)// 将输入数据转换为累加数据    
{     
   int i;     
   for(i=0;i<INPUT_SIZE;i++)  out[in[i]-1]++;     
}     
int markshunzi(int *dt,int i,int d)//顺子匹配,d=-1表示选择操作,1表示回滚     
{     
    if(i>=7) return -1;

    if(d==-1)    
    {     
        if(dt[i]==0||dt[i+1]==0||dt[i+2]==0) return -1;

    }    
    dt[i]+=d;     
    dt[i+1]+=d;     
    dt[i+2]+=d;     
    return 0;     
}     
int markke(int *dt,int i,int d)//d的意义同上     
{

    dt[i] += 3*d;    
    if(dt[i]>=0&&dt[i]<=4)  return 0;     
    dt[i] -= 3*d;     
    return -1;

}    
int check3pattern(int *dt,int total) //进行顺子或者刻的搜索过程     
{     
    int i,j ;     
    if(total==12) return 0;     
    for(i=0;i<9;i++)     
    {     
        if(dt[i]==0) continue;  
        if(markke(dt,i,-1)==0)     
        {     
            total+=3;     
            j = check3pattern(dt,total);    
            total-=3;     
            markke(dt,i,1);     
            if(j==0)     
            {     
                printf("%d,%d,%d \n",i+1,i+1,i+1);     
                return 0;     
            };

        }    
        if(markshunzi(dt,i,-1)==0)     
        {     
            total+=3;     
            j =check3pattern(dt,total);            
            total-=3;     
            markshunzi(dt,i,1);     
            if(j==0)     
            {     
                printf("%d,%d,%d \n",i+1,i+2,i+3);     
                return 0;     
            }

        }    
        if(j!=0) return -1;     
    }     
    return -1;     
}     
int is_hupai(int *dt)     
{     
     int i,left = 0,rst; //对子的左边张数,对子的右边张数     
      for(i=0;i<9;i++)   //是否为7对子     
     {     
         if(dt[i]%2!=0)   
         {     
             break;     
         }     
     }     
     if(i==9)     
     {     
         printf("七对子 \n");     
         return 0;  //符合7对子牌型     
     }     
     for(i=0;i<9;i++)     
     {             
         if((dt[i]==2&&left%3==0)||dt[i]>2) //做一些剪枝     
         {     
             dt[i]-=2;     
             rst = check3pattern(dt,0);     
             dt[i]+=2;     
             if(rst==0)     
             {     
                 printf("门对:%d,%d \n",i+1,i+1);     
                 return 0;     
             }     
         }             
         left+=dt[i];     
     }     
     return -1;     
}

void main()    
{     
   int i;     
   getdata(input,data);     
   for(i=0;i<9;i++)     
   {     
        if(data[i]>=4)     
        {     
            printf("%d萬已经超过4张牌,不能加入%d 萬\n",i+1,i+1);     
            continue;     
        }     
        data[i]++;      
       if(is_hupai(data)==0)     
       {     
           printf("胡 %d 萬 \n",i+1);     
       }     
       else     
       {     
           printf("不胡 %d 萬 \n",i+1);     
       }

        data[i]--;    
   }

}