【转载】德州扑克牌型算法-Lua代码实现

原文地址:https://www.namidame.tech/Lua-Texas.html

本文提供了一种用Lua实现的德州扑克牌型、得分及成牌选择算法,是在公司空余时间老板要求练手写的算法。。。包括了代码和测试用例,代码可以应用在德州扑克手游的牌型计算模块中。

这里有几个文件,直接上代码
安装Lua运行环境后命令行运行main.lua文件即可
其中CardDealer文件是自动发牌的,由于测试用例需要自己编写,这个类也没什么用了

main.lua

-- Author: luyuejun
-- Date: 2017/6/15

require("CardUtil")
require("TableUtil")
require("CardDealer")

    -- "高牌"     1
    -- "一对"     2
    -- "两对"     3
    -- "三条"     4
    -- "顺子"     5
    -- "同花"     6
    -- "葫芦"     7
    -- "四条"     8
    -- "同花顺" 9

-- 以下为测试用例
local datas = {}
table.insert(datas, {input={H={{1,1},{1,2}},P={{1,3},{1,4},{1,5}}},expectOutput={T=9,S=90504030201,C={{1,1},{1,2},{1,3},{1,4},{1,5}}}})
table.insert(datas, {input={H={{4,10},{4,12}},P={{4,11},{4,13},{4,1}}},expectOutput={T=9,S=91413121110,C={{4,10},{4,11},{4,12},{4,13},{4,1}}}})
table.insert(datas, {input={H={{4,10},{4,12}},P={{4,11},{4,8},{4,1}}},expectOutput={T=6,S=61412111008,C={{4,8},{4,10},{4,11},{4,12},{4,1}}}})
table.insert(datas, {input={H={{4,10},{4,12}},P={}},expectOutput={T=1,S=11210,C={{4,10},{4,12}}}})
table.insert(datas, {input={H={{4,10},{4,12},{3,12}},P={}},expectOutput={T=2,S=2121210,C={{4,10},{4,12},{3,12}}}})
table.insert(datas, {input={H={{1,12},{4,12}},P={{3,12}}},expectOutput={T=4,S=4121212,C={{1,12},{4,12},{3,12}}}})
table.insert(datas, {input={H={{1,1},{1,13}},P={{1,12}}},expectOutput={T=1,S=1141312,C={{1,12},{1,13},{1,1}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{1,12}}},expectOutput={T=2,S=2141412,C={{1,12},{2,1},{1,1}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{3,1}}},expectOutput={T=4,S=4141414,C={{1,1},{2,1},{3,1}}}})

table.insert(datas, {input={H={{1,1},{2,13}},P={{3,2},{3,3}}},expectOutput={T=1,S=114130302,C={{3,2},{3,3},{2,13},{1,1}}}})
table.insert(datas, {input={H={{1,1},{2,11}},P={{3,1},{3,3}}},expectOutput={T=2,S=214141103,C={{3,3},{2,11},{1,1},{3,1}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{4,2},{3,2}}},expectOutput={T=3,S=314140202,C={{4,2},{3,2},{1,1},{2,1}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{3,1},{3,2}}},expectOutput={T=4,S=414141402,C={{3,2},{3,1},{1,1},{2,1}}}})
table.insert(datas, {input={H={{4,4},{3,4}},P={{4,2},{3,2}}},expectOutput={T=3,S=304040202,C={{3,2},{4,2},{4,4},{3,4}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{3,1},{4,1}}},expectOutput={T=8,S=814141414,C={{1,1},{2,1},{3,1},{4,1}}}})
table.insert(datas, {input={H={{1,1},{2,2}},P={{3,2},{4,2},{1,2}}},expectOutput={T=8,S=80202020214,C={{1,1},{1,2},{2,2},{3,2},{4,2}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{3,1},{4,1},{1,2}}},expectOutput={T=8,S=81414141402,C={{1,2},{1,1},{2,1},{3,1},{4,1}}}})
table.insert(datas, {input={H={{1,1},{2,2}},P={{3,4},{4,7},{1,6}}},expectOutput={T=1,S=11407060402,C={{2,2},{3,4},{1,6},{4,7},{1,1}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{3,4},{4,7},{1,6}}},expectOutput={T=2,S=21414070604,C={{3,4},{1,6},{4,7},{1,1},{2,1}}}})
table.insert(datas, {input={H={{1,2},{2,2}},P={{3,4},{4,1},{1,6}}},expectOutput={T=2,S=20202140604,C={{3,4},{1,6},{4,1},{1,2},{2,2}}}})

