分享一个麻将听牌算法(带癞子)(Lua)

算法已验证,目前没有发现问题,还有待优化,请指正(没有考虑东南西北中发白);

M.CardTb = {
    {0,0,0,0,0,0,0,0,0}, --筒子
    {0,0,0,0,0,0,0,0,0}, --万字
    {0,0,0,0,0,0,0,0,0}, --条字
    {0}
}

---用于存放手牌个数,最后一个用来存放癞子,

首先创建一个table,用来存储手牌,我看到网上不少听牌算法用的都是一维数组,讲真我觉得一维数组有点眼花,所以用了二维数组。

M.Card = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
        0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,
        0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,}

---听的牌

这个数组就是用来求那些牌可以胡牌的。

做完这些就可以来实现胡牌方法了

M.checkHu = function(CardTb,indexTb,value)
    local NewCardTb =  M.deepCopy(CardTb)
    local continue = true
    local Log = false

    local index1 = indexTb[1]
    local index2 = indexTb[2]
    if M.J258 then  --有些麻将对将牌有特殊需求(比如长沙麻将)
        if indexTb[2] ~= 2 and indexTb[2] ~= 5 and indexTb[2] ~= 8 then
            continue = false
            M.changeJiang(CardTb,index1,index2,value)
        end
    end
    if continue then
        if index1 == 3 and index2 == 5 and value == 0x02 then
            Log = true
        end
        if NewCardTb[index1][index2] == 0 then
            continue = false
            M.changeJiang(CardTb,index1,index2,value)
        else
            NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
            if NewCardTb[index1][index2]  > 0 then
                NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
                local result = M.check(NewCardTb,Log)
                if result then
                    table.insert(M.HuCardList,value)
                    if not M.HuType[tostring(value)] then
                        M.HuType[tostring(value)] = ''
                    end
                    local hutype = '平胡\n'
                    hutype = M.checkHuType(CardTb,hutype)
                    M.HuType[tostring(value)] = hutype
                    return true
                else
                    continue = false
                    M.changeJiang(CardTb,index1,index2,value)
                end
            else
                if M.LaiZi and NewCardTb[4][1] > 0 then
                    NewCardTb[4][1] = NewCardTb[4][1] - 1
                    local result = M.check(NewCardTb,Log)
                    if result then
                        table.insert(M.HuCardList,value)
                        table.insert(M.HuCardList,value)
                        if not M.HuType[tostring(value)] then
                            M.HuType[tostring(value)] = ''
                        end
                        local hutype = '平胡\n'
                        hutype = M.checkHuType(CardTb,hutype)
                        M.HuType[tostring(value)] = hutype
                        return true
                    else
                        continue = false
                        M.changeJiang(CardTb,index1,index2,value)
                    end
                else
                    continue = false
                    M.changeJiang(CardTb,index1,index2,value)
                end
            end
        end
    end
end

M.changeJiang = function(CardTb,index1,index2,value)
    index2 = index2 + 1
    if index2 == 10 then
       index1 = index1 + 1
       index2 = 1
    end
    if index1 < 4 then
        M.checkHu(CardTb,{index1,index2},value)
    end
end

看这段可能有点突兀,CardTb 这个参数是将手牌转化成前面说的二维数组,indexTb 是将牌位置的索引,value 是判断是否能胡的牌,这张牌已经添加进手牌了。M.chengeJiang 的主要作用就是在不能胡的情况下变更将牌,M.check是胡牌逻辑,

