编辑代码

      
local FuncNormalExtra = {}

local NormalBingoType = {
    Horizontal1 = 1,
    Horizontal2 = 2,
    Horizontal3 = 3,
    Horizontal4 = 4,
    Horizontal5 = 5,
    Vertical1 = 6,
    Vertical2 = 7,
    Vertical3 = 8,
    Vertical4 = 9,
    Vertical5 = 10,
    LT_RB = 11,
    RT_LB = 12,
    Corner = 13,
    Count = 14 - 1
}
FuncNormalExtra.NormalBingoType = NormalBingoType

function FuncNormalExtra:checkIsBingo(card, excludeCheckTypes , assumeDaubCells)
    local data = {}
    for x = 1, 5 do
        data[x] = {}
        for y = 1, 5 do
            data[x][y] = card[(x - 1) * 5 + y]
        end
    end

    local bingoResult = { }
    for i = 1, NormalBingoType.Count, 1 do
        bingoResult[i] = false
    end

	local function checkIsMark( flag, i, j )
        if assumeDaubCells then
            for _, cellConfig in pairs(assumeDaubCells or { }) do
                if cellConfig[1] == i and cellConfig[2] == j then
                    return true
                end
            end
        end
        if flag[i][j] == 1 then
            return true
        end
        return false
    end
    
    --------------------------------
    -- check bingo in row
    -- * * * * *
    -- bingo type =  1 2 3 4 5
    local isBingo = false
    for i=1,5 do
        if not excludeCheckTypes or not excludeCheckTypes[i] then
            isBingo = true
            for j=1,5 do
                if not checkIsMark(data,i,j) then
                    isBingo = false
                    break
                end
            end
            if isBingo then
                bingoResult[i] = true
            end
        end
    end
    
    --------------------------------
    -- check bingo in column
    -- *
    -- *
    -- *
    -- *
    -- *
    -- bingo type =  6 7 8 9 10
    for i=1,5 do
        if not excludeCheckTypes or not excludeCheckTypes[i + 5] then
            isBingo = true
            for j=1,5 do
                if not checkIsMark(data,j,i) then 
                    isBingo = false
                    break
                end
            end
            if isBingo then
                bingoResult[i + 5] = true
            end
        end
    end
    
    --------------------------------
    -- check bingo in angle line
    -- *     |     *
    --  *    |    *
    --   *   |   *
    --    *  |  *
    --     * | *
    -- bingo type =  11 12
    if not excludeCheckTypes or not excludeCheckTypes[11] then
        isBingo = true
        for i=1,5 do
            if not checkIsMark(data,i,i) then
                isBingo = false
                break
            end
        end
        
        if isBingo then
            bingoResult[11] = true
        end
    end
        
    if not excludeCheckTypes or not excludeCheckTypes[12] then
        isBingo = true
        for i=1,5 do
            if not checkIsMark(data,i,6-i) then 
                isBingo = false
                break
            end
        end
        
        if isBingo then
            bingoResult[12] = true
        end
    end
    
    --------------------------------
    -- check bingo in angle line
    -- *     *
    --
    --
    --
    -- *     *
    -- bingo type =  13
    if not excludeCheckTypes or not excludeCheckTypes[13] then
        if checkIsMark(data,1,1) and 
        checkIsMark(data,1,5) and 
        checkIsMark(data,5,1) and 
        checkIsMark(data,5,5) then
            bingoResult[13] = true
        end 
    end
    
    return bingoResult
end

-- 一个Board的位置信息 {
--     1 , 2 , 3 , 4 , 5 , 第一行
--     6 , 7 , 8 , 9 , 10, 第二行
--     11, 12, 13, 14, 15, 第三行
--     16, 17, 18, 19, 20, 第四行
--     21, 22, 23, 24, 25  第五行
-- }

--[[********************** 可修改参数 start **********************]]
local BASE_PROBABILITY = 80        -- 基础概率(总概率100)
local ADD_PROBABILITY = 5         -- 增加概率
local MARK_PROBABILITY = 28       -- 标记到数字有效的概率(总概率100) 先判断是否会被标记 再计算标记有效
local ROUND_BALL_COUNT = 1        -- 每局单卡球数

local LoopCount = 1000           -- 循环次数。
local DebugOut = false              -- 开启调试。开启后,只会计算一遍,会把每次读球数据打印出来,可以核对是否计算错误。
if DebugOut then
    LoopCount = 1
end
--[[********************** 可修改参数  end  **********************]]
local MaxY = 5
local MaxX = 5
local CellCount = MaxY * MaxX

local function grid2Pos(grid)
    return (grid - 1) % MaxY + 1, math.ceil(grid / MaxX)
end

local function pos2Grid(x, y)
    return (y - 1) * MaxX + x
end

local function dump_value_(v)
    if type(v) == "string" then
        v = "\"" .. v .. "\""
    end
    return tostring(v)