table.insert(datas, {input={H={{1,2},{2,2}},P={{3,1},{4,1},{1,6}}},expectOutput={T=3,S=31414020206,C={{1,6},{1,2},{2,2},{3,1},{4,1}}}})
table.insert(datas, {input={H={{1,2},{2,2}},P={{3,3},{4,3},{1,1}}},expectOutput={T=3,S=30303020214,C={{1,1},{1,2},{2,2},{3,3},{4,3}}}})
table.insert(datas, {input={H={{1,2},{2,1}},P={{3,1},{4,1},{1,6}}},expectOutput={T=4,S=41414140602,C={{1,2},{1,6},{2,1},{3,1},{4,1}}}})
table.insert(datas, {input={H={{1,2},{2,2}},P={{3,2},{4,1},{1,6}}},expectOutput={T=4,S=40202021406,C={{1,6},{4,1},{2,2},{1,2},{3,2}}}})
table.insert(datas, {input={H={{1,2},{2,1}},P={{3,3},{4,4},{1,5}}},expectOutput={T=5,S=50504030201,C={{2,1},{1,2},{3,3},{4,4},{1,5}}}})
table.insert(datas, {input={H={{1,13},{2,1}},P={{3,12},{4,11},{1,10}}},expectOutput={T=5,S=51413121110,C={{1,10},{4,11},{3,12},{1,13},{2,1}}}})

table.insert(datas, {input={H={{1,13},{2,9}},P={{3,12},{4,11},{1,10}}},expectOutput={T=5,S=51312111009,C={{2,9},{1,10},{4,11},{3,12},{1,13}}}})
table.insert(datas, {input={H={{1,1},{1,2}},P={{1,4},{1,3},{1,8}}},expectOutput={T=6,S=61408040302,C={{1,2},{1,3},{1,4},{1,8},{1,1}}}})

table.insert(datas, {input={H={{1,1},{2,1}},P={{1,12},{1,11},{1,10},{1,4}}},expectOutput={T=6,S=61412111004,C={{1,4},{1,10},{1,11},{1,12},{1,1}}}})
table.insert(datas, {input={H={{1,3},{2,3}},P={{3,3},{4,1},{4,3},{1,4}}},expectOutput={T=8,S=80303030314,C={{4,1},{1,3},{2,3},{3,3},{4,3}}}})
table.insert(datas, {input={H={{1,1},{2,1}},P={{3,1},{4,4},{4,3},{1,4}}},expectOutput={T=7,S=71414140404,C={{1,4},{4,4},{1,1},{2,1},{3,1}}}})

table.insert(datas, {input={H={{1,1},{2,1}},P={{3,3},{4,3},{1,3},{1,4}}},expectOutput={T=7,S=70303031414,C={{1,1},{2,1},{3,3},{4,3},{1,3}}}})
table.insert(datas, {input={H={{1,2},{2,2}},P={{3,3},{4,3},{1,1},{3,10}}},expectOutput={T=3,S=30303020214,C={{1,1},{1,2},{2,2},{3,3},{4,3}}}})

table.insert(datas, {input={H={{1,2},{2,2}},P={{3,3},{4,3},{1,1},{3,10},{4,10}}},expectOutput={T=3,S=31010030314,C={{1,1},{3,3},{4,3},{3,10},{4,10}}}})
table.insert(datas, {input={H={{1,1},{1,2}},P={{1,3},{1,4},{1,5},{4,12},{4,13}}},expectOutput={T=9,S=90504030201,C={{1,1},{1,2},{1,3},{1,4},{1,5}}}})
table.insert(datas, {input={H={{4,10},{4,12}},P={{4,11},{4,13},{4,1},{2,1}}},expectOutput={T=9,S=91413121110,C={{4,10},{4,11},{4,12},{4,13},{4,1}}}})


require("CardTest")
CardTest.test(datas)

CardUtil.lua

-- Author: luyuejun
-- Date: 2017/6/15

require("TableUtil")

DEBUG_LOG = false

CARD_POINTS = {
    0x01, 0x02, 0x03, 0x04,
    0x05, 0x06, 0x07, 0x08,
    0x09, 0x0A, 0x0B, 0x0C,
    0x0D, 0x0E
}

TYPE_POINTS = {
    "01","02","03","04",
    "05","06","07","08",
    "09","10","11","12",
    "13","14"
}

