姐姐:你去帮我和闺蜜打麻将?
学霸哥哥:可是我不会打麻将呀!
姐姐:你不是学霸吗?我教你一个麻将公式,我闺蜜可是单身哟!
学霸哥哥:什么公式?
姐姐:麻将胡牌公式: AAA*M+ABC*N+BB,WMN可以为任意数,胡牌里面有且只有一对!
学霸哥哥:原来麻将还可以这样玩。好的 地址微信发给我,马上到!
通过这个对话,我想大家应该都能明白麻将的胡牌公式是怎么样了,如果只是简单的麻将胡牌,我想算法实现起来就比较的简单。
第一步:
我们挑出所有的对子(如果牌中一个对子就没有,那么就不能胡牌)
第二步:
一次从牌里面去掉对子
第三步:
每次for循环跳3个数,看这3个数是否为ABC,AAA.如果都满足这样的条件,则这一副牌就可以胡牌。如果不满足这个条件,则没有胡牌。
这个我们用python实现算法就比较的简单,也比较的好理解。下面我们给出python的胡牌实现算法!这个里面多增加了一个7对的胡牌,大家可以看一下,看是否理解这个算法,也可以自己复制一下代码,跑一下看一下效果。
def hupaiAlgorithm(self,handStr):
a =handStr[:]
if len(a) % 3 != 2:
return False
double = []
for x in set(a):
if a.count(x) >= 2:
double.append(x)
if len(double) == 0:
return False
#7对胡牌
qidui = True
if len(a) == 14:
for x in set(a):
if a.count(x) not in [2, 4]:
qidui = False
break
else:
qidui = False
if qidui:
return True
a1 = a.copy()
a2 = []
for x in double:
a1.remove(x)
a1.remove(x)
a2.append((x, x))
for i in range(int(len(a1) / 3)):
if a1.count(a1[0]) == 3:
a2.append((a1[0],) * 3)
a1 = a1[3:]
elif a1[0] in a1 and a1[0] + 1 in a1 and a1[
0] + 2 in a1:
a2.append((a1[0], a1[0] + 1, a1[0] + 2))
a1.remove(a1[0] + 2)
a1.remove(a1[0] + 1)
a1.remove(a1[0])
else:
a1 = a.copy()
a2 = []
break
else:
return True
else:
return False
如果上面的胡牌算法理解了,那么恭喜你,你接下来就可以看一下带万能牌的四川麻将胡牌算法了!
最终的测试效果
首先我们来理解一下带万能牌的四川麻将如何才能胡牌,带完成牌的意思就是,万能牌可以代替任何一张麻将牌,只要最后的麻将能,满足那个公式就能胡牌。这个是重点,必须要理解这个重点,才能完成万能牌的胡牌算法!
我们结合上面正常麻将的胡牌思路,大家再想一想,如果正常牌不能胡牌,带万能牌能胡牌,是不是我们万能牌就只能代替下面3种情况才能胡牌:
我们看这手牌:112245777万能万能
1.当有2张牌不能成为ABC时,替换中间一张牌使牌成为ABC,比如45,万能牌变成345或者是456.
2.当牌中的对子>1,且不能满足7对胡牌的时候。万能牌代替牌中的任何一个对子,比如在我们举例的牌里面 万能牌就只能代替1或者是2.
通过我们2万能牌的替换:
这手牌就变成了下面这种情况
112245777万能万能=》11122345777.
我们通过这样的变化,是不是就可以胡牌了。
3.当牌中没有一个对子的时候,万能牌就只能替换成其中的某一张牌,成为一个对子看是否满足胡牌的公式。
比如:1234567万能
这点万能牌就可以替换成1,4,7其中的任何一张牌,使牌变成:1123456,12344567,12345677.
万能牌能替换的这3种方式,这点大家有没有理解,如果理解了,接下来我们就可以来讨论,具体的算法怎么实现了。如果没有理解的同学,可以反复观看几次,必须要先理解这3点的替换思路才能够更好的理解算法。(这点我们不讨论7对的特殊胡牌算法)。
还有一点就是万能牌使用的次数只能小于等于万能牌的数量,这点也很重要。
通过上面的讲解我们就能很好的实现算法了,我们只需要在正常的胡牌算法里面改动一下就能实现万能牌的胡牌算法了。大体思路还是按照正常的胡牌算法来,只是在需要使用万能牌的时候,我们替换一下万能牌,然后把万能牌的数量-1,最后看使用万能牌的数量使用超过了已有的万能牌数量。里面增加一个7对的万能牌胡牌算法!
def hupaiAlgorithm(self,handStr,laziCnt):
a =handStr[:]
a2=handStr[:]
if (len(a)+laziCnt) % 3 != 2:
return False,a2
double = []
if laziCnt >0:
for x in set(a):
if x not in double:
double.append(x)
for x in set(a):
if a.count(x) >= 2 and x not in double:
double.append(x)
if len(double) == 0:
# print('和牌失败:无对子')
return False,a2
if laziCnt == 0:
qidui = True
if len(a) == 14:
for x in set(a):
if a.count(x) not in [2, 4]:
qidui = False
break
else:
qidui = False
if qidui:
return True,a2
else:
for card in a:
cardArr=[[],[],[],[]]
for card in a:
iCnt = a.count(card)
# print("iCnt:",iCnt,"handCards:",a)
if card not in cardArr[iCnt-1]:
cardArr[iCnt-1].append(card)
if len(cardArr[0])+len(cardArr[2]) == laziCnt:
huCard=[]
for i in range(4):
if i==0:
huCard = huCard + cardArr[i]*2
else:
huCard = huCard + cardArr[i]*(i+1)
huCard.sort()
return True,huCard
a1 = a.copy()
a2 = [] # a2用来存放和牌后分组的结果。
for x in double:
if x in a1:
a1.remove(x)
if x in a1:
a1.remove(x)
a2.append((x, x))
nUseLaziCnt =0
index = 0
isNohuCard = False
while(len(a1)>0 and isNohuCard == False):
a1Card = a1[0]
if a1.count(a1Card)==3:
a2.append((a1Card,) * 3)
a1 = a1[3:]
elif a1Card in a1 and a1Card + 1 in a1 and a1Card + 2 in a1 and( int(a1Card/10) == int((a1Card+1)/10) and int((a1Card+1)/10) == int((a1Card+2)/10) ): # 这里注意,11,2222,33,和牌结果22,123,123,则连续的3个可能不是相邻的。
a2.append((a1Card, a1Card + 1, a1Card + 2))
a1.remove(a1Card + 2)
a1.remove(a1Card + 1)
a1.remove(a1Card)
elif((a1Card in a1 and a1Card+1 in a1 and (int(a1Card//10) == int((a1Card+1)//10))) or (a1Card in a1 and a1Card+2 in a1 and (int(a1Card//10) == int((a1Card+2)//10)) )) and (nUseLaziCnt<laziCnt):
a2.append((a1Card, a1Card + 1, a1Card + 2))
if a1Card in a1: a1.remove(a1Card)
if a1Card+1 in a1: a1.remove(a1Card + 1)
if a1Card+2 in a1: a1.remove(a1Card + 2)
nUseLaziCnt = nUseLaziCnt +1
elif a1.count(a1Card)==2 and (nUseLaziCnt<laziCnt):
a2.append((a1Card, a1Card, a1Card))
if a1Card in a1: a1.remove(a1Card)
if a1Card in a1: a1.remove(a1Card)
nUseLaziCnt = nUseLaziCnt +1
else:
if len(a1)==1 and (laziCnt -nUseLaziCnt) ==2 :
a2.append([a1Card]*3)
if a1Card in a1: a1.remove(a1Card)
else:
a1 = a.copy()
a2 = []
isNohuCard = True
if isNohuCard == False:
return True,a2
else:
return False,handStr
算法里面有一个7对的胡牌算法:
这里来讲解一下如何实现的。7对胡牌,最后胡牌里面就是 全是对子 或者有4条。有且只有这2种牌型。我们就很好实现了,我们定义一个多维数组,一次记录牌出现1,2,3,4张的情况。我们只需要把出现一张牌的数量和3张牌的数量相加。2则是否刚好等于万能麻将的数量就可以了。
for card in a:
cardArr=[[],[],[],[]]
for card in a:
iCnt = a.count(card)
# print("iCnt:",iCnt,"handCards:",a)
if card not in cardArr[iCnt-1]:
cardArr[iCnt-1].append(card)
if len(cardArr[0])+len(cardArr[2]) == laziCnt:
huCard=[]
for i in range(4):
if i==0:
huCard = huCard + cardArr[i]*2
else:
huCard = huCard + cardArr[i]*(i+1)
huCard.sort()
return True,huCard
你品,你细细品一下,看是不是这个道理。下面给大家看一个截图,带万能麻将的胡牌效率。
一个万能牌的情况,理论上4个万能和1个万能使用的时间差不多,都是毫秒级别的。如果这个四川万能麻将的胡牌算法,能满足一切的需求。
有了这个核心的胡万能牌算法,接下来得 听牌算法,是否胡万能的算法就很容易实现了!