编辑代码

-- 一个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  第五行
-- }
local propEnum = {
    None = 0,
    Corn = 1,           -- 玉米
    Wheat = 2,          -- 小麦
    Soybean = 3,        -- 大豆
    Count = 4,
}
local PropEnum = propEnum

--[[********************** 可修改参数 start **********************]]
local numberOfProp = {              -- 初始的时候,每种道具的数量。
    [propEnum.Corn] = 4,            -- 玉米
    [propEnum.Wheat] = 7,           -- 小麦
    [propEnum.Soybean] = 8,        -- 大豆
}
local propToScore = {
    [propEnum.Corn] = 4,
    [propEnum.Wheat] = 3,
    [propEnum.Soybean] = 2,
}
local CountToStartProducing = 3
local ScoreGetBingo = 30            -- 多少分达成bingo。

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

local InvalidNum = 0
local RowCount = 5
local ColumnCount = 5
local CellCount = RowCount * ColumnCount

math.randomseed(os.time())

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.contain(t, v)
    for _, value in pairs(t) do
        if value == v then
            return true
        end
    end
    return false
end

local EnergyToEmoji = {
    [propEnum.Corn] = "��",
    [propEnum.Wheat] = "��",
    [propEnum.Soybean] = "��",
}
local function getOneCell(number)
    local cell = { }
    cell.cellNum = number
    cell.tag = propEnum.None
    function cell:resetTag()
        self.tag = propEnum.None
    end
    function cell:setTag(tag)
        self.tag = tag
    end
    function cell:getDescription()
        local cellNumStr = "��"
        if self.cellNum ~= InvalidNum then
            cellNumStr = tostring(self.cellNum)
            if string.len(cellNumStr) == 1 then
                cellNumStr = cellNumStr .. " "
            end
        end
        
        if self.tag == propEnum.None then
            return string.format("{%s,   }", cellNumStr)
        else
            return string.format("{%s, %s}", cellNumStr, EnergyToEmoji[self.tag])
        end
    end

    -- 格子被点了。
    function cell:beenTagged()
        if self.cellNum == InvalidNum then
            return false, 0
        end
        self.cellNum = InvalidNum
        return true, self.tag
    end
    return cell
end