PAI_XING_STRING = {
    "高牌",
    "一对",
    "两对",
    "三条",
    "顺子",
    "同花",
    "葫芦",
    "四条",
    "同花顺",
}

Card = {
    hua = 1,
    dian = 1,
    isHand = false,
}

Card.__index = Card

function printC(card)
    print("card===")
    print("hua=",card.hua,"dian=",card.dian)
    print("card===")
end

function printHD(tb)
    CardUtil.printHuaDic(tb)
end

function printDD(tb)
    CardUtil.printDianDic(tb)
end

function Card:new(hua, dian, isHand)
    local o = {}
    setmetatable(o, self)

    o.hua = hua
    o.dian = dian
    o.isHand = isHand or false

    return o
end

function Card:getHua()
    return self.hua
end

function Card:getDian()
    return self.dian
end

function Card:IsHand()
    return self.isHand
end

CardUtil = {}

function CardUtil.getCardInfo(hands, publics)
    local tb = hands
    TableUtil.concat(tb, publics)
    TableUtil.print(tb)
end

function CardUtil.isTongHua(tb)
    local flag = false
    local huas = {0,0,0,0}

    for i,v in ipairs(tb) do
        huas[v.hua] = huas[v.hua] + 1
    end

    for i,v in ipairs(huas) do
        if v >= 5 then 
            return true, i 
        end
    end
    return false
end

function CardUtil.isTongHuaVecShunZi(tb)
    local flag = false
    local curIndex = #tb
    local preIndex = #tb-1
    for i = #tb, 2, -1 do
        for j = i, i-3, -1 do
            curIndex = j
            preIndex = j - 1
            -- print("i = ",i,"j = ",j)
            -- print("compare ",curIndex," ",preIndex)
            if tb[preIndex] == nil then
                return false
            elseif curIndex == #tb then
                if tb[curIndex].dian == 1 then
                    if tb[preIndex].dian ~= 13 then -- TJQKA的处理
                        break
                    end
                elseif tb[curIndex].dian ~= tb[preIndex].dian + 1 then
                    break
                end
            elseif tb[curIndex].dian ~= tb[preIndex].dian + 1 then
                break
            elseif curIndex == i - 3 then --比完一轮5张都没断,即是顺子
                local isASpecial = false
                if tb[preIndex].dian == 1 then isASpecial = true end
                local cards = {}
                for k=i-4,i do
                    -- print("insert ",k)
                    table.insert(cards, tb[k])
                end
                return true, cards, isASpecial
            end
        end
    end
    return false
end

-- A有两个位置,权值1和14
function CardUtil.getDianDicSpec(tb)
    local dians = {
        {},{},{},{},
        {},{},{},{},
        {},{},{},{},
        {},{}
    }
    for i,v in ipairs(tb) do
        -- print("insert into dian=", v.dian)
        table.insert(dians[v.dian], v)      
        if v.dian == 1 then
            table.insert(dians[14], v)
        end
    end
    return dians
end

-- A只有权值14
function CardUtil.getDianDic14(tb)
    local dians = {
        {},{},{},{},
        {},{},{},{},
        {},{},{},{},
        {},{}
    }
    for i,v in ipairs(tb) do
        if v.dian == 1 then
            table.insert(dians[14], v)
        else
            table.insert(dians[v.dian], v)      
        end
    end
    return dians
end

function CardUtil.printDianDic(dictionary)
    print("dianDic=")
    CardUtil.printDic(dictionary)
    print("")
end 

function CardUtil.getHuaDic(tb)
    local huas = {
        {},{},{},{},
    }
    local As = { -- 先将A存起来,最后再放进每一种花色里,与默认A权值为14类似
        {},{},{},{},
    }
    for i,v in ipairs(tb) do
        -- print("insert into dian=", v.dian)
        if v.dian == 1 then
            table.insert(As[v.hua], v)
        else
            table.insert(huas[v.hua], v)
        end
    end
    for i,hua in ipairs(As) do
        for _,v in pairs(hua) do
            table.insert(huas[i], v)
        end
    end
    return huas
end

function CardUtil.printHuaDic(dictionary)
    print("huaDic=")
    CardUtil.printDic(dictionary)
    print("")
end 

function CardUtil.printDic(dictionary)
    for i, v in ipairs(dictionary) do
        TableUtil.print(v)
    end 
end

