麻将的胡牌算法

本文探讨了麻将胡牌的算法,从普通麻将的计算方式出发,详细介绍了如何通过数据结构选择和特定规则判断胡牌条件。对于有癞子(百搭)的麻将,提出了利用癞子牌补足顺子或刻子的方法,并提供了无癞子和有癞子的算法实现示例。
摘要由CSDN通过智能技术生成

正常的麻将胡牌方式为满足N * ABC + M *DDD +EE 的形式,及存在一个对子(EE),剩余牌均能组成顺子(ABC)或者刻子(DDD)。

很容易发现必须满足size%3 == 2的形式才可以去计算胡牌。

数据结构的选取:

麻将有万、饼、条各九种,另外还有东西南北中,春夏秋冬。
种类不是很多,一个字节表示就可以了,前四位代表类型,后四位代表值,东西南北中,春夏秋冬可以集中到一种类型中去。

普通麻将的计算方式:

  • 1.首先找出所有包含一对的情形,移除对子(注意去重),记下剩余牌的所有集合为Tn;
  • 2.针对每个Tn中的数组尝试移除一个顺子,成功转到2,失败到3。
  • 3.针对每个Tn中的数组尝试移除一个刻子(DDD),成功转到2。
  • 4.若当前的数组的数量变为0,则表示,当前的方案可以胡牌。

2,3,4可以作为一个check_3n(检测是否满足N * ABC + M *DDD)的函数,递归调用即可。

针对有癞子的麻将(百搭):

最简单的办法是尝试将癞子牌变为所有派来进行尝试,不过如果手中有多张癞子牌的话计算量就相当大了,比如3张,则需要计算牌的种类的3次方次,虽然中途可以通过剪枝减少部分计算量,但还是太慢了。
针对这种情况我们可以在计算出癞子的数量,如果出现找出顺子或刻子失败,我们则可以用癞子去补,如果失败了,那么当前的方案就不通过。

  • 1.同样找出所有包含一对的情形,移除对子,移除的时候需要注意更新癞子的数量这里需要注意的是对子是怎么产生的:
    • 原有的对子
    • 一个癞子和一普通的组成的对子
    • 一对癞子
  • 2.针对每个数组尝试移除一个顺子,成功转到2,如果失败尝试用癞子去补,癞子也不够,转到3。
  • 3.针对每个数组尝试移除一个刻子(DDD),成功转到2,如果失败尝试用癞子去补,癞子也不够,当前的方案就不通过。
  • 4.若当前的数组的数量变为0,则表示,当前的方案可以胡牌。

有些人好像还不很了解,补充一个lua版无癞子的算法吧(很多复制都可以优化掉):

function table_copy_table(ori_tab)
    if (type(ori_tab) ~= "table") then
        return nil
    end
    local new_tab = {}
    for i,v in pairs(ori_tab) do
        local vtyp = type(v)
        if (vtyp == "table") then
            new_tab[i] = table_copy_table(v)
        elseif (vtyp == "thread") then
            new_tab[i] = v
        elseif (vtyp == "userdata") then
            new_tab[i] = v
        else
            new_tab[i] = v
        end
    end
    return new_tab
end


function sort_card(t)
    table.sort(t, function(a,b)
        local sa,ra = a&0xf,a&0xf0
        local sb,rb = b&0xf,b&0xf0
        if ra == rb then
            return sa < sb
        else
            return ra < rb
        end

    end)
end

function remove_three_same(t)
    assert(#t%3 == 0 and #t > 0)
    local found = false
    local begin
    for i=1,#t - 2 do
        if t[i] == t[i + 1] and t[i] == t[i + 2] then
            found = true
            begin = i
            break
        end
    end

    if found 
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值