local function addTagToBoard(board)
    local currentIndex = 1
    for propId = PropEnum.None + 1, PropEnum.Count - 1, 1 do
        local tagCount = numberOfProp[propId] or 0
        while tagCount > 0 and currentIndex <= #board do
            board[currentIndex].tag = propId
            tagCount = tagCount - 1
            currentIndex = currentIndex + 1
        end
    end
    shuffleTable(board, 1, #board)
end

local function PrintCurrentState(board, currentScore, ballStr, extraMsg, ignore)
    local str = ""
    for i = 1, RowCount, 1 do
        for j = 1, ColumnCount, 1 do
            local cellIndex = (i - 1) * ColumnCount + j
            local cell = board[cellIndex]
            str = str .. string.format("%s    ", cell:getDescription())
        end
        if i ~= RowCount then
            str = str .. "\r\n"
        end
    end
    if ballStr and ballStr ~= InvalidNum then
        print("Read ball: ", ballStr)
    end
    if extraMsg and extraMsg ~= "" then
        print(extraMsg)
    end
    print(str)
    if currentScore then
        print(string.format("Current score: %d/%d", currentScore, ScoreGetBingo))
    end
    if not ignore then
        print()
    end
end

local function simulateReadBall()
    -- generated read balls.
    local balls = { }
    for i = 1, CellCount do
        table.insert(balls, i)
    end
    -- generate board.
    local board = { }
    for i = 1, CellCount do
        table.insert(board, getOneCell(i))
    end
    shuffleTable(board)
    -- generate tag.
    addTagToBoard(board)
    -- build map for board.
    local numToBoardIndex = { }
    for cellIndex, cell in ipairs(board) do
        if cell.cellNum ~= InvalidNum then
            numToBoardIndex[cell.cellNum] = cellIndex
        end
    end

    shuffleTable(balls)
    -- read balls
    local totalScore = 0

    local theScoreWhen15 = 0
    local readBallCount = 0

    if DebugOut then
        PrintCurrentState(board, nil, nil, nil, InvalidNum)
    end

    local cornIndexs = { }
    local wheatIndexs = { }
    local soybeanIndexs = { }
    local machineProps = { }
    while #balls > 0 do
        readBallCount = readBallCount + 1
        local ballNum = balls[1]
        table.remove(balls, 1)
        local readIndex = numToBoardIndex[ballNum]
        assert(readIndex ~= nil, string.format("Cant find ball num index: %d", ballNum))
        assert(board[readIndex].cellNum == ballNum or board[readIndex].cellNum == InvalidNum, "NumToBoardIndex Map Error!")

        local success, propType = board[readIndex]:beenTagged()
        if propType ~= PropEnum.None then
            table.insert(machineProps, propType)
        end

        local ballStr = string.format("%d ----- %d", ballNum, readBallCount)
        local str = "这个球读完后的机器: "
        for _, propId in pairs(machineProps) do
            if propId == PropEnum.Corn then
                str = str .. "��"
            elseif propId == PropEnum.Wheat then
                str = str .. "��"
            elseif propId == PropEnum.Soybean then
                str = str .. "��"
            end
        end

        if #machineProps == CountToStartProducing then
            local bet = 2
            for i = 2, #machineProps, 1 do
                if machineProps[i] ~= machineProps[i - 1] then
                    bet = 1
                    break
                end
            end
            local getScore = 0
            for _, prop in pairs(machineProps) do
                getScore = getScore + propToScore[prop] * bet
            end
            totalScore = totalScore + getScore
            machineProps = { }

            if DebugOut then
                PrintCurrentState(board, totalScore, ballStr, str .. "。开始制作,分数为制作后的分数。", true)
                print()
            end
        else
            if DebugOut then
                PrintCurrentState(board, totalScore, ballStr, str, true)
                print()
            end
        end

        if readBallCount <= 15 then
            theScoreWhen15 = totalScore
        end
        if totalScore >= ScoreGetBingo then
            break
        end
    end
    
    assert(totalScore >= ScoreGetBingo and readBallCount <= CellCount, "Config cannot reach bingo.")

    if theScoreWhen15 > ScoreGetBingo then
        theScoreWhen15 = ScoreGetBingo 
    end

    return readBallCount, theScoreWhen15
end

local bingoNeedReadBall = { }
for i = 1, CellCount do
    bingoNeedReadBall[i] = 0
end
local allTotalScoreWhen15 = 0
for i = 1, LoopCount do
    local ballCountCompleteBingo, snailNodePositionWhen15 = simulateReadBall()
    bingoNeedReadBall[ballCountCompleteBingo] = bingoNeedReadBall[ballCountCompleteBingo] + 1
    allTotalScoreWhen15 = allTotalScoreWhen15 + snailNodePositionWhen15
end
local bingoTotal = { }
bingoTotal[1] = 0
for i = 2, CellCount do
    bingoTotal[i] = bingoNeedReadBall[i] + bingoTotal[i - 1]
end

local strH = ""
local str1 = ""
local str2 = ""
for i = 1, #bingoNeedReadBall, 1 do
    local l1 = string.len(tostring(bingoNeedReadBall[i]))
    local l2 = string.len(tostring(bingoTotal[i]))
    local l = l1 > l2 and l1 or l2
    if l < string.len(tostring(i)) then
        l = string.len(tostring(i))
    end
    strH = strH .. string.format(string.format("%%%dd", l), i)
    str1 = str1 .. string.format(string.format("%%%dd", l), bingoNeedReadBall[i])
    str2 = str2 .. string.format(string.format("%%%dd", l), bingoTotal[i])
    if i ~= #bingoNeedReadBall then
        strH = strH .. ", "
        str1 = str1 .. ", "
        str2 = str2 .. ", "
    end
end

print("                  ", strH)
print("daub bingo count: ", str1)
print("cumulative bingo: ", str2)
print("aver score at 15: ", allTotalScoreWhen15 / LoopCount)