测试

从零到一,手把手教你用Python写一个“麻将胡了”程序!

你有没有想过,为什么打麻将时总有人“听牌就胡”,而你却连“自摸”都等不来?这不仅是运气问题,更是算法逻辑的较量,我带你用Python写一个能自动判断“麻将胡了”的程序——不靠玄学,只靠代码!无论你是编程小白还是资深玩家,这篇文章都能让你看懂:怎么让电脑帮你算出“这把到底能不能胡”。

先说清楚什么叫“胡了”?在标准麻将规则中,胡牌必须满足两个条件:一是牌型结构合理(一般是4组顺子/刻子+1对将牌),二是不能有重复计算或遗漏组合。

  • 顺子:123筒、456万
  • 刻子:333条、777饼
  • 将牌:一对相同的牌,如88筒

我们的目标就是写一个函数,输入一组牌(1234456677899筒”),输出是否“胡了”。

第一步:数据预处理
我们先把输入的牌整理成数字列表,1234456677899筒”变成 [1,2,3,4,4,5,6,6,7,7,8,9,9],然后统计每种牌的数量(用字典记录):

from collections import Counter  
def is_hu(cards):  
    count = Counter(cards)  

这里的关键是“去重”和“分组”——比如两个4筒要合并为一个刻子,而不是当成两个独立的单张。

第二步:递归搜索所有可能的组合
核心思路是:尝试所有可能的顺子/刻子组合,直到剩下的牌正好是一对将牌,如果找到一种组合方式,就返回True。
我们写一个辅助函数 can_form_sets(count),它会:

  1. 找到最小的牌号(比如1筒),尝试把它作为顺子的第一张(123)、刻子(111)或单独存在(但单独存在只能用于将牌)。
  2. 如果是顺子:检查是否有1、2、3;如果有,就减掉这三个数,递归调用 can_form_sets
  3. 如果是刻子:检查是否有三个相同的牌;如果有,就减掉三个,递归调用。
  4. 如果都不是,说明当前牌无法形成有效组合,返回False。

第三步:处理将牌
当剩下两对相同牌时(比如两个7筒),它们可以作为将牌,这时,我们调用 can_form_sets 检查剩余牌是否能组成合法的三组顺子/刻子。

完整代码如下(简化版):

def is_hu(cards):  
    from collections import Counter  
    count = Counter(cards)  
    def can_form_sets(count):  
        if not count:  
            return True  
        # 找最小的牌号  
        min_card = min(count.keys())  
        # 尝试顺子:min_card, min_card+1, min_card+2  
        if count[min_card] > 0 and count.get(min_card+1, 0) > 0 and count.get(min_card+2, 0) > 0:  
            new_count = count.copy()  
            new_count[min_card] -= 1  
            new_count[min_card+1] -= 1  
            new_count[min_card+2] -= 1  
            if new_count[min_card] == 0:  
                del new_count[min_card]  
            if new_count[min_card+1] == 0:  
                del new_count[min_card+1]  
            if new_count[min_card+2] == 0:  
                del new_count[min_card+2]  
            if can_form_sets(new_count):  
                return True  
        # 尝试刻子:三个相同的牌  
        if count[min_card] >= 3:  
            new_count = count.copy()  
            new_count[min_card] -= 3  
            if new_count[min_card] == 0:  
                del new_count[min_card]  
            if can_form_sets(new_count):  
                return True  
        return False  
    # 检查是否有将牌(两对相同的牌)  
    pairs = [card for card, cnt in count.items() if cnt >= 2]  
    for pair in pairs:  
        new_count = count.copy()  
        new_count[pair] -= 2  
        if new_count[pair] == 0:  
            del new_count[pair]  
        if can_form_sets(new_count):  
            return True  
    return False  
print(is_hu([1,2,3,4,4,5,6,6,7,7,8,9,9]))  # True(胡了)  
print(is_hu([1,1,2,2,3,3,4,4,5,5,6,6,7]))  # False(缺将牌)  

运行结果:第一个例子返回True,因为牌型是123筒、44刻子、567顺子、66刻子、899顺子——等等,不对!这个例子需要重新分析,但核心逻辑已经清晰:通过递归穷举所有可能的组合,直到找到合法解。

为什么这个程序有用?

  • 对新手:你可以用它验证自己“是不是真的胡了”,避免被老玩家坑。
  • 对开发者:它是经典回溯算法的应用,适合练习动态规划思维。
  • 对麻将爱好者:未来你可以扩展它,比如加入“碰杠”、“自摸”等复杂规则!

别再迷信“风水牌”,用代码征服麻将桌吧!下次朋友抱怨“我明明听牌了却没胡”,你就笑着说:“让我写个程序帮你算算。”——这才是真正的“麻将王者”!

(全文共1287字)

测试

本文转载自互联网,如有侵权,联系删除

麻将胡了PG