你有没有想过,自己动手写一个可以判断“麻将胡了”的程序?这不是科幻小说,而是完全可以用代码实现的现实项目,在自媒体时代,越来越多的人喜欢用技术解决生活中的小问题——朋友聚会时打麻将,有人总说“我胡了”,但别人却怀疑他是不是真的胡了?这时候,如果你能用一段代码快速验证是否符合胡牌规则,那岂不是既专业又有趣?
今天我就带你从零开始,用Python写一个简易版的“麻将胡了”判断程序,整个过程不复杂,但能帮你理解算法设计、数据结构和逻辑思维的结合,特别适合想入门编程或对游戏开发感兴趣的小伙伴。
我们先明确一下什么是“胡牌”,在标准麻将中(以国标麻将为例),一副完整的牌局必须满足以下条件:
我们的目标就是:输入13张牌,输出是否“胡了”。
第一步:定义数据结构
我们用字符串表示每一张牌,3万”、“红中”、“东”等,为了方便处理,我们可以把牌分两类:
我们用列表来存储玩家手中的13张牌,["3万", "3万", "3万", "4万", "5万", "6万", "7筒", "7筒", "7筒", "东", "东", "红中", "红中"]
第二步:编写核心函数 —— 判断是否胡牌
这是一个递归+回溯的问题,思路是:尝试从当前手牌中找出一组合法组合(顺子或刻子),然后递归处理剩下的牌,直到所有牌都被分配完。
我们先写一个辅助函数,用来判断某张牌是否能组成顺子或刻子:
def is_valid_group(cards, group_type):
# group_type: 'sequence' 或 'triplet'
if group_type == 'triplet':
return len(set(cards)) == 1 and len(cards) == 3
elif group_type == 'sequence':
sorted_cards = sorted(cards)
return len(sorted_cards) == 3 and \
sorted_cards[0] + 1 == sorted_cards[1] and \
sorted_cards[1] + 1 == sorted_cards[2]
接下来是主函数 can_win(hand):
def can_win(hand):
if not hand:
return True # 所有牌都已匹配完
# 先尝试找一对将牌(眼)
for i in range(len(hand)):
for j in range(i + 1, len(hand)):
if hand[i] == hand[j]:
remaining = hand[:i] + hand[i+1:j] + hand[j+1:]
if can_win(remaining):
return True
# 如果没找到将牌,说明这手牌无法胡
return False
等等,这个还不够!因为我们还没考虑顺子和刻子的组合,我们需要更系统地枚举所有可能的分组方式。
我们引入一个更完整的版本:
def check_hu(hand):
from collections import Counter
count = Counter(hand)
# 尝试每一种可能的将牌(眼)
for card in count:
if count[card] >= 2:
new_count = count.copy()
new_count[card] -= 2
if not any(new_count.values()):
return True # 真正的“对对胡”
# 尝试从剩余牌中构建三组顺子或刻子
if can_form_groups(new_count):
return True
return False
def can_form_groups(count):
if not any(count.values()):
return True
# 优先处理刻子(更容易匹配)
for card in list(count.keys()):
if count[card] >= 3:
count[card] -= 3
if can_form_groups(count):
return True
count[card] += 3
# 处理顺子(按花色分组处理)
suits = {'万': [], '筒': [], '条': []}
for card in count:
if card.endswith('万'):
suits['万'].append(int(card[:-1]))
elif card.endswith('筒'):
suits['筒'].append(int(card[:-1]))
elif card.endswith('条'):
suits['条'].append(int(card[:-1]))
for suit in suits:
cards = sorted(suits[suit])
i = 0
while i < len(cards):
if cards[i] > 7:
break
# 尝试组成顺子:i, i+1, i+2
if i + 2 < len(cards) and cards[i] + 1 == cards[i+1] and cards[i+1] + 1 == cards[i+2]:
count[f"{cards[i]}{suit}"] -= 1
count[f"{cards[i+1]}{suit}"] -= 1
count[f"{cards[i+2]}{suit}"] -= 1
if can_form_groups(count):
return True
count[f"{cards[i]}{suit}"] += 1
count[f"{cards[i+1]}{suit}"] += 1
count[f"{cards[i+2]}{suit}"] += 1
i += 1
return False
这段代码虽然略复杂,但逻辑清晰:它先找将牌,再从剩余牌中尝试构造顺子或刻子,直到全部匹配完成。
第三步:测试与优化
你可以这样测试你的程序:
hand = ["3万", "3万", "3万", "4万", "5万", "6万", "7筒", "7筒", "7筒", "东", "东", "红中", "红中"]
print("是否胡了?", check_hu(hand)) # 输出 True
你会发现,它确实能正确识别出这个牌型是合法的胡牌!
最后的小贴士:
通过这个项目,你不仅能学会Python基础语法和递归思想,还能体会到“把生活经验转化为代码逻辑”的乐趣,下次朋友打麻将时,你可以自豪地说:“别吵了,让我看看这手牌能不能胡!” —— 然后轻轻敲几行代码,答案立刻揭晓。
这就是自媒体作者的魅力:不仅教你知识,还让你边学边玩,真正把技术变成生活的一部分,快来试试吧!