function CardUtil.isSiTiao(dictionary)
    for i,v in ipairs(dictionary) do
        if #v >= 4 then
            -- 拿出这四张牌
            local cards = {}
            for _, v1 in pairs(v) do
                table.insert(cards, v1)
            end
            -- 找出除四条外最大一张牌
            for j = #dictionary, 1, -1 do
                if i ~= j and #dictionary[j] > 0 then
                    table.insert(cards, 1, dictionary[j][1])
                    return true, cards
                end
            end
            return true, cards -- 四张卡时在这里返回
        end
    end
    return false
end

function CardUtil.isHuLu( dictionary )
    -- body
    local dian3 = 0 -- 最大三条所在点数
    local dian2 = 0 -- 最大一对所在点数
    for i = #dictionary, 1, -1 do -- 倒序查找,从最大的找起
        if #dictionary[i] == 3 then
            if dian3 == 0 then
                dian3 = i
            elseif dian2 == 0 then -- 如果已经取出最大的三条,应从第二大的三条里取两张作为一对
                dian2 = i
            end
        elseif #dictionary[i] == 2 then -- 这里有可能从三条里面拿,例如AAAKKK8
            if dian2 == 0 then
                dian2 = i
            end
        end
        if dian3 > 0 and dian2 > 0 then
            break
        end
    end
    if dian3 > 0 and dian2 > 0 then
        -- 先插入权值小的一对,再插入权值大的三条
        local cards = {}
        table.insert(cards, dictionary[dian2][1])
        table.insert(cards, dictionary[dian2][2])
        for _,v in pairs(dictionary[dian3]) do
            table.insert(cards, v)
        end
        return true, cards
    else
        return false
    end
end

function CardUtil.isSanTiao( dictionary )
    -- body
    local maxSame = 0
    local dian = 0
    local hasPair = false
    for i,v in ipairs(dictionary) do
        if #v >= maxSame then
            maxSame = #v
            dian = i
        end
        if #v == 2 then
            hasPair = true
        end     
    end
    if maxSame == 3 and not hasPair then
        local cards = {}
        -- 拿出最大的两张牌,不能是一对
        for i = #dictionary, 1, -1 do
            if #dictionary[i] == 1 then
                if #cards == 0 then
                    table.insert(cards, dictionary[i][1])
                elseif #cards == 1 then
                    table.insert(cards, 1, dictionary[i][1]) -- 为了按牌型升序排列,例如A8333
                end
            end
        end
        -- 拿出最大的三条
        for i = 1, 3 do
            table.insert(cards, dictionary[dian][i])
        end
        return true, cards
    else 
        return false
    end
end

function CardUtil.isTwoPairs(dictionary)
    if #dictionary[1] > 0 and dictionary[1][1].dian == 1 then
        dictionary[1] = {}
    end
    local pairCount = 0
    local maxSame = 0
    local maxPairIndex = 0
    local secMaxPairIndex = 0
    for i = #dictionary, 1, -1 do
        if #dictionary[i] == 2 then
            pairCount = pairCount + 1
            if maxPairIndex == 0 then
                maxPairIndex = i
            elseif secMaxPairIndex == 0 then
                secMaxPairIndex = i
            end
        end
        if #dictionary[i] >= maxSame then
            maxSame = #dictionary[i]
        end
    end
    if pairCount >= 2 and maxSame == 2 then
        local cards = {}
        -- 取出最大的一张
        for i = #dictionary, 1, -1 do
            if #dictionary[i] >= 1 and i ~= maxPairIndex and i ~= secMaxPairIndex then -- 剩下的一张可能从第三对两对里取,比如AAKKJJ
                table.insert(cards, dictionary[i][1])
                break
            end
        end
        -- 取出最大的两对
        for i = 1, 2 do table.insert(cards, dictionary[secMaxPairIndex][i]) end -- 倒序
        for i = 1, 2 do table.insert(cards, dictionary[maxPairIndex][i]) end
        return true, cards
    else
        return false
    end
end

function CardUtil.isOnePair(dictionary)
    local pairCount = 0
    local maxSame = 0
    local pairIndex = 0
    for i,v in ipairs(dictionary) do
        if #v == 2 then
            pairCount = pairCount + 1
            if pairIndex == 0 then
                pairIndex = i
            end
        end
        if #v >= maxSame then
            maxSame = #v
        end
    end
    if pairCount == 1 then
        local cards = {}
        -- 取最大的三张单牌
        for i = #dictionary, 1, -1 do
            if #dictionary[i] == 1 then
                if #cards < 3 then
                    table.insert(cards, 1, dictionary[i][1])
                else
                    break
                end
            end
        end
        -- 取出对子
        for i = 1,2 do table.insert(cards, dictionary[pairIndex][i]) end
        return true, cards
    else
        return false
    end
