近来正在做麻将游戏,写了个判断听牌的算法(暂且称其为算法),和大家分享一下,
算法还没通过全面的验证,可能会遗漏某些情况。(我不太会打麻将阿)
其中判断和牌算法的程序代码是网上找的,是听牌算法的基石。在这感谢这位仁兄了。
1、在介绍算法之前,先说说我的牌值顺序:
0-8 : 1-9万
9-17 : 1-9筒
18-26: 1-9条
27-30: 东南西北风
31-33: 中发白
无花
2、MaJiang3.java 是判断可否听牌的程序
(1)、判断点:当玩家抓进一张牌后(14张),系统判断出这时候打出某些牌后就听牌了
(2)、思想:检查将某个牌替换成另一个牌后能不能和(不考虑番种),能和就表示能听
3、MaJiang2.java 是判断某一手牌是否能和的程序
还是看代码吧,我在程序里加了些注释:
import java.util.*;
public class MaJiang3

...{

/**//*
先拿掉一个,然后再检测缺少什么,补上,这里不行,就补别的地方
*/
public ArrayList entryList = new ArrayList(); //替换对子
private int fmaj = -1; //可以打掉的牌
private int tmaj = -1; //可以补上的牌

int[] w=...{3,1,1,1,2,1,1,1,3}; //1-9万各个牌的个数

int[] to=...{0,0,0,0,0,0,0,0,0};

int[] ti=...{0,0,0,0,0,0,0,0,0};

int[] z=...{0,0,0,0,0,0,0};
public MaJiang3(int[] w, int[] to, int[] ti, int[] z)

...{
this.w = w;
this.to = to;
this.ti = ti;
this.z = z;
}
private void ting()

...{
for(int i = 0; i < 34; i++)

...{
boolean exeIT = false;
if((i < 9 && w[i] >0) )

...{
w[i]--;
fmaj = i;
if(!check())

...{ w[i]++;continue;}
w[i]++;
}
else if(i >=9 && i < 18 && to[i-9] >0)

...{
to[i-9]--;
fmaj = i;
if(!check())

...{ to[i-9]++;continue;}
to[i-9]++;
}
else if(i >=18 && i <27 && ti[i-18] >0)

...{
ti[i-18]--;
fmaj = i;
if(!check())

...{ ti[i-18]++;continue;}
ti[i-18]++;
}
else if((i >= 27 && z[i-27] >0))

...{
z[i-27] = z[i-27] -1;
fmaj = i;
if(!check())

...{ z[i-27]++;continue;}
z[i-27]++;
}
}
}

private boolean check()

...{
boolean res = true;
res = checkZi(z, 27); //如果字牌不符合条件,就不用检查序数牌了
checkNum(w, 0);
checkNum(to, 9);
checkNum(ti, 18);
return res;
}
//检查字:因为字和序数牌不同,单独拿出来
private boolean checkZi(int[] hua, int beginLoc)

...{
//判断字
boolean checkjiang = false;
for(int i = 0; i < hua.length; i++)

...{
if(beginLoc + i == fmaj) continue;
if(hua[i] == 2)

...{
hua[i]++;
if(hu(w,to,ti,z))

...{
tmaj = beginLoc+i;
print();
entryList.add(new Entry(fmaj, tmaj));
}
else

...{
if(!checkjiang)

...{
checkjiang = true;
}
else

...{
hua[i]--;
return false;//不用往下匹对了,
}
}
hua[i]--;
}
else if(hua[i] == 1)

...{
hua[i]++;
if(hu(w,to,ti,z))

...{
tmaj = beginLoc+i;
print();
entryList.add(new Entry(fmaj, tmaj));
}
else

...{
hua[i]--;
return false;//不用往下匹对了
}
hua[i]--;
}
}
return true;
}
private void checkNum(int[] hua, int beginLoc)

...{
boolean[] hasreplace = new boolean[9]; //检查是否已经替换过
for (int i=0;i<hua.length ;i++ )

...{
if(beginLoc + i == fmaj) continue;
if((i == 0 || hua[i] >0) && !hasreplace[i])

...{
hua[i]++;
hasreplace[i] = true;
if(hu(w,to,ti,z))

...{
tmaj = beginLoc+i;
entryList.add(new Entry(fmaj, tmaj));
}
hua[i]--;
//替换成i前面的那张牌
if(i > 0 && i < 9 && !hasreplace[i-1])

...{
hua[i-1]++;
hasreplace[i-1] = true;
if(hu(w,to,ti,z))

...{
tmaj = beginLoc + i - 1;
entryList.add(new Entry(fmaj, tmaj));
}
hua[i-1]--;
}
//替换成i前面的那张牌
if(i > 0 && i < 8 && !hasreplace[i+1])

...{
hua[i+1]++;
hasreplace[i+1] = true;
if(hu(w,to,ti,z))

...{
tmaj = beginLoc + i + 1;
entryList.add(new Entry(fmaj, tmaj));
}
hua[i+1]--;
}
}
}
}
public boolean hu(int[] aWan,int[] aTong,int[] aTiao,int[] aZi)

...{
int[] tempWang = new int[aWan.length];
int[] tempTong = new int[aTong.length];
int[] tempTiao = new int[aTiao.length];
int[] tempZi = new int[aZi.length];
System.arraycopy(aWan, 0, tempWang, 0, aWan.length);
System.arraycopy(aTong, 0, tempTong, 0, aTong.length);
System.arraycopy(aTiao, 0, tempTiao, 0, aTiao.length);
System.arraycopy(aZi, 0, tempZi, 0, aZi.length);
boolean res = new MaJiang2().Hu(tempWang, tempTong, tempTiao, tempZi);
return res;
}
private void print()

...{
System.out.print("w = ");
for(int i = 0; i < w.length; i++)

...{
System.out.print(w[i] + ", ");
}
System.out.println();
System.out.print("to = ");
for(int i = 0; i < to.length; i++)

...{
System.out.print(to[i] + ", ");
}
System.out.println();
System.out.print("ti = ");
for(int i = 0; i < ti.length; i++)

...{
System.out.print(ti[i] + ", ");
}
System.out.println();
System.out.print("z = ");
for(int i = 0; i < z.length; i++)

...{
System.out.print(z[i] + ", ");
}
System.out.println();
}
public static void main(String[] args)

...{

int[] w=...{0,0,0,0,0,0,0,1,1};

int[] to=...{0,0,0,0,1,1,1,0,0};

int[] ti=...{0,1,0,2,0,0,0,0,0};

int[] z=...{0,0,0,0,0,0,0};
MaJiang3 mj=new MaJiang3(w,to,ti,z);
mj.ting();
System.out.println(mj.entryList);
}
class Entry

...{
public int fmaj;
public int tmaj;
public Entry(int fmaj, int tmaj)

...{
this.fmaj = fmaj;
this.tmaj = tmaj;
}
public void setFmaj(int fmaj)

...{
this.fmaj = fmaj;
}
public void setTmaj(int tmaj)

...{
this.tmaj = tmaj;
}
public String toString()

...{
return "(" + fmaj + ", " + tmaj + ")";
}
}
}