end
local function dump(value, description, nesting)
    if type(nesting) ~= "number" then nesting = 3 end

    local lookupTable = {}
    local result = {}

    -- local traceback = string.split(debug.traceback("", 2), "\n")
    -- print("dump from: " .. string.trim(traceback[3]))

    local function dump_(value, description, indent, nest, keylen)
        description = description or "<var>"
        local spc = ""
        if type(keylen) == "number" then
            spc = string.rep(" ", keylen - string.len(dump_value_(description)))
        end
        if type(value) ~= "table" then
            result[#result +1 ] = string.format("%s%s%s = %s", indent, dump_value_(description), spc, dump_value_(value))
        elseif lookupTable[tostring(value)] then
            result[#result +1 ] = string.format("%s%s%s = *REF*", indent, dump_value_(description), spc)
        else
            lookupTable[tostring(value)] = true
            if nest > nesting then
                result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, dump_value_(description))
            else
                result[#result +1 ] = string.format("%s%s = {", indent, dump_value_(description))
                local indent2 = indent.."    "
                local keys = {}
                local keylen = 0
                local values = {}
                for k, v in pairs(value) do
                    keys[#keys + 1] = k
                    local vk = dump_value_(k)
                    local vkl = string.len(vk)
                    if vkl > keylen then keylen = vkl end
                    values[k] = v
                end
                table.sort(keys, function(a, b)
                    if type(a) == "number" and type(b) == "number" then
                        return a < b
                    else
                        return tostring(a) < tostring(b)
                    end
                end)
                for i, k in ipairs(keys) do
                    dump_(values[k], k, indent2, nest + 1, keylen)
                end
                result[#result +1] = string.format("%s}", indent)
            end
        end
    end
    dump_(value, description, "- ", 1)

    for i, line in ipairs(result) do
        print(line)
    end
end

local function shuffleTable(t, startIndex, endIndex)
    if startIndex == nil then
        startIndex = 1
    end
    if endIndex == nil then
        endIndex = #t
    end
    for i = startIndex, endIndex do
        local randomIndex = math.random(startIndex, endIndex)
        local tempValue = t[i]
        t[i] = t[randomIndex]
        t[randomIndex] = tempValue
    end
end

function table.nums(t)
    local count = 0
    for k, v in pairs(t) do
        count = count + 1
    end
    return count
end

math.randomseed(os.time())
local function simulateBlackout()
    local boardConfig = {}   --blackout 卡面
    local markList = {}      --标记状态
    local waitBallList = {}  --待标记的球
    for i = 1, CellCount do
        boardConfig[i] = i
        waitBallList[i] = i
        markList[i] = 0
    end
    shuffleTable(boardConfig) --将卡面打乱

    local curProbability = BASE_PROBABILITY  --当前被标记的概率
    local curRound = 0   --当前局数
    local capCount = 0   --当前转换帽子数
    local bingoCount = 0 --当前bingo次数
    local bingoNeed = {} --bingo次数对应局数

    local function markOne()
        curRound = curRound + 1
        for count = 1, ROUND_BALL_COUNT do
            if math.random(1, 100) <= curProbability then
                if math.random(1, 100) <= MARK_PROBABILITY then
                    --被标记
                    curProbability = BASE_PROBABILITY
                    local index = table.remove(waitBallList, 1)
                    markList[index] = 1
                else
                    curProbability = curProbability + ADD_PROBABILITY
                    capCount = capCount + 1
                end
            else
                --未被标记
                curProbability = curProbability + ADD_PROBABILITY
            end
            local result = FuncNormalExtra:checkIsBingo(markList)
            local count = 0
            for i = 1, #result, 1 do
                if result[i] then
                    count = count + 1
                end
            end
            if bingoCount ~= count then
                bingoNeed[count] = curRound
            end
            bingoCount = count

            if #waitBallList == 0 then
                break
            end
        end
    end

    while true do
        markOne()
        if #waitBallList == 0 then
            break
        end
    end

    if DebugOut then
        print("标记所有数字需要%d局", curRound)
        print("标记完产生的帽子球", capCount)
        print("bingo类型对应局输", bingoNeed[1] or 0, bingoNeed[2] or 0, bingoNeed[3] or 0, bingoNeed[13] or 0)
    end

    return waitBallList, curRound, capCount, bingoNeed
end

local blackout = 0
local blackoutCap = 0
local blackoutBingo = {}
for count = 1, LoopCount do
    local waitBallList, curRound, capCount, bingoNeed = simulateBlackout()
    blackout = blackout + curRound
    blackoutCap = blackoutCap + capCount
    blackoutBingo[1] = (blackoutBingo[1] or 0) + (bingoNeed[1] or 0)
    blackoutBingo[2] = (blackoutBingo[2] or 0) + (bingoNeed[2] or 0)
    blackoutBingo[3] = (blackoutBingo[3] or 0) + (bingoNeed[3] or 0)
    blackoutBingo[13] = (blackoutBingo[13] or 0) + (bingoNeed[13] or 0)
end

print("平均标记完需要局数", blackout / LoopCount)
print("平均标记完转换帽子数", blackoutCap / LoopCount)
print("平均每种bingo类型数", blackoutBingo[1] / LoopCount, blackoutBingo[2] / LoopCount, blackoutBingo[3] / LoopCount, blackoutBingo[13] / LoopCount)