麻将的小程序 2006-07-18

  期末考试期间,看见某网站有这么一道编程的题目,说是要做一个判断是否胡牌的程序.

  我挺喜欢麻将的,虽然很少打,但也会想做一个麻将的程序.故此先研究一下其中的算法吧.

  题目基本是这样的,编写一个判断是否能胡牌的程序,各种牌分别是

条子是 0x01到0x09
筒子是 0x11到0x19
万子是 0x21到0x29
东南西北分别是0x30,0x40,0x50,0x60
中发白分别是0x70,0x80,0x90
百搭牌是0x00

 其中百搭就是我们常说的"卉儿",万能牌.同时,这里有条规则,白板要代替成为百搭牌的那种牌.(咱也不知道是哪个非洲国家的玩法...)

 我的基本思路很简单,一般的回溯算法,首先寻找对子,再找三个的顺或刻,如果其中一步一旦寻找不到,就回溯到重新执行上一步的更正,知道某一种搭配方式可以达到即中断或者到最后都没有合适的即结束.

 这里有两个问题,一是中途判断是否为顺或者刻及其相应工作很复杂,特别是当以一个百搭为基准(指有了此牌后找相应的两个其他牌)进行寻找时更是无从下手,我于是便先用快速排序把牌进行从大到小的排列.这样一来不但百搭永远不可能成为基准牌,而且对顺或刻的寻找也方便了很多.真是一举多得.

还有就是此例仍然使用了很多变量和数组,我定义数组b来作为一个类似回溯时候的栈,k作为控制,一旦本次寻找失败,好能找到上次的数据,再此基础修改重做.还有c标志位.可读性仍然是这么差.

程序如下:

#include
#include
#define N 14
int b[50],c[50];
int check(int a,int b,int c){//检验的函数,检验顺子和刻子,但不考虑其分类,  
                          //所以使用时候要结合Class
 int flag=0;
 if((a==29||b==29||c==29)&&(a==30||b==30||c==30)) flag=0; //29和30是个特殊情况,虽然只相差1
 //但并不存在顺的可能,故只要同时存在九万和东风即不可能合格
 else if(c==0) flag=1;//有百搭的情况,因为abc按降序排列,a与b之差又小于1,故只要存在百搭即为合格
 else if(a==b&&b==c) flag=1;//刻子情况
 else if(a-b==1&&b-c==1) flag=1; //顺子情况
  
 return flag;
}

int find(int a[],int length,int j,int &k){//寻找刻或顺,i为长度
 int t,s;
 if(b[k]!=-1){c[b[k]]=0; c[b[k+1]]=0; c[b[k+2]]=0;}//如果是重选,则解除锁定
 for(b[k]!=-1?t=b[k+1]:t=j+1;t  if(c[t]!=1&&a[j]-a[t]<=1){
   for(b[k]!=-1?s=b[k+2]+1:s=t+1;s    if(c[s]!=1&&check(a[j],a[t],a[s])==1){
     b[k++]=j;b[k++]=t;b[k++]=s;       //添入简陋栈内
     c[j]=1;c[t]=1;c[s]=1;             //锁定
     return 1;
    }
   }
  }
 }
 if(b[k]!=-1){
  b[k]=-1;b[k+1]=-1;b[k+2]=-1;
 }
 k=k-3;
 return 0;
}

int Partition(int a[],int p,int r){     
 int i=p;
 int j=r+1;
 int temp;
 int x=a[p];
 while(true){
  while(a[++i]>x);
  while(a[--j]  if(i>=j) break;
  temp=a[i];
  a[i]=a[j];
  a[j]=temp;
 }
 a[p]=a[j];
 a[j]=x;
 return j;
}

void QuickSort(int a[],int p,int r){    //快速排序
 if(p  int q=Partition(a,p,r);
  QuickSort(a,p,q-1);
  QuickSort(a,q+1,r);
 }
}

int Hu(int a[],int length,int baida){
 int i,j,m,k,n,count=0,flag=0,leg;
 if((length-2)/3*3 for(i=0;i  if(a[i]==baida){
   a[i]=0;
   count++;
  }
  else if(a[i]==90)
   a[i]=baida;
 }
 for(i=0;i QuickSort(a,0,length-1);

 for(i=0;i  if(c[i]==0){
   j=i+1;
   c[i]=1;
   while(j               //省写力气
    if(c[j]==0&&(a[i]==a[j]||a[j]==0)){
        flag=k=0;
     c[j]=1;
     leg=0;
     for(m=0;m      n=k;
      if(c[m]==0&&find(a,length,m,k)==0){
       if(k<0) break;
       else {
        m--;
        leg--;
       }
      }
      else if(n       leg++;
       if(leg==(length-2)/3) return 1;//胡牌
      }
                                
     }
     c[j]=0;
    }
    if(j     j=length-count+1;
    else j++;
    
   }
   c[i]=0;
  }
 }
 return 0;   //不能胡牌
}

int main(){
 int k=0;
 int mj[N]={28,29,27,1,2,3,2,3,4,4,90,23,23,24};
 printf("%d/n",Hu(mj,N,4));
 for(int i=0;i return 0;
}

正如上面所说,由于使用了排序,本身寻找的时间大大缩短了.特别是寻找对的时候.但我并没有修改寻找顺刻的程序,其中还存在很多没必要的步骤.我想留到以后再写了.

这程序基本经过一些数据的测试,但,测试麻将这工作好象比一般数据对人的难度要高...故暂且作罢.大家谁测试出有错误也请告知.

 

你可能感兴趣的:(算法,c,测试,算法,工作,class,编程)