M.check = function(CardTb,Log)
    for k,valuetb in pairs(CardTb) do
        if k < 4 then
            for i = 1,7 do
                local value1 = valuetb[i]
                local value2 = valuetb[i + 1]
                local value3 = valuetb[i + 2]
                if value1 >= 3 then
                    valuetb[i] = valuetb[i] - 3
                    value1 = value1 - 3
                end
                if value2 >= 3 then
                    valuetb[i + 1] = valuetb[i + 1] - 3
                    value2 = value2 - 3
                end
                if value3 >= 3 then
                    valuetb[i + 2] = valuetb[i + 2] - 3
                    value3 = value3 - 3
                end
                if value1 + value2 + value3 == 6 then
                    valuetb[i] = 0
                    valuetb[i + 1] = 0
                    valuetb[i + 2] = 0
                    value3 = 0
                    value1 = 0
                    value2 = 0
                end
                if value1 + value2 + value3 == 5 and M.LaiZi and CardTb[4][1] > 0 then
                    value1 = 0
                    value2 = 0
                    value3 = 0
                    valuetb[i] = 0
                    valuetb[i + 1] = 0
                    valuetb[i + 2] = 0
                    CardTb[4][1] = CardTb[4][1] - 1
                end
                if value1 > 0 then
                    value1 = value1 -1
                    if value1 > 0 then
                        if M.LaiZi and CardTb[4][1] > 0 then
                            valuetb[i] = valuetb[i] - 2
                            CardTb[4][1] = CardTb[4][1] - 1
                        end
                    else
                        if value2 > 0 and value3 > 0 then
                            valuetb[i] = valuetb[i] - 1
                            valuetb[i + 1] = valuetb[i + 1] - 1
                            valuetb[i + 2] = valuetb[i + 2] - 1
                            value2 = value2 - 1
                            value3 = value3 - 1
                        elseif M.LaiZi and CardTb[4][1] > 0 then
                            if value2 + value3 > 0 then
                                valuetb[i] = valuetb[i] > 0 and valuetb[i] - 1 or 0
                                valuetb[i + 1] = valuetb[i + 1] > 0 and valuetb[i + 1] - 1 or 0
                                valuetb[i + 2] = valuetb[i + 2] > 0 and valuetb[i + 2] - 1 or 0
                                CardTb[4][1] = CardTb[4][1] - 1
                            else
                                if CardTb[4][1] >= 2 then
                                    valuetb[i] = valuetb[i] - 1
                                    CardTb[4][1] = CardTb[4][1] - 2
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    local count = 0
    for k,vTb in pairs(CardTb) do
        for k,v in pairs(vTb) do
            count = count + v
        end
    end
    return count == 0 and true or false
end

这个是优先把大于3张的做碰处理。然后是2张三连做吃处理(如果缺一张则用癞子补齐,有癞子的话),紧接者就是顺子,如果当前牌数为2的话,有癞子就用癞子补齐做碰处理

 

 

最后附上全部代码,


M = {}

M.CardTb = {
    {0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0},
    {0}
}

M.Card = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
        0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,
        0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,}

M.LaiZi = false
M.J258 = false

M.QingYiSe = false
M.JJH = false
M.PPH = false
M.QQR = false
M.QXD = false


M.HuCardList = {}
M.HuType = {}
M.TingCardList = {}


M.getTingCardLogic = function(handCardList, weaveCardList,gameType,liaZiTb,param1)
    M.TingCardList = {}
    local handCardCount = #handCardList
    local temp = {} --计算过可以的牌,添加进temp,后面就不会重复计算
    for i = 1,handCardCount do
        repeat
            local CardTb = M.deepCopy(handCardList)
            local value = CardTb[i]
            if M.isInTable(temp,value) then
                break
            end
            if not M.isInTable(liaZiTb,value) then
                CardTb[i] = nil
                M.getHuCardLogic(CardTb,weaveCardList,gameType,liaZiTb,param1)
                if #M.HuCardList > 0 then
                    if not M.TingCardList[tostring(value)] then
                        M.TingCardList[tostring(value)] = {}
                    end
                    M.TingCardList[tostring(value)]['hucard'] = M.HuCardList
                    M.TingCardList[tostring(value)]['hutype'] = M.HuType
                end
            end
            table.insert(temp,value)
        until true
    end
end