end

function CardUtil.getHighCard(dictionary)
    local cards = {}
    for i = #dictionary, 1, -1 do
        if #cards < 5 then
            if #dictionary[i] == 1 then
                local hasElement = false
                for _,v in pairs(cards) do
                    if dictionary[i][1].dian == v.dian then
                        hasElement = true
                    end
                end
                if not hasElement then
                    table.insert(cards, 1, dictionary[i][1])
                end
            end
        else
            break
        end
    end
    return cards
end

function CardUtil.isShunZiByDic(dictionary)
    for i = 14, 5, -1 do
        if #dictionary[i] > 0 then
            for j = i, i-4, -1 do
                -- print("i = ",i,"j = ",j)
                -- print("compare ",curIndex," ",nextIndex)
                
                if #dictionary[j] == 0 then
                    break
                elseif j == i - 4 then --比完一轮都没断,即是顺子
                    local cards = {}
                    local isASpecial = false
                    for k = j,i do
                        if k == j and dictionary[k][1].dian == 1 then isASpecial = true end --A2345的情况
                        table.insert(cards, dictionary[k][1])
                    end
                    return true, cards, isASpecial
                end
            end
        end
    end
    return false    
end

function CardUtil.isTongHuaByDic(dictionary)
    for i,v in ipairs(dictionary) do
        if #v >= 5 then
            return true, v
        end
    end
    return false
end

-- tb 从点数小到大排列
-- 当isASpecial为true时,A的权值由正常的14变为1,例如A2345
function CardUtil.getCardPoint(tb, paiXing, isASpecial)
    local paiXingPoint = TYPE_POINTS[paiXing]
    local strPoint = ""
    isASpecial = isASpecial or false -- 正常情况A权值为14
    for i,v in ipairs(tb) do
        if v.dian < 10 then
            if v.dian == 1 then
                if isASpecial then
                    strPoint = strPoint.."01"
                else
                    strPoint = "14"..strPoint
                end
            else
                strPoint = "0"..tostring(v.dian)..strPoint
            end
        else
            strPoint = tostring(v.dian)..strPoint
        end
    end
    strPoint = paiXingPoint..strPoint
    local point = tonumber(strPoint)
    return point
end

-- 确定牌型
-- 按牌型不同算分
--[[
    主要思路:
    将手牌与公共牌合并,并按点数升序排序
    A一般权值为14,只有在顺子/同花顺中的A2345中才有可能权值为1
    将牌按点数分别装入索引1到14数组中,getDianDicSpec中A会放入1和14两个数组中,即有两个权值; 
    getDianDic14中A只会放入14数组中,即只有一个权值
    getHuaDic按花色放入四个数组
    1.先判断是否同花顺:判断是否同花,若是,则判断“同花的数组”是否同时为顺子
    2.判断是否四条,注意第5张牌有可能从对子或三条里面拿
    3.判断是否葫芦,注意第4,5张牌可能从另外的三条里面拿,如3334447
    4.判断是否同花,这在同花顺时已经判断过
    5.判断是否顺子,这里不可以用判断同花顺时的结果,因为那只是判断同花的几张牌是否顺子,
        并未包含其他花色的牌,比如红桃45679+黑桃8,红桃的数组不是顺子,但56789是顺子
        为此写了两个判断顺子的函数isTongHuaVecShunZi/isShunzi
    6.判断是否三条,这时不会有另外的对子或三条,否则早就判断为葫芦
    7.判断是否两对,注意可能有三对的情况
    8.判断是否一对
    9.若以上都不是,直接判断为高牌
--]]

-- 牌型得分
    -- "高牌"     1
    -- "一对"     2
    -- "两对"     3
    -- "三条"     4
    -- "顺子"     5
    -- "同花"     6
    -- "葫芦"     7
    -- "四条"     8
    -- "同花顺" 9

-- 输入
    -- hands: 手牌table,例如{{1,2},{3,4}}
    -- publics: 公共牌table,可有0/3/4/5张公共牌,例如{{3,3},{4,1},{4,3},{1,4}}
