📖 广安麻将算法概述
广安麻将起源于四川广安,属于"血战到底"玩法体系,使用万、条、筒三门花色共108张牌(不加字牌)。其算法核心围绕胡牌判定、听牌检测和番数计算三大模块展开。
图1:广安麻将算法三大核心模块关系
与普通麻将算法相比,广安麻将最显著的算法差异在于:必须定缺一门、血战到底(一家胡牌后其他人继续)、以及查花猪/查大叫的终局处理。这些规则直接影响了摸牌、出牌和胡牌判断的算法流程。
算法整体流程
一局广安麻将的算法处理流程可以抽象为以下步骤:
- 初始化牌墙,发牌(庄家14张,闲家13张)
- 玩家定缺选择(确定缺哪一门花色)
- 摸牌、出牌、碰、杠的循环处理
- 胡牌判定(每次出牌/杠后检测)
- 血战到底(继续对局直到三家胡牌或牌墙摸完)
- 查花猪/查大叫,计算最终得分
🃏 胡牌判断算法(核心)
胡牌判断是广安麻将算法中最基础、最关键的模块。其数学本质是:将14张手牌(加上胡牌那张)拆分为一个对子(将牌)+ 若干顺子或刻子,或满足七对/龙七对等特殊牌型。
算法思路:递归回溯
标准胡牌判断采用经典的"取出将牌+迭代拆解"方法,伪代码如下:
function isHu(tiles):
count = 统计每张牌的张数
if 总张数 % 3 != 2: return false
// 尝试每种牌作为将牌
for tile in count:
if count[tile] >= 2:
count[tile] -= 2
if canFormTriplets(count):
return true
count[tile] += 2 // 还原
// 七对检测
if 所有count[tile] == 0或2 且总对数为7:
return true
return false
function canFormTriplets(count):
for i from 1 to 9:
while count[i] > 0:
// 尝试组成刻子(三个相同)
if count[i] >= 3: count[i] -= 3
// 尝试组成顺子(i, i+1, i+2 同花色)
else if count[i+1] > 0 且 count[i+2] > 0:
count[i]--; count[i+1]--; count[i+2]--
else: return false
return true
图2:胡牌判断算法递归回溯流程
优化建议:在实际代码中,广安麻将算法通常使用二进制位运算或状态压缩表来加速判断。例如将每门牌的量编码为4-bit,利用查表法代替递归,单次胡牌判断可控制在微秒级。
广安麻将特有约束
- 缺一门约束:胡牌时,手牌中必须缺少至少一门花色(否则判为"花猪")。算法在胡牌检测前首先检查是否存在三种花色都有的情况。
- 将牌选择:广安麻将允许任意牌作将,但"将"必须为完全相同的一对。
- 抢杠胡:若玩家杠牌的另一张牌恰好是某玩家要胡的牌,则触发抢杠胡,算法需额外处理介入逻辑。
🎯 听牌算法实现
听牌算法用于计算当前手牌还差哪些牌就能胡。其核心思路是枚举所有可能的待摸牌,对每种情况执行一次胡牌判断,复杂度为O(34×胡牌判断耗时)。
朴素实现
遍历牌墙中剩余的每一张牌(除去明牌),将牌加入手牌后调用isHu()函数。若返回true,即为听这张牌。伪代码如下:
function getTingTiles(hand):
tingList = []
for tile in 所有牌(1~9万, 1~9条, 1~9筒):
if 剩余牌中还有该牌:
hand.append(tile)
if isHu(hand): tingList.append(tile)
hand.pop()
return tingList
图3:听牌算法逐张枚举测试示意
剪枝优化
广安麻将算法实战中通常采用去重剪枝:同一张牌有4张,最多只尝试1次;同时可先检查缺门约束,提前排除不可能胡的牌。高级实现还会利用"胡牌表"的位掩码特性做批量查询,将听牌检测从线性枚举优化为常数级查表。
要点:听牌算法只在摸牌后和杠牌后触发,出牌后不需要检测(因为出牌后手牌数不满足胡牌条件)。
💰 算番算法详解
广安麻将的算番算法是决定每局得分的关键。它依据玩家的胡牌牌型、操作过程(杠/吃等)以及特殊状态进行叠加计算。下面列出广安麻将最常见的番种及对应番数:
| 番种 |
番数 |
说明 |
| 平胡(素胡) | 1番 | 基础胡牌,无特殊牌型 |
| 大对子(碰碰胡) | 2番 | 由4组刻子+1对将组成 |
| 清一色 | 3番 | 手牌全部为同一门花色 |
| 清大对 | 4番 | 清一色+大对子的组合 |
| 七对 | 2番 | 7个对子组成的胡牌 |
| 龙七对 | 3番 | 含至少1个四张牌的七对 |
| 杠上花 | +1番 | 杠牌后摸牌直接胡 |
| 杠上炮 | +1番 | 杠牌后打出的牌被其他人胡 |
| 金钩钓 | +1番 | 胡牌时手中只有一张牌 |
| 海底捞月 | +1番 | 摸最后一张牌胡牌 |
| 海底炮 | +1番 | 海底牌打出后被胡 |
| 带幺九 | 2番 | 所有顺/刻含1或9 |
图4:广安麻将所有番种及番数对照
算番算法公式
总番数 = 基础番(胡牌类型番数)+ 附加番(杠/海底/金钩钓等)。若有多种特殊牌型(如清一色+大对子),番数采用乘法叠加还是加法叠加取决于地方约定。广安麻将主流规则采用加法累加,但"清大对"作为复合牌型直接算4番。
注意:广安麻将中"根"(即4张相同牌)在部分规则中会额外+1番。算法实现时需要同时支持血战到底模式下,先胡者的番数不受后胡者影响,独立结算。
📊 算法流程图文解释
以下通过分步图解的方式,展示广安麻将算法在一局完整游戏中的运行流程:
图5:广安麻将算法整体流程图(发牌→定缺→行牌→胡牌→结算)
分步说明
1
发牌与定缺:算法随机洗牌并等分牌墙。每位玩家选择一张牌作为"定缺牌",标记自己缺的那门花色。
2
行牌处理:轮转摸牌-出牌,算法监听碰、杠操作并实时更新手牌状态。
3
胡牌检测:每次摸牌或杠后执行isHu()。若true,则根据当前操作类型(自摸/点炮/抢杠)记录胡牌信息。
4
血战到底:当有玩家胡牌,若未达到三家胡牌且牌墙未空,则继续从下家开始行牌。算法需标记已胡玩家并跳过其出牌。
5
终局查算:牌墙摸完或三家胡牌后,检查未胡玩家是否缺门(花猪)和是否听牌(大叫)。然后一次性结算所有玩家番数。
整套算法的时间复杂度主要取决于胡牌判断和番数统计。广安麻将算番因血战到底存在多次结算,需仔细处理多家交互的番数叠加。
❓ 广安麻将算法常见问题解答
广安麻将和普通四川麻将算法有哪些区别?
广安麻将属于四川麻将分支,核心区别有:① 必须定缺一门;② 血战到底,已胡玩家退出后其他人继续;③ 有查花猪和查大叫的终局惩罚;④ 不能吃牌(部分地区可碰不可吃)。算法上需要相应增加缺门检查、多玩家状态管理和终局结算逻辑。
广安麻将胡牌算法的时间复杂度是多少?
朴素递归实现的胡牌判断复杂度约为O(N^2),N为手牌数量(14张)。使用查表+位运算优化后可降至O(1)~O(34)。听牌算法若是逐张枚举,复杂度为O(34×胡牌判断耗时)。在手机端实现中建议采用预编译状态表来保证实时性。
算番算法中"清大对"为何比"清一色"番数高?
"清大对"是清一色与大对子(碰碰胡)的复合牌型,牌型组合更苛刻:既要全部同一花色,又需4组刻子+1对将。因此广安麻将直接将其定为4番,高于清一色的3番。算法上这是一个特判分支,优先于单一牌型判断。
如何用代码判断抢杠胡?
当玩家A杠牌时,算法先将杠牌加入A的手牌构成"暗杠/明杠",然后检查其他玩家是否有这张牌的胡牌。若有,则触发"抢杠胡",A的杠牌操作失败,改为被胡。实现时需要在杠操作的分支中额外对所有其他玩家执行一次isHu(hand+这张牌)。
广安麻将"查花猪"和"查大叫"在算法中如何计算?
牌局结束时(牌墙摸完或三家胡牌),若存在未胡玩家,算法逐一检查其手牌是否缺门:若缺门则作为"花猪"赔付其他玩家;若不缺门,再检查是否听牌,若听牌则不用赔付,若不听牌则"大叫"需要向胡牌玩家赔付。赔付金额按约定番数基数计算。
为什么听牌算法中要去重剪枝?
因为同一张牌在牌墙中最多剩余4张,且相同面值的牌对胡牌判断结果是一致的。去重剪枝可以将34种牌种逐一测试而不是4×34次,极大减少计算量。这在血量到底模式下多玩家频繁调用听牌检测时尤为重要。