M.getHuCardLogic = function(handCardList, weaveCardList,gameType,liaZiTb,param1)

    M.LaiZi = false
    M.J258 = false
    M.QingYiSe = false
    M.JJH = false
    M.PPH = false
    M.QQR = false
    M.QXD = false

    M.handCardList = handCardList
    M.weaveCardList = weaveCardList
    M.gameType = gameType

    -------判断游戏是否有癞子,是否要2,5,8坐将--------------------------
    M.LaiZi = #liaZiTb > 0
    M.J258 = --根据具体游戏来判断是否需要2 5 8 坐将
    -------判断游戏是否有癞子,是否要2,5,8坐将--------------------------

    --------- 根据游戏类型判断大胡规则 ----------------------------------
    M.QingYiSe =  --根据具体游戏来判断是否可以胡此大胡

    M.QXD = --根据具体游戏来判断是否可以胡此大胡

    M.PPH = --根据具体游戏来判断是否可以胡此大胡

    M.JJH = --根据具体游戏来判断是否可以胡此大胡

    M.QQR = --根据具体游戏来判断是否可以胡此大胡
    --------- 根据游戏类型判断大胡规则 ----------------------------------

    local handCard = {}
    for i,v in pairs(handCardList) do
        table.insert(handCard,v)
    end
    M.HuCardList = {}
    M.HuType = {}
    for k,v in pairs(M.Card) do
        local cardlist = M.deepCopy(handCard)
        local needCheck = true
        table.insert(cardlist,v)
        local CardTb = M.convertToArr(cardlist,liaZiTb)
        M.J258 =  M.checkSpecialHu(CardTb)
        if M.isQiXiaoDui(CardTb) then
            needCheck = false
            table.insert(M.HuCardList,v)
            if not M.HuType[tostring(v)] then
                M.HuType[tostring(v)] = ''
            end
            local hutype = '平胡\n'
            hutype = M.checkHuType(CardTb,hutype)
            M.HuType[tostring(v)] = hutype
        end
        if needCheck and M.isJiangJiangHu(CardTb) then
            needCheck = false
            table.insert(M.HuCardList,v)
            if not M.HuType[tostring(v)] then
                M.HuType[tostring(v)] = ''
            end
            local hutype = '平胡\n'
            hutype = M.checkHuType(CardTb,hutype)
            M.HuType[tostring(v)] = hutype
        end
        if needCheck then
            M.checkHu(CardTb,{1,1},v)
        end
    end
    M.removeRepeated(M.HuCardList)
end

M.checkSpecialHu = function(CardTb)  --检查是否符合大胡规则,不确定是否胡牌,作用于是否需要2,5,8坐将
    if M.QingYiSe then
        if M.isQingYiSe(CardTb) then
            return false
        end
    end
    if M.PPH then
        if M.isPengPengHu(CardTb) then
            return false
        end
    end
    if M.QQR then
        if M.isQuanQiuRen(CardTb) then
            return false
        end
    end
    return true
end

M.checkHuType = function(CardTb,hutype)
    if M.QingYiSe then
        if M.isQingYiSe(CardTb) then
            hutype = hutype .. '清一色\n'
        end
    end
    if M.QXD then
        if M.isQiXiaoDui(CardTb) then
            hutype = hutype .. '七小对\n'
        end
    end
    if M.PPH then
        if M.isPengPengHu(CardTb) then
            hutype = hutype .. '碰碰胡\n'
        end
    end
    if M.JJH then
        if M.isJiangJiangHu(CardTb) then
            hutype = hutype .. '将将胡\n'
        end
    end
    if M.QQR then
        if M.isQuanQiuRen(CardTb) then
            hutype = hutype .. '全求人\n'
        end
    end

    return hutype
end

M.checkHu = function(CardTb,indexTb,value)
    local NewCardTb =  M.deepCopy(CardTb)
    local continue = true
    local Log = false

    local index1 = indexTb[1]
    local index2 = indexTb[2]
    if M.J258 then
        if indexTb[2] ~= 2 and indexTb[2] ~= 5 and indexTb[2] ~= 8 then
            continue = false
            M.changeJiang(CardTb,index1,index2,value)
        end
    end
    if continue then
        if index1 == 3 and index2 == 5 and value == 0x02 then
            Log = true
        end
        if NewCardTb[index1][index2] == 0 then
            continue = false
            M.changeJiang(CardTb,index1,index2,value)
        else
            NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
            if NewCardTb[index1][index2]  > 0 then
                NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
                local result = M.check(NewCardTb,Log)
                if result then
                    -- logError('xx : '..Json.encode(CardTb))
                    table.insert(M.HuCardList,value)
                    if not M.HuType[tostring(value)] then
                        M.HuType[tostring(value)] = ''
                    end
                    local hutype = '平胡\n'
                    hutype = M.checkHuType(CardTb,hutype)
                    M.HuType[tostring(value)] = hutype
                    return true
                else
                    continue = false
                    M.changeJiang(CardTb,index1,index2,value)
                end
            else
                if M.LaiZi and NewCardTb[4][1] > 0 then
                    NewCardTb[4][1] = NewCardTb[4][1] - 1
                    local result = M.check(NewCardTb,Log)
                    if result then
                        -- logError('bb : '..Json.encode(CardTb))
                        table.insert(M.HuCardList,value)
                        table.insert(M.HuCardList,value)
                        if not M.HuType[tostring(value)] then
                            M.HuType[tostring(value)] = ''
                        end
                        local hutype = '平胡\n'
                        hutype = M.checkHuType(CardTb,hutype)
                        M.HuType[tostring(value)] = hutype
                        return true
                    else
                        continue = false
                        M.changeJiang(CardTb,index1,index2,value)
                    end
                else
                    continue = false
                    M.changeJiang(CardTb,index1,index2,value)
                end
            end
        end
    end
