最近做的一个麻将里面有双鬼牌的玩法,即为8张鬼牌,第一反应是采用N重循环把鬼牌变成一张张牌去遍历是否能胡牌,实际测试在5张牌鬼牌的情况得出结果就需要差不多5,6分钟。
因此自己做了一套用凑牌的方式去判断胡牌,原理是尝试把手牌中的任意一张当做对子(将牌),如果不够两张则用鬼牌去补一张,最后再提取出对子,判断剩下的手牌组成横或者顺子需要多少鬼牌,如果大于剩余的鬼牌数量,则本次检查胡牌失败,把对子还原到手牌中,尝试提取下一个对子继续检测。
我这里的实现方式C++,逻辑并不复杂可以简单的转成lua
首先传入的参数分别是手牌的索引(已经去掉鬼牌),和手牌的数量,以及鬼牌的数量
手牌的索引实际上是一个size大小为34(因为麻将的牌除去重复的一共34张)的char数组HandCard,其中HandCard[i]中的i代表牌值(0-34分别为1-9万,1-9条,1-9筒,东南西北中发白按顺序排列),HandCard[i]的值为手牌中这个牌的数量
bool CheckCanHu(char const HandCard[MAX_INDEX], size_t HandCardSize,size_t GhostCount)
{
char TotalCount = HandCardSize + GhostCount;
if ((TotalCount - 2) % 3 != 0 || TotalCount > MAX_HANDCOUNT)
{
//牌数,不满足3n+2,或大于14张
return false;
}
//当该手牌中只有万能牌时
if (TotalCount == GhostCount)
{
return true;
}
char CardIndexTemp[MAX_INDEX];
memcpy(CardIndexTemp, HandCard, sizeof(CardIndexTemp));
std::vector<char> PairsInfo; //用于存放所有能构成胡牌的对子的值
char CheckZero = ((GhostCount < 2) ? 2 : 0);//(0-未检查 1-成功 2-失败 )
//1.把手牌中的每一张当做对子(将牌),然后检查余下的牌是否能达到胡牌条件(组成顺子或者横)
for (char i = 0; i < MAX_INDEX; ++i)
{
if (0 == CardIndexTemp[i])
{
//尝试检测一次鬼牌变成手牌里没有的牌
if (CheckZero == 0)
{
//CheckZero不为0说明检测过了 不再检测
GhostCount -= 2;
if