感觉网上关于麻将的源码资源很少,一般这种算法都是用递归,把牌堆分解成若干子牌堆然后针对2-3张牌的情形给出一个出口。
和牌算法比较常见,毕竟只要是麻将编程都要用到,后面两种虽然普通的麻将编程用不到,但是要编写AI对策以及某些特殊规则(例如日本麻将)就有用了,尤其一向听的算法。
三种算法原理差不多,都是先分析牌数较少的情形,然后牌数较多的情形通过牌堆分解后,对提取剩余牌堆调用自身。
本源码使用C++,分MDeck和MDeckExtract类。这两个类定义如下:
typedef int MTile;
class MDeck;
class MDeckExtract;
class MDeck
{
public:
MTile tile[200];
int length;
};
class MDeckExtract
{
public:
int methodCount;
MDeck extracted[10];
MDeck remained[10];
};
其中MDeck类实际上就是一个由MTile(int)组成的数组和牌堆长度,跟CArray类很像。
而MDeckExtract类则用于存储牌堆的提取结果。其中methodCount是提取方案的数目,extracted存储提取方案中可以提取的目标牌堆,remain则存储剩余牌堆。举个简单的例子:
例如一个牌堆为 3,3,4,5,6,若对其进行顺子提取操作,则MDeckExtract应该是这样的:
methodCount 为 2,即两种提取方案。
extracted[0]为3,4,5,remain[0]为3,6;extracted[1]为4,5,6,remain[1]为3,3。
接下来是提取方法(其中有的较为简单的方法的定义例如牌堆排序、创建不包含重复的牌的副本、牌堆连接、加入等方法就不帖进来了,很容易实现)的源码。
MDeckExtract MDeck::extractDuizi(){
sortTile();
int i = 0;
MDeck dr = removeRepeatedTile();
MDeck dt;
MDeck de;
MDeckExtract e;
MTile t;
for(i = 0;i<dr.length;i++){
t = dr.tile[i];
dt = (*this);
de.length = 0;
if(dt.countTile(t)>1){
dt.removeTile(t);
dt.removeTile(t);
de.pushTile(t);
de.pushTile(t);
e.extracted[e.methodCount] = de;
e.remained[e.methodCount] = dt;
e.methodCount ++;
}
}
return e;
}
MDeckExtract MDeck::extractShunzi(){
sortTile();
int i = 0;
MDeck dr = removeRepeatedTile();
MDeck dt;
MDeck de;
MDeckExtract e;
MTile t;
for(i = 0;i<dr.length;i++){
t = dr.tile[i];
dt = (*this);
de.length = 0;
if(dt.countTile(t+1)>0 &a