这个是判断和牌的算法, 来自网络.
public class MaJiang2

...{
private boolean jiang=false;//是否找到将

public MaJiang2()...{}

//花色,判断这个花色是否被减完了(如果没有减完自然没有和)

private int huase(int[] hua)

...{
if (hua.length==7)

...{
//判断字,自比较特殊,没有顺
for (int i=0;i<hua.length ;i++ )

...{
if (hua[i]==3||hua[i]==4)

...{
hua[i]=0;
huase(hua);
}
//如果字有两个,肯定是将
if (hua[i]==2&&!jiang)

...{
hua[i]=0;
jiang=true;
huase(hua);
}
}
}
else

...{
for (int i=0;i<hua.length ;i++ )

...{
//如果没有将,先把将减出去
if (!jiang&&hua[i]>=2)

...{
hua[i]=hua[i]-2;
jiang=true;
int fanhui=huase(hua);
//如果递归回来依旧没有减完,则把将加回去
if (fanhui!=0)

...{
hua[i]=hua[i]+2;
jiang=false;
}
}
if (hua[i]!=0&&i<7&&hua[i+1]!=0&&hua[i+2]!=0)

...{
hua[i]--;
hua[i+1]--;
hua[i+2]--;
huase(hua);
int fanhui=huase(hua);
//如果递归回来依旧没有减完,减去的加回去
if (fanhui!=0)

...{
hua[i]++;
hua[i+1]++;
hua[i+2]++;
}
}
if (hua[i]==3||hua[i]==4)

...{
int temp=hua[i];
hua[i]=0;
huase(hua);
int fanhui=huase(hua);
//如果递归回来依旧没有减完,减去的加回去
if (fanhui!=0)

...{
hua[i]++;
hua[i]=temp;
}
}
}
}
int re=0;
//最后判断减没减完
for (int i=0;i<hua.length ;i++ )

...{
re=re+hua[i];
}
return re;
}


public boolean Hu(int[] aWan,int[] aTong,int[] aTiao,int[] aZi)//aTiao

...{
if(huase(aZi) == 0 && huase(aWan) == 0
&& huase(aTong) == 0 && huase(aTiao) == 0 && jiang)

...{
return true;
}
else

...{
return false;
}
}
public static void main(String[] args)

...{
MaJiang2 mj=new MaJiang2();

int[] w=...{0,0,0,0,0,0,1,1,1};

int[] to=...{0,0,0,0,1,1,1,0,0};

int[] ti=...{0,0,0,2,0,0,0,0,0};

int[] z=...{0,0,0,0,0,0,0};
long beginTime = System.currentTimeMillis();
mj.Hu(w,to,ti,z);
long endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - beginTime));
}
}