end

M.changeJiang = function(CardTb,index1,index2,value)
    index2 = index2 + 1
    if index2 == 10 then
       index1 = index1 + 1
       index2 = 1
    end
    if index1 < 4 then
        M.checkHu(CardTb,{index1,index2},value)
    end
end

M.check = function(CardTb,Log)
    for k,valuetb in pairs(CardTb) do
        if k < 4 then
            for i = 1,7 do
                local value1 = valuetb[i]
                local value2 = valuetb[i + 1]
                local value3 = valuetb[i + 2]
                if value1 >= 3 then
                    valuetb[i] = valuetb[i] - 3
                    value1 = value1 - 3
                end
                if value2 >= 3 then
                    valuetb[i + 1] = valuetb[i + 1] - 3
                    value2 = value2 - 3
                end
                if value3 >= 3 then
                    valuetb[i + 2] = valuetb[i + 2] - 3
                    value3 = value3 - 3
                end
                if value1 + value2 + value3 == 6 then
                    valuetb[i] = 0
                    valuetb[i + 1] = 0
                    valuetb[i + 2] = 0
                    value3 = 0
                    value1 = 0
                    value2 = 0
                end
                if value1 + value2 + value3 == 5 and M.LaiZi and CardTb[4][1] > 0 then
                    value1 = 0
                    value2 = 0
                    value3 = 0
                    valuetb[i] = 0
                    valuetb[i + 1] = 0
                    valuetb[i + 2] = 0
                    CardTb[4][1] = CardTb[4][1] - 1
                end
                if value1 > 0 then
                    value1 = value1 -1
                    if value1 > 0 then
                        if M.LaiZi and CardTb[4][1] > 0 then
                            valuetb[i] = valuetb[i] - 2
                            CardTb[4][1] = CardTb[4][1] - 1
                        end
                    else
                        if value2 > 0 and value3 > 0 then
                            valuetb[i] = valuetb[i] - 1
                            valuetb[i + 1] = valuetb[i + 1] - 1
                            valuetb[i + 2] = valuetb[i + 2] - 1
                            value2 = value2 - 1
                            value3 = value3 - 1
                        elseif M.LaiZi and CardTb[4][1] > 0 then
                            if value2 + value3 > 0 then
                                valuetb[i] = valuetb[i] > 0 and valuetb[i] - 1 or 0
                                valuetb[i + 1] = valuetb[i + 1] > 0 and valuetb[i + 1] - 1 or 0
                                valuetb[i + 2] = valuetb[i + 2] > 0 and valuetb[i + 2] - 1 or 0
                                CardTb[4][1] = CardTb[4][1] - 1
                            else
                                if CardTb[4][1] >= 2 then
                                    valuetb[i] = valuetb[i] - 1
                                    CardTb[4][1] = CardTb[4][1] - 2
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    local count = 0
    for k,vTb in pairs(CardTb) do
        for k,v in pairs(vTb) do
            count = count + v
        end
    end
    return count == 0 and true or false
end



M.convertToArr = function(handCardList,liaZiTb)
    local CardTb = M.deepCopy(M.CardTb)
    for k,value in ipairs(handCardList) do
        if M.isInTable(liaZiTb,value) then
            CardTb[4][1] = CardTb[4][1] + 1
        else
            local suit = math.modf(value/16) + 1
            CardTb[suit][math.fmod(value, 16)] = CardTb[suit][math.fmod(value, 16)] + 1
        end
    end
    return CardTb
