local propEnum = {
None = 0,
Gold = 1,
ManyGolds = 2,
MapFragment = 3,
Magnifier = 4,
Map = 5,
TreasureBox = 6,
Count = 7,
}
local PropEnum = propEnum
local numberOfProp = {
[propEnum.Gold] = 6,
[propEnum.ManyGolds] = 3,
[propEnum.MapFragment] = 4,
[propEnum.Magnifier] = 3,
}
local propToScore = {
[propEnum.Gold] = 1,
[propEnum.ManyGolds] = 3,
[propEnum.TreasureBox] = 6,
}
local fragmentsCountToMap = 2
local magnifierEffectCells = 2
local ScoreGetBingo = 20
local LoopCount = 10000
local DebugOut = false
if DebugOut then
LoopCount = 1
end
local InvalidNum = 0
local RowCount = 5
local ColumnCount = 5
local CellCount = RowCount * ColumnCount
math.randomseed(os.time())
local function indexToRowColumn(index)
return math.floor((index - 1) / ColumnCount) + 1, (index - 1) % ColumnCount + 1
end
local function rowColumnToIndex(row, column)
if row <= 0 or column <= 0 or row > RowCount or column > ColumnCount then
return nil
end
return (row - 1) * ColumnCount + column
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.contain(t, v)
for _, value in pairs(t) do
if value == v then
return true
end
end
return false
end
local function dump(list, string)
local str = "" .. string
for k, v in ipairs(list) do
str = str .. v .. ", "
end
print(str)
end
local PropToEmoji = {
[PropEnum.Gold] = "��",
[PropEnum.ManyGolds] = "��",
[PropEnum.MapFragment] = "��",
[PropEnum.Magnifier] = "��",
[PropEnum.Map] = "��️",
[PropEnum.TreasureBox] = "��",
}
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
local cellTagStr = " "
if self.tag ~= propEnum.None then
cellTagStr = PropToEmoji[self.tag]
end
return string.format("{%s, %s}", cellNumStr, cellTagStr)
end
function cell:beenTagged()
if self.cellNum == InvalidNum then
return false, 0, 0
end
local tag = self.tag
self.cellNum = InvalidNum
self.tag = PropEnum.None
return true, tag
end
return cell
end
local function addTagToBoard(board)
local addPropQueue = { }
for propId = PropEnum.None + 1, PropEnum.Count - 1, 1 do
local tagCount = numberOfProp[propId] or 0
while tagCount > 0 do
table.insert(addPropQueue, propId)
tagCount = tagCount - 1
end
end
shuffleTable(addPropQueue)
local candidateCellIndexs = { }
for cellIndex = 1, CellCount, 1 do
table.insert(candidateCellIndexs, cellIndex)
end
table.remove(candidateCellIndexs, 13)
shuffleTable(candidateCellIndexs)
while #addPropQueue > 0 and #candidateCellIndexs > 0 do
local propId = table.remove(addPropQueue, 1)
local tagCellIndex = table.remove(candidateCellIndexs, 1)
board[tagCellIndex]:setTag(propId)
end
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 ~= "" then
print(ballStr)
end
print(str)
if extraMsg and extraMsg ~= "" then
print(extraMsg)
end
if currentScore then
print("Current score: ", currentScore)
end
if not ignore then
print()
end
end
local function simulateReadBall()
local balls = { }
for i = 1, CellCount do
table.insert(balls, i)
end
local board = { }
for i = 1, CellCount do
table.insert(board, getOneCell(i))
end
shuffleTable(board)
addTagToBoard(board)
local numToBoardIndex = { }
for cellIndex, cell in ipairs(board) do
if cell.cellNum ~= InvalidNum then
numToBoardIndex[cell.cellNum] = cellIndex
end
end
shuffleTable(balls)
local totalScore = 0
local theScoreWhen15 = 0
local readBallCount = 0
if DebugOut then
PrintCurrentState(board, nil, nil, nil, false)
end
local currentFragmentCount = 0
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 propToScore[propType] then
totalScore = totalScore + propToScore[propType]
elseif propType == PropEnum.MapFragment then
currentFragmentCount = currentFragmentCount + 1
if currentFragmentCount == fragmentsCountToMap then
totalScore = totalScore + propToScore[PropEnum.TreasureBox]
currentFragmentCount = 0
end
elseif propType == PropEnum.Magnifier then
local indexs = { }
for cellIndex, cell in pairs(board) do
if cell.cellNum ~= InvalidNum and (cell.tag == PropEnum.Gold or cell.tag == PropEnum.ManyGolds) then
table.insert(indexs, cellIndex)
end
end
shuffleTable(indexs)
local remainingCount = magnifierEffectCells
while remainingCount > 0 and #indexs > 0 do
local cellIndex = table.remove(indexs, 1)
totalScore = totalScore + propToScore[board[cellIndex].tag]
board[cellIndex]:resetTag()
remainingCount = remainingCount - 1
end
end
local ballStr = string.format("读球: %d --- %d --- %d", readIndex, ballNum, readBallCount)
if DebugOut then
PrintCurrentState(board, totalScore, ballStr, string.format("fragments count: %d", currentFragmentCount))
end
if readBallCount <= 15 then
theScoreWhen15 = totalScore
end
if totalScore >= ScoreGetBingo then
break
end
end
if theScoreWhen15 > ScoreGetBingo then
theScoreWhen15 = ScoreGetBingo
end
return readBallCount, theScoreWhen15, totalScore >= ScoreGetBingo
end
local bingoNeedReadBall = { }
for i = 1, CellCount do
bingoNeedReadBall[i] = 0
end
local allTotalScoreWhen15 = 0
for i = 1, LoopCount do
local ballCountCompleteBingo, snailNodePositionWhen15, bingo = simulateReadBall()
if bingo then
bingoNeedReadBall[ballCountCompleteBingo] = bingoNeedReadBall[ballCountCompleteBingo] + 1
end
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)