-- 输出
    -- paiXing:成牌牌型,例如9,为同花顺
    -- cardPoint:牌型得分,例如91413121110,前1或2位为牌型分值,和成牌牌型相对应,后面为每张牌的得分,直接比较得分可知牌型间大小
    -- returnVec:最大成牌,返回最大牌型的几张牌,例如{{4,10},{4,11},{4,12},{4,13},{4,1}}
function CardUtil.calculatePoint(hands, publics)
    local tb = TableUtil.concat(hands, publics)
    TableUtil.sort(tb)
    
    local dianDicSp = CardUtil.getDianDicSpec(tb)
    if DEBUG_LOG then CardUtil.printDianDic(dianDicSp) end
    local dianDic14 = CardUtil.getDianDic14(tb)
    if DEBUG_LOG then CardUtil.printDianDic(dianDic14) end
    local huaDic = CardUtil.getHuaDic(tb)
    if DEBUG_LOG then CardUtil.printHuaDic(huaDic) end

    local isTongHua, tongHuaVec = CardUtil.isTongHuaByDic(huaDic)
    if DEBUG_LOG then print("isTongHua=", isTongHua) end
    if DEBUG_LOG then if tongHuaVec then printT(tongHuaVec) end end
    local isTongHuaShun = false
    local isASpecial = false
    local isTongHuaVecShunZi = false
    local tongHuaShunVec = {}
    if isTongHua then
        if tongHuaVec[#tongHuaVec].dian == 1 then -- 需要处理一下vec
            if DEBUG_LOG then print("special") end
            local tmpVec = {}
            for _,v in pairs(tongHuaVec) do
                table.insert(tmpVec, v)
            end
            table.insert(tmpVec, 1, tongHuaVec[#tongHuaVec]) -- 如果有后面A,将A也加入最前面,类似生成dianDicSp
            if DEBUG_LOG then printT(tmpVec) end
            isTongHuaVecShunZi, tongHuaShunVec, isASpecial = CardUtil.isTongHuaVecShunZi(tmpVec)
        else
            isTongHuaVecShunZi, tongHuaShunVec, isASpecial = CardUtil.isTongHuaVecShunZi(tongHuaVec)
        end 
        isTongHuaShun = isTongHua and isTongHuaVecShunZi
    end
    if DEBUG_LOG then print("isTongHuaShun=",isTongHuaShun) end

    local typePoint = 0
    local cardPoint = 0
    local totalPoint = 0 -- 返回的牌型得分

    local paiXing = 0 -- 返回的牌型
    local returnVec = {} -- 返回选择哪几张牌

    if isTongHuaShun then -- 同花顺
        if DEBUG_LOG then print("tonghuashun") end
        if DEBUG_LOG then printT(tongHuaShunVec) end
        paiXing = 9
        cardPoint = CardUtil.getCardPoint(tongHuaShunVec, paiXing, isASpecial)
        returnVec = tongHuaShunVec -- 拿出同花的数组判断,如果也是顺子,则是同花顺,见上
    else
        local isSiTiao, siTiaoVec = CardUtil.isSiTiao(dianDic14)
        if DEBUG_LOG then print("isSiTiao=",isSiTiao) end
        if DEBUG_LOG then if siTiaoVec then TableUtil.print(siTiaoVec) end end
        if isSiTiao then -- 四条
            if DEBUG_LOG then print("siTiao") end
            paiXing = 8
            typePoint = TYPE_POINTS[paiXing]
            cardPoint = CardUtil.getCardPoint(siTiaoVec, paiXing)
            returnVec = siTiaoVec
        else
            local isHuLu, huLuVec = CardUtil.isHuLu(dianDic14)
            if DEBUG_LOG then print("isHuLu=  ",isHuLu) end
            if DEBUG_LOG then if isHuLu then TableUtil.print(huLuVec) end end
            if isHuLu then -- 葫芦
                if DEBUG_LOG then print("huLu") end
                paiXing = 7
                typePoint = TYPE_POINTS[paiXing]
                cardPoint = CardUtil.getCardPoint(huLuVec, paiXing)
                returnVec = huLuVec         
            elseif isTongHua then --同花
                if DEBUG_LOG then 
                    print("tonghua") 
                    if tongHuaVec then printT(tongHuaVec) end
                end
                paiXing = 6
                typePoint = TYPE_POINTS[paiXing]
                cardPoint = CardUtil.getCardPoint(tongHuaVec, paiXing)
                returnVec = tongHuaVec
            else 
                local isShunZi, shunZiVec, isASpecial = CardUtil.isShunZiByDic(dianDicSp) -- 只有顺子特殊处理,当A2345时权值为1
                if DEBUG_LOG then 
                    print("isShunzi=",isShunZi) 
                    if shunZiVec then printT(shunZiVec) end
                end             
                if isShunZi then--顺子
                    if DEBUG_LOG then print("shunzi") end
                    paiXing = 5
                    typePoint = TYPE_POINTS[paiXing]
                    cardPoint = CardUtil.getCardPoint(shunZiVec, paiXing, isASpecial)
                    returnVec = shunZiVec
                else
                    local isSanTiao, sanTiaoVec = CardUtil.isSanTiao(dianDic14)
                    if DEBUG_LOG then print("isSanTiao=",isSanTiao) end
                    if DEBUG_LOG then if isSanTiao then TableUtil.print(sanTiaoVec) end end
                    if isSanTiao then -- 三条
                        if DEBUG_LOG then print("santiao") end
                        paiXing = 4
                        typePoint = TYPE_POINTS[paiXing]
                        cardPoint = CardUtil.getCardPoint(sanTiaoVec, paiXing)
                        returnVec = sanTiaoVec
                    else
                        local isTwoPairs, twoPairsVec = CardUtil.isTwoPairs(dianDic14)
                        if DEBUG_LOG then print("isTwoPairs=",isTwoPairs) end
                        if DEBUG_LOG then if isTwoPairs then TableUtil.print(twoPairsVec) end end
                        if isTwoPairs then -- 两对
                            if DEBUG_LOG then print("two pairs") end
                            paiXing = 3
                            typePoint = TYPE_POINTS[paiXing]
                            cardPoint = CardUtil.getCardPoint(twoPairsVec, paiXing)
                            returnVec = twoPairsVec
                        else
                            local isOnePair, onePairVec = CardUtil.isOnePair(dianDic14)
                            if DEBUG_LOG then print("isOnePair=",isOnePair) end
                            if DEBUG_LOG then if isOnePair then TableUtil.print(onePairVec) end end
                            if isOnePair then -- 一对
                                if DEBUG_LOG then print("one pair") end
                                paiXing = 2
                                typePoint = TYPE_POINTS[paiXing]
                                cardPoint = CardUtil.getCardPoint(onePairVec, paiXing)
                                returnVec = onePairVec
                            else -- 高牌
                                if DEBUG_LOG then print("isHighCard=  ", true) end
                                local cards = CardUtil.getHighCard(dianDic14)
                                if DEBUG_LOG then 
                                    printT(cards)
                                    print("high cards")
                                end
                                paiXing = 1
                                typePoint = TYPE_POINTS[paiXing]
                                cardPoint = CardUtil.getCardPoint(cards, paiXing)
                                returnVec = cards
                            end     
                        end 
                    end
                end
            end
        end
    end
    totalPoint = typePoint + cardPoint
    if DEBUG_LOG then print("totalPoint=",totalPoint) end
    return paiXing, cardPoint, returnVec
end

CardTest.lua

-- Author: luyuejun
-- Date: 2017/6/15

require("CardUtil")

CardTest = {}

CardTest.__index = CardTest

function CardTest:new()
    local o = {}
    setmetatable(o, self)

    return o
end

function CardTest.test(datas)
    local correct = 0
    local incorrect = 0
    for i,v in ipairs(datas) do
        local inputData = v.input
        local expectOutPutData = v.expectOutput
        local flag = CardTest.testOne(inputData, expectOutPutData)
        if flag then correct = correct + 1
        else incorrect = incorrect + 1 end
    end
    print("")
    print("correct=",correct)
    print("error=   ",incorrect)
end

function CardTest.testOne(inputData, expectOutPutData)
    local inputHands = inputData["H"]
    local inputPublics = inputData.P

    local hands = {}
    local publics = {}

    for _,v in pairs(inputHands) do
        local card = Card:new(v[1], v[2], true)
        table.insert(hands, card)
    end

    for _,v in pairs(inputPublics) do
        local card = Card:new(v[1], v[2], false)
        table.insert(publics, card)
    end

    expectOutPutCardType = expectOutPutData.T
    expectOutPutScore = expectOutPutData.S
    expectOutPutCards = expectOutPutData.C
    --printT(expectOutPutCards)
    local outPutCardType, outPutScore, outPutCards = CardUtil.calculatePoint(hands, publics)
    print("牌型 = "..PAI_XING_STRING[outPutCardType])
    print("得分 = "..outPutScore)
    print("牌组 = ")
    printT(outPutCards)
    local isCardType = CardTest.verifyCardType(expectOutPutCardType, outPutCardType)
    local isScore = CardTest.verifyScore(expectOutPutScore, outPutScore)
    local isCards = CardTest.verifyCards(expectOutPutCards, outPutCards)

    if isCardType and isScore and isCards then
        return true
    else
        return false
    end
end

function CardTest.verifyCardType(expectOutPutCardType, outPutCardType)
    if expectOutPutCardType == outPutCardType then
        return true
    else
        print("out put card type expected:"..expectOutPutCardType)
        print("output: "..outPutCardType)
        return false
    end
end

function CardTest.verifyScore(expectOutPutScore, outPutScore)
    if expectOutPutScore == outPutScore then
        return true
    else
        print("out put score expected:"..expectOutPutScore)
        print("output: "..outPutScore)
        return false
    end
end

function CardTest.verifyCards(expectOutPutCards, outPutCards)
    local flag = true
    for i,v in ipairs(expectOutPutCards) do
        -- print("compare-----")
        -- printC(outPutCards[i])
        if not CardTest.sameCard(v, outPutCards[i]) then
            print("out put cards "..tostring(i).." expected:")
            print("hua=",v[1],"dian=",v[2])
            print("output:")
            printC(outPutCards[i])
            flag = false
        end
    end
    return flag
end

function CardTest.sameCard(inputCard, outPutCard)
    if inputCard[2] == outPutCard.dian then
        return true
    else
        return false
    end
end

TableUtil.lua

-- Author: luyuejun
-- Date: 2017/6/15

TableUtil = {}

function printT(tb)
    TableUtil.print(tb)
end

function TableUtil.concat(tb1, tb2)
    local newTb = {}
    for i,v in pairs(tb1) do
        table.insert(newTb, v)
    end
    if #tb2 > 0 then
        for i,v in pairs(tb2) do
            table.insert(newTb, v)
        end
    end
    return newTb
end

function TableUtil.print(tb)
    for i, v in ipairs(tb) do
        print(v.hua.." "..v.dian)
        if i == #tb then print("=========")
        else print("---") end
    end
end

function TableUtil.sort(tb, comps)
    local function defaultComps(a,b)
        return a.dian < b.dian
    end
    if not comps then
        comps = defaultComps
    end

    table.sort(tb, comps)
end

function TableUtil.uniqueConcat(tb1, tb2)
    for i,v1 in pairs(tb2) do
        local hasElement = false
        for _, v2 in pairs(tb1) do
            if v2.dian == v1.dian then
                hasElement = true
                break
            end
        end
        if not hasElement then
            table.insert(tb1, v1)
        end
    end
    return tb1
end

CardDealer.lua

-- Author: luyuejun
-- Date: 2017/6/15
require("CardUtil")

CardDealer = {
    cardStates = {

    }   
}

CardDealer.__index = CardDealer

function CardDealer:new()
    local o = {}
    setmetatable(o, self)

    return o
end

function CardDealer:reset()
    self.cardStates = {}
end

function CardDealer:dealTwoHands()
    local cards = {}
    --math.randomseed(tostring(os.time()):reverse():sub(1, 6))
    while #cards < 2 do
        local suit = math.random(1, 4)
        local rank = math.random(1, 13)
        local str = tostring(suit)..tostring(rank)
        -- print("suit=",suit)
        -- print("rank=",rank)
        -- print("str=",str)
        if self.cardStates[str] == nil then
            self.cardStates[str] = true
            local isHand = true
            local card = Card:new(suit, rank, isHand)
            table.insert(cards, card)
            -- print("insert str=",str)
        end
    end
    return cards
end

function CardDealer:dealPublic(amount)
    if amount < 0 or amount > 5 then
        print("CardDealer:dealPublic#amount error!")
        return
    else
        local cards = {}
        --math.randomseed(tostring(os.time()):reverse():sub(1, 6))
        while #cards < amount do
            local suit = math.random(1, 4)
            local rank = math.random(1, 13)
            local str = tostring(suit)..tostring(rank)
            -- print("suit=",suit)
            -- print("rank=",rank)
            --print("str=",str)
            if self.cardStates[str] == nil then
                self.cardStates[str] = true
                local isHand = false
                local card = Card:new(suit, rank, isHand)
                table.insert(cards, card)
            end
        end
        return cards
    end
end
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351