end

M.isQingYiSe = function(CardTb)
    local AllCardTb = M.deepCopy(CardTb)
    for k,value in ipairs(M.weaveCardList) do
        local suit = math.modf(value/16) + 1
        AllCardTb[suit][math.fmod(value, 16)] = AllCardTb[suit][math.fmod(value, 16)] + 1
    end
    for k,valuetb in pairs(AllCardTb) do
        local count = 0
        for k,value in pairs(valuetb) do
            count = count + value
        end
        count = count + AllCardTb[4][1]
        if count >= 14 then
            return true
        end
    end
    return false
end

M.isQiXiaoDui = function(CardTb)
    local newCardTb = M.deepCopy(CardTb)
    local count = 0
    for k,valueTb in pairs(newCardTb) do
        if k <= 3 then
            for k,v in pairs(valueTb) do
                if newCardTb[4][1] > 0 and v%2 ~= 0 then
                    newCardTb[4][1] = newCardTb[4][1] - 1
                else
                    if v%2 ~= 0 then
                        return false
                    end
                end

            end
        end
    end
    for k,v1 in pairs(CardTb) do
        for k,v in pairs(v1) do
            count = count + v
        end
    end
    if count ~= 14 then
        return false
    end
    return true
end

M.isJiangJiangHu = function(CardTb)
    local count = 0
    for k,valueTb in pairs(CardTb) do
        for k1,v in pairs(valueTb) do
            if v > 0 and k1 ~= 2 and k1 ~= 5 and k1 ~= 8 then
                return false
            end
            count = count + v
        end
    end
    if count ~= 14 then
        return false
    end
    return true
end

M.isQuanQiuRen = function(CardTb)
    local count = 0
    for k,valueTb in pairs(CardTb) do
        for k1,v in pairs(valueTb) do
            count = count + v
        end
    end
    if count ~= 2 then
        return false
    end
    return true
end

M.isPengPengHu = function(CardTb)
    local AllCardTb = M.deepCopy(M.CardTb)
    for k,value in ipairs(M.weaveCardList) do
        local suit = math.modf(value/16) + 1
        AllCardTb[suit][math.fmod(value, 16)] = AllCardTb[suit][math.fmod(value, 16)] + 1
    end
    for k,valueTb in pairs(AllCardTb) do
        for k,v in pairs(valueTb) do
            if v ~= 0 and v >= 3 then
                return false
            end
        end
    end
    local count = 0
    local pengcount = 0
    for k,valueTb in pairs(CardTb) do
        for k,v in pairs(valueTb) do
            count = count + v
            if v == 3 then
                pengcount = pengcount + 1
            end
        end
    end
    if pengcount*3 + 2 ~= count then
        return false
    end
    return true
end

M.isInTable = function(tb,value)
    for k,v in ipairs(tb) do
        if v == value then
            return true
        end
    end
    return false
end

M.deepCopy = function (object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then

            return lookup_table[object]
        end  -- if
        local new_table = {}
        lookup_table[object] = new_table


        for index, value in pairs(object) do
            new_table[_copy(index)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end

M.removeRepeated = function(a)
    for k,v in pairs(a) do
        local count=0
        for j in pairs(a)do count=count+1 end
        for i=k+1,count do
            if v==a[i] then
                table.remove(a,i)
            end
        end
    end
end

return M

最后说明一下,外部用的方法 M.getTingCardLogic 可以用来计算打出那些牌可以听那些牌,M.getHuCardLogic 计算可以听那些牌。 M.HuCardList  M.HuType 在使用 M.getHuCardLogic 会用到来存储胡牌信息 ,M.TingCardList 在使用M.getTingCardLogic用来存储听牌信息,两个方法参数一样,前三个参数就不解释了。liaZiTb 是有癞子玩法的时候把那些牌是癞子放到数组中。param1 大多数情况是没有用的,有玩法是选中大胡玩法才可以胡大胡,而大胡是不需要坐将的,所以param1根据自己的实际需要做处理

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值