麻将胡牌算法实现——时间复杂度O(n*2)
本文有博主在一家棋牌公司写的胡牌算法总结,如果有错误的地方,欢迎矫正:
胡牌规则(不包括十三么)
- 牌的总数为3*sum+2
- 必须有一对对子
- 剩余的牌三三组合均能组合成顺子或者是刻子
国内某大神总结出的胡牌公式
n*AAA + m*ABC + DD = 胡牌 (n+m==sum)
这条公式很简单,但是在程序中应用的话就有一些疑惑了。究竟从何入手,有些疑惑。
定义列表
- 万字:MAHJ_W_1-MAHJ_W_9
- 筒子:MAHJ_T_1-MAHJ_T_9
- 条子:MAHJ_S_7-MAHJ_S_7
- 东南西北中发白:**-MAHJ_BAI
思路分析
这条公式最大的问题就是不知道对子究竟在哪个位置。
- 有可能独立在刻子和顺子之外的两章
- 有可能就隐藏在刻字中
所以博主在研究这问题的时候的切入点都是找出其中所有的顺子和对子,包括重复计算的情况:
1 1 1 2 3 4 5 6 7 8 9 10 11 12
其中刻子有一对:1
其中顺子有四对:123 456 789 101112
那么我们写出来的程序必须要满足n+m==sum或者n+m==sum+1才可以
代码块
如有问题,可以直接联系我扣扣:623702748,例如:
bool hu(unsigned short * arr, int len, unsigned short lastBoard)
{
unsigned short *mahj = arr;
int bmd = len + 1;
unsigned short board[60] = { 0 };
for (int i = 0; i < bmd; ++i)
{
++board[mahj[i]];
}
++board[lastBoard];
int n = (bmd - 2) / 3;
//开始检测
int cnt_kan = 0;
int cnt_sun = 0;
for (int ma = MAHJ_W_1; ma <= MAHJ_W_7;)
{
if (board[ma] && board[ma + 1] && board[ma + 2] && ma + 2 <= MAHJ_W_9)
{
cnt_sun++;
ma += 3;
}
else
{
ma++;
}
}
for (int ma = MAHJ_T_1; ma <= MAHJ_T_7;)
{
if (board[ma] && board[ma + 1] && board[ma + 2] && ma + 2 <= MAHJ_T_9)
{
cnt_sun++;
ma += 3;
}
else
{
ma++;
}
}
for (int ma = MAHJ_S_1; ma <= MAHJ_S_7;)
{
if (board[ma] && board[ma + 1] && board[ma + 2] && ma + 2 <= MAHJ_S_9)
{
cnt_sun++;
ma += 3;
}
else
{
ma++;
}
}
for (int ma = MAHJ_W_1; ma <= MAHJ_BAI; ++ma)
{
if (board[ma] >= 3)
{
cnt_kan++;
}
}
if (cnt_kan + cnt_sun == n)
{
//刚好相等就找眼
for (int ma = MAHJ_W_1; ma < MAHJ_BAI; ++ma)
{
if (board[ma] == 2)
return true;
}
}
else if (cnt_kan + cnt_sun == n + 1)
{
return true;
}
return false;
}
经过测试,大部分的配型,例如暗刻、门前清、平和、四归一、双同刻、双暗刻、断么九等都可以检测成功