编辑代码

      
--
-- Author: ZhouNan
-- Date: 2023-11-28 15:56
-- Description: 242主题
-- change: 
-- 
local Theme253Const = {}
---------------------- 可调参数 -------------------------------

Theme253Const.PROP_COUNT = {10, 2, 2} -- 道具生产数量 {爆竹、 双头、 礼炮}
Theme253Const.BINGO_TARGET = 4 -- bingo条件 消除几列

local CollectHistoryRound = 15 -- 统计多少次标记下的收集物
local MaxClickCount = 25 -- 测试的最多标记次数 最大为25
local LoopAllCount = 10000 -- 模拟测试的总次数
---------------------- 可调参数 end ----------------------------

local DEBUG_BOARD_COUNT = 10 -- 调试模式下生成的格子数量
local DEBUG = false
local DRAW_BOARD = true -- 打印出格子排布
local CollectCount = 0

local MAX_ROW = 5 -- 单卡的行数
local MAX_COL = 5 -- 单卡的列数
local BingoRateMap = {} -- bingo概率记录
local RunHistory = {}

---- 
local PropMap = {}
local PropInfo = {}
local colFlags = {}
local Score = 0

Theme253Const.PROP_ENUM = {
	NONE = 0,
	FIRECRACKER = 1,
	FIRECRACKER_2 = 2,
	FIREWORK = 3,
}

Theme253Const.MAX_ROW = MAX_ROW
Theme253Const.MAX_COL = MAX_COL

local BreakFlag = false

-----------------------------------------------------------------------------------------------
-----------------------------------    公共方法    ---------------------------------------------
-----------------------------------------------------------------------------------------------

local function clone(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
        local newObject = {}
        lookup_table[object] = newObject
        for key, value in pairs(object) do
            newObject[_copy(key)] = _copy(value)
        end
        return setmetatable(newObject, getmetatable(object))
    end
    return _copy(object)
end

table.keys = function (tab)
	local list = {}
	for k in pairs(tab) do
		table.insert(list, k)
	end
	return list
end

table.indexof = function (tab, tmp)
	for i, v in pairs(tab) do
		if v == tmp then
			return i
		end
	end
	return false
end

local printDebug = function (...)
	if DEBUG then
		print(...)
	end
end

local Theme253Helper = {}

function Theme253Helper.posToKey(r, c)
	if type(r) == "table" then
		return string.format("%d_%d", r[1], r[2])	
	else
		return string.format("%d_%d", r, c)
	end
end

function Theme253Helper.keyToPos(posKey)
	local r = tonumber(string.sub(posKey, 1, 1))
	local c = tonumber(string.sub(posKey, 3, 3))
	return r, c
end

function Theme253Helper.getLeftPos(map)
	local list = {}
	for r = 1, Theme253Const.MAX_ROW do
		for c = 1, Theme253Const.MAX_COL do
			if map[r][c] == 0 then
				table.insert(list, {r, c})
			end
		end
	end
	return list
end

function Theme253Helper.getUnclickedPos(map)
	local list = {}
	for r = 1, Theme253Const.MAX_ROW do
		for c = 1, Theme253Const.MAX_COL do
			if map[r][c] ~= -1 then
				table.insert(list, {r, c})
			end
		end
	end
	return list
end

function Theme253Helper.randomTable(tab, remove)
	local index = math.random(1, #tab)
	if remove then
		return table.remove(tab, index), index
	else
		return tab[index], index
	end
end

Theme253Helper.main = function()
	RunHistory = {}
	Theme253Helper.genCellsPos() -- 摆放标记位置的板子

	local flagBoard = Theme253Helper.genEmptyBoard() -- 模拟点击的格子
	for i = 1, MaxClickCount do
		local r, c = Theme253Helper.clickCardCell(flagBoard)
		flagBoard[r][c] = -1
		table.insert(RunHistory, "")
		table.insert(RunHistory, string.format("---- click ---- %s, %s", r, c))
		Theme253Helper.removeGrid(r, c)
		if Theme253Helper.checkBingo(PropMap) then
			-- if i == 1 then
			-- 	printHistory(true)
			-- end
			if i < CollectHistoryRound then
				CollectCount = CollectCount + Score
			end
			-- printDebug(">>>>>>>>>>>>>>>>>>>>>>>>>> bingo !!!!!!!!!!!!!")
			BingoRateMap[i] = (BingoRateMap[i] or 0) + 1
			break
		end
		if i == CollectHistoryRound then
			CollectCount = CollectCount + Score
		end
		if i >= MaxClickCount then
			print(string.format("------ %d个格子点完都没bingo !!!!!!", MaxClickCount))
			printHistory(true)
			-- BreakFlag = true
			return
		end
	end
	printHistory()
	-- print(string.format("总耗时:%6f", os.clock() - startTime))     5 5 5
	printDebug("================================================= finish ====")
	printDebug("")
end

Theme253Helper.checkBingo = function(board)
	local cnt = 0
	for col = 1, Theme253Const.MAX_COL do
		local flag = true
		for row = 1, Theme253Const.MAX_ROW do
			if board[row][col] ~= -1 then
				flag = false
				break
			end
		end
		if flag then
			cnt = cnt + 1
		end
	end
	if cnt >= Theme253Const.BINGO_TARGET then
		return true
	end
	return false
end

-----------------------------------------------------------------------------------------------
-----------------------------------    地图生成    ---------------------------------------------
-----------------------------------------------------------------------------------------------

-- 生成格子
Theme253Helper.genCellsPos = function()
	PropMap = Theme253Helper.genEmptyBoard()
	Score = 0
	colFlags = {}

	local firecrackerCnt = Theme253Const.PROP_COUNT[Theme253Const.PROP_ENUM.FIRECRACKER]
	local colList = {1, 2, 3, 4, 5}
	for i = 1, math.min(5, firecrackerCnt) do
		local random = math.random(1, #colList)
		local col = table.remove(colList, random)
		local row = math.random(1, Theme253Const.MAX_ROW)
		PropMap[row][col] = Theme253Const.PROP_ENUM.FIRECRACKER
	end
	if firecrackerCnt > 5 then
		firecrackerCnt = firecrackerCnt - 5
	else
		firecrackerCnt = 0
	end
	local cntList = clone(Theme253Const.PROP_COUNT)
	cntList[1] = firecrackerCnt

	local posList = Theme253Helper.getLeftPos(PropMap)
	for pType, cnt in ipairs(cntList) do
		for i = 1, cnt do
			local pos = Theme253Helper.randomTable(posList, true)
			local posKey = Theme253Helper.posToKey(pos)
			PropMap[pos[1]][pos[2]] = pType
		end
	end

	table.insert(RunHistory, "----------- 道具初始化位置 ")
	table.insert(RunHistory, {
		type = 1,
		board = clone(PropMap),
	})
end

Theme253Helper.history_1 = function (data)
	printTable(data.board)
end

-----------------------------------------------------------------------------------------------
-----------------------------------    移除格子    ---------------------------------------------
-----------------------------------------------------------------------------------------------

Theme253Helper.removeGrid = function (r, c)
	if PropMap[r][c] == -1 then
		return false
	end
	local propType = PropMap[r][c]
	PropMap[r][c] = -1
	table.insert(RunHistory, "-----------------------------------")
	if propType ~= 0 then
		table.insert(RunHistory, "------ 触发了道具:"..propType)
	end
	if not colFlags[c] then
        local flag = true
        for i = 1, Theme253Const.MAX_ROW do
            if PropMap[i][c] ~= -1 then
                flag = false
                break
            end
        end
        if flag then
            colFlags[c] = true
			if propType ~= Theme253Const.PROP_ENUM.FIRECRACKER then
				local backup = propType
				propType = Theme253Const.PROP_ENUM.FIRECRACKER
				local leftPosList = Theme253Helper.getLeftPos(PropMap)
				if #leftPosList > 0 then
					local pos = Theme253Helper.randomTable(leftPosList, true)
					PropMap[pos[1]][pos[2]] = backup
				end
			end
        end
    end
	if propType == Theme253Const.PROP_ENUM.FIRECRACKER then
		local row = -1
		for i = Theme253Const.MAX_ROW, 1, -1 do
			if PropMap[i][c] ~= -1 then
				row = i
				break
			end
		end
		if row ~= -1 then
			Theme253Helper.removeGrid(row, c)
			Score = Score + 1
		end
	elseif propType == Theme253Const.PROP_ENUM.FIRECRACKER_2 then
		local colList = {}
		for i = 1, Theme253Const.MAX_COL do
			local left = c - i
			local right = c + i
			if left > 0 and PropMap[r][left] ~= -1 then
				table.insert(colList, left)
			end
			if right <= Theme253Const.MAX_COL and PropMap[r][right] ~= -1 then
				table.insert(colList, right)
			end
		end
		for _, _c in ipairs(colList) do
			Theme253Helper.removeGrid(r, _c)
		end

	elseif propType == Theme253Const.PROP_ENUM.FIREWORK then
		local leftPosList = Theme253Helper.getUnclickedPos(PropMap)
		for i = 1, 2 do
			if #leftPosList > 0 then
				local pos = Theme253Helper.randomTable(leftPosList, true)
				if pos then
					table.insert(RunHistory, "------ 礼炮:"..pos[1].."  "..pos[2])
					Theme253Helper.removeGrid(pos[1], pos[2])
				end
			end
		end
	end
	table.insert(RunHistory, {
		type = 1,
		board = clone(PropMap)
	})
end

function Theme253Helper.propExchangePos()

end

-----------------------------------------------------------------------------------------------
-----------------------------------    other    -----------------------------------------------
-----------------------------------------------------------------------------------------------

-- 生成最原始的空板子
Theme253Helper.genEmptyBoard = function ()
	local board = {}
	for row = 1, MAX_ROW do
		board[row] = {}
		for col = 1, MAX_COL do
			board[row][col] = Theme253Const.PROP_ENUM.NONE
		end
	end
	return board
end

-- 模拟点击格子
Theme253Helper.clickCardCell = function(flagBoard)
	local emptyList = Theme253Helper.getLeftPos(flagBoard)
	local pos = Theme253Helper.randomTable(emptyList)
	return pos[1], pos[2]
end

function printTable(tab)
	local row = #tab
	local col = #tab[1]
	local str = ""
	for i = 1, row do
		local d = tab[i]
		for j = 1, col do
			str = str.."\t"..tab[i][j]
		end
		str = str.."\n"
	end
	print(str)
end

function printHistory(focus)
	if not DEBUG and not focus then
		return
	end
	for i, info in ipairs(RunHistory) do
		if type(info) == "string" then
			print(info)
		else
			local funcName = "history_"..info.type
			if Theme253Helper[funcName] then
				Theme253Helper[funcName](info)
			end
		end
	end
end

print("调试开关:", DEBUG)
print("格子打印开关:", DRAW_BOARD)
print("----------------------------")
if DEBUG then
	for i = 1, DEBUG_BOARD_COUNT do
		Theme253Helper.main()
	end
else
	print("总测试次数:", LoopAllCount)
	-- print(string.format("铲子数量:%d", ShovelCount))
	-- print(string.format("扫帚数量:%d", BroomCount))
	-- print(string.format("铲雪机数量:%d", MachineCount))
	-- print(string.format("bingo条件:%d", BingoCount))
	print("----------------------------")
	for i = 1, LoopAllCount do
		Theme253Helper.main()
		if BreakFlag then
			print("!!!!!!!!!!!!! break run")
			return
		end
	end
	local totalBingo = {}
	for i = 1, MaxClickCount do
		local info = BingoRateMap[i]
		if not info then
			BingoRateMap[i] = 0
		end
		if i == 1 then
			totalBingo[i] = BingoRateMap[i]
		else
			totalBingo[i] = totalBingo[i - 1] + BingoRateMap[i]
		end
		if info then
			local total = totalBingo[i]
			print("总共标记次数:"..i..", 该标记次数下总共的bingo次数:"..info..", bingo的比例:"..(info/LoopAllCount)..", 累计bingo次数:"..total.." , 累计bingo比例:"..(total/LoopAllCount) )
		end
	end
	print("----------------------------")
	print("标记格子数量发生bingo:", table.concat(BingoRateMap, ", "))
	print("标记累计发生bingo数量:", table.concat(totalBingo, ", "))

	print(string.format("%d 次标记时收集物:%s, 平均:%0.2f", CollectHistoryRound, CollectCount, CollectCount / LoopAllCount))
	-- local ballCount = 0
	-- local total = 0
	-- for ballcnt, num in pairs(SnowBallBingoCount) do
	-- 	ballCount = ballCount + ballcnt * num
	-- 	total = total + num 
	-- end
	-- print("---------------------------- bingo15次获得的雪球数 ".. ballCount / total)
	-- local keys = table.keys(SnowBallBingoCount)
	-- table.sort(keys)
	-- for _, ballcnt in pairs(keys) do
	-- 	print(string.format("收集雪球 %d 个 %d 次", ballcnt, SnowBallBingoCount[ballcnt]))
	-- end
	
end