代码
import re
def check_win(cards):
complete = []
cards = sorted(cards)
for i in set(cards):
original_cards = cards.copy()
if cards.count(i) >= 2:
cards.remove(i)
cards.remove(i)
complete.append((i, i))
for j in range(int(len(cards)/3)):
if cards.count(cards[0]) >= 3:
complete.append((cards[0], cards[0], cards[0]))
cards = cards[3:]
elif cards[0] in cards and cards[0]+1 in cards and cards[0]+2 in cards:
complete.append((cards[0], cards[0]+1, cards[0]+2))
cards.remove(cards[0]+2)
cards.remove(cards[0]+1)
cards.remove(cards[0])
if len(complete) == 5:
return complete
else:
cards = original_cards
complete = []
def data_transf(cards):
m = list(map(int, ''.join(re.findall(r'\d+(?=m)', cards))))
p = list(map(str, ''.join(re.findall(r'\d+(?=p)', cards))))
for i in range(len(p)):
p[i] = int('2' + p[i])
s = list(map(str, ''.join(re.findall(r'\d+(?=s)', cards))))
for i in range(len(s)):
s[i] = int('4' + s[i])
z = list(map(str, ''.join(re.findall(r'\d+(?=z)', cards))))
for i in range(len(z)):
z[i] = int('2' + z[i]) * 3
return m + p + s + z
cards = '1336p243m2p4578p77z' #1-9:m 21-29:p 41-49:s 63 66 69 72 75 78 81:z
print(check_win(data_transf(cards)))
算法思路
输入格式为了顺应人的习惯,使用正则表达式进行了处理。将数据转换为不同的数字,每个花色之间空出了足够的距离来防止判断顺子干扰(以及未来可能的牌理(向听,进张数)判断)。
转换数据后,将所有数字代码相加组成列表cards
,目标是将列表中零散的数字组成一个个元组(即麻将的将、刻字、顺子)的列表complete
返回。通过set
去重,遍历每一种列表的数字代码,若大于等于2个就认为对子提取成功,开始分析剩下的3n张牌怎样组成面子。
就像判断清一色的听牌一样,从边上抽取面子是最好的选择,这里也是如此。通过思考可以发现,例如333456这样的牌,如果先抽顺子就会留下336这样的无解形状,而先提取刻子就不会发生这样的情况。按照刻子->顺子的顺序循环n次,即可处理完手牌。
不能忘记的是,因为使用remove
方法,需要将原始数据备份original_cards
,以便下次循环使用。
还有一些后续需要改进的地方,之后再写。
结果展示
乱序的普通手牌
九莲也可以