从零开始教你写一个“麻将胡了”程序:用代码还原中国人的牌桌智慧
你有没有想过,为什么在街边茶馆、家庭聚会甚至手机App里,麻将总是那么受欢迎?它不仅是娱乐,更是一种融合策略、概率和心理博弈的复杂游戏,我作为一位自媒体作者,带你走进编程的世界,用Python手把手教你写一个“麻将胡了”的判断程序——不是模拟打牌,而是真正理解“胡牌”背后的逻辑!
我们要明确什么是“胡牌”,在标准麻将中,一副牌由13张牌组成,玩家通过摸牌或吃碰杠后凑成4组顺子或刻子+1对将牌(即“听牌”),就可以胡牌。“123万、456筒、789条、一对红中、一对白板”,这就是合法的胡牌组合。
我们用Python实现这个逻辑,先定义数据结构:
import itertools
# 为了简化,我们只处理万、筒、条三种花色(不含字牌)
def is_valid_hand(cards):
# 检查是否正好14张牌
if len(cards) != 14:
return False
# 将牌分组统计:每种花色单独处理
suits = {}
for card in cards:
suit = (card - 1) // 9 + 1 # 1=万, 2=筒, 3=条
rank = (card - 1) % 9 + 1 # 1~9
if suit not in suits:
suits[suit] = []
suits[suit].append(rank)
# 对每个花色分别检查是否能组成有效组合
for suit_cards in suits.values():
if not can_form_groups(suit_cards):
return False
# 检查是否有且仅有一对将牌(两个相同的数字)
pairs = [c for c in cards if cards.count(c) == 2]
if len(pairs) != 1:
return False
return True
def can_form_groups(cards):
# 排序便于处理
cards.sort()
# 使用递归穷举所有可能的分组方式(顺子/刻子)
def backtrack(hand, groups):
if not hand:
return True
# 尝试组成顺子(3连)
for i in range(len(hand)):
for j in range(i+1, len(hand)):
for k in range(j+1, len(hand)):
if hand[i] + 1 == hand[j] and hand[j] + 1 == hand[k]:
new_hand = hand[:i] + hand[i+1:j] + hand[j+1:k] + hand[k+1:]
if backtrack(new_hand, groups + [(hand[i], hand[j], hand[k])]):
return True
# 尝试组成刻子(三个相同)
for i in range(len(hand)):
if hand.count(hand[i]) >= 3:
new_hand = [x for x in hand if x != hand[i]]
if backtrack(new_hand, groups + [[hand[i]] * 3]):
return True
return False
return backtrack(cards, [])
这段代码的核心在于“回溯法”:尝试所有可能的组合方式,直到找到一种合法的胡牌结构,虽然效率不高(指数级复杂度),但非常适合教学演示。
举个例子:
输入:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13]
输出:True(说明这副牌可以胡!)
真实麻将还有更多规则,比如七对、十三幺、混一色等特殊牌型,这些都可以扩展为独立函数来处理。
写这个程序的意义不止是“让电脑能识牌”,更重要的是帮助我们理解麻将的本质:它是一种数学游戏,也是一种文化符号,当你用代码还原出“胡牌”的逻辑时,你会发现——原来那些看似玄乎的“听牌感觉”,其实都藏在排列组合之中。
如果你喜欢这种“编程+生活”的内容,请点赞关注,下期我会讲如何用AI预测对手出牌习惯,让你在牌桌上真正“赢麻了”!







