你有没有想过,打麻将时那句“我胡了!”背后其实藏着一套精妙的算法?我就带你用Python实现一个“麻将胡了”的判断程序——不光能帮你理解游戏规则,还能提升你的编程思维和逻辑能力,无论你是初学者还是有一定基础的开发者,这篇文章都能让你收获满满。
先说清楚目标:我们要写的不是一个完整的麻将游戏,而是一个能判断玩家是否“胡牌”的函数,也就是说,输入一组麻将牌(比如123456789万、筒、条),程序能自动判断这组牌是否符合胡牌条件。
麻将胡牌的基本规则是什么?一张标准的麻将手牌有13张牌,必须由4组顺子或刻子(三张相同)+1对将(两张相同)组成,举个例子:
- 123万 + 456筒 + 789条 + 11条 + 22筒(这是胡牌)
- 如果多了一张,或者少了一对,就不算胡。
现在我们来一步步实现这个程序:
第一步:数据结构设计
我们把每张牌表示为字符串,1万”、“5筒”、“9条”,这样便于处理,为了提高效率,我们可以用字典统计每种牌的数量,"1万": 3, "2筒": 2, ...}。
第二步:检查是否有“对子”(将)
遍历所有牌,找到数量为2的牌作为将,如果没找到,直接返回False,注意:如果有多个对子,只能选一个当将,其他必须是顺子或刻子。
第三步:移除将后,剩下的11张牌必须能被分成3组完整组合(顺子或刻子),这里就要用递归+回溯的思想了。
- 刻子:同一牌出现3次(如“1万”×3)
- 顺子:连续三张同花色的牌(如“1万2万3万”)
关键点来了:如何高效地枚举所有可能的组合?我们写一个辅助函数,不断尝试从剩余牌中找出一个刻子或顺子,然后递归处理剩下的牌,如果最后能把全部牌分完,说明胡牌成功!
第四步:优化与边界处理
- 去重:避免重复计算同一组牌的不同排列
- 异常处理:确保输入合法(如牌数不是13张)
- 性能优化:用缓存减少重复计算
下面是核心代码片段(简化版):
def is_win(hand):
from collections import Counter
count = Counter(hand)
# 找到任意一对作为将
pairs = [k for k, v in count.items() if v >= 2]
for pair in pairs:
new_count = count.copy()
new_count[pair] -= 2
if not any(new_count.values()):
continue # 这种情况不可能存在,因为只剩11张
if can_split(new_count):
return True
return False
def can_split(count):
if not any(count.values()):
return True
for card in count:
if count[card] == 0:
continue
# 尝试刻子
if count[card] >= 3:
new_count = count.copy()
new_count[card] -= 3
if can_split(new_count):
return True
# 尝试顺子(需检查花色一致)
# 简化版本,实际要区分花色和数字
# ...(此处省略具体顺子判断逻辑)
这个程序虽然简单,但体现了编程中的经典思想:分解问题、递归求解、状态管理,它不仅适用于麻将,还能迁移到其他组合类问题,比如数独、拼图等。
我想说的是:学编程不是为了做游戏,而是培养解决问题的能力,当你能用代码模拟现实世界里的规则时,你就真正掌握了“抽象”这个技能。
下次朋友打麻将时,你可以自信地说:“别急,让我帮你看看能不能胡!”——然后掏出手机运行你的程序 😄
快动手试试吧,让代码替你喊出那句“我胡了!”







