-- local utils_bt_grid = require("servers.battle.lib.utils_bt_grid") -- require("lib.lualib.luaext") local utils_bt_grid = require("utils_bt_grid") local battleAdapt = require "adapt.battleAdapt" local battleConst = require "battle.battleConst" local root = {} local function log2Client(core, logStr) if not core then print(logStr) return end core:notifyClientLog(logStr) end -- 色块补充。grids里,x:0~4,y:0~9 function root:supply_grids(core, seat, grids, supplyType, is2v2) -- 每个颜色的数量 local colorCountMap = {0, 0, 0, 0} local hasUpdate = false for _, v in ipairs(grids) do local color = v.color if color >= 1 and color <= 4 then colorCountMap[color] = colorCountMap[color] + 1 elseif color == 0 then hasUpdate = true end end if not hasUpdate then -- 无需色块补充 return end self:_drop(seat, grids) local colorMap = utils_bt_grid:grids_to_color_map(grids) -- 判断A类和B类是否启用,不启动的话,需要替换成L类 if string.find(supplyType, "A") == 1 or string.find(supplyType, "B") == 1 then local linkInfo5 = self:_get_link_len_info(seat, colorMap, 5) local more5, count5 = linkInfo5.moreLen, linkInfo5.countLen local msg = string.format("色块补充日志:补充前状态 连线长度为5的数量: %d, 是否有长度超过5的连线: %s", count5, more5) log2Client(core, msg) if string.find(supplyType, "A") == 1 then if not (more5 or count5 >= 2) then -- A类色块补充,替换为L类色块补充 supplyType = string.gsub(supplyType, "A", "L") else supplyType = "A" end else if not (more5 or count5 >= 1) then -- B类色块补充,替换为L类色块补充 supplyType = string.gsub(supplyType, "B", "L") else supplyType = "B" end end end log2Client(core, string.format("色块补充日志:色块补充方案: %s", supplyType)) -- updateList里,x:1~5,y:1~10 local updateList if supplyType == "A" or supplyType == "B" then updateList = self:_supply_ab(core, seat, colorMap, colorCountMap, supplyType) elseif string.find(supplyType, "L") == 1 then updateList = self:_supply_l(core, seat, colorMap, colorCountMap, supplyType) elseif string.find(supplyType, "W") == 1 or string.find(supplyType, "R") == 1 then updateList = self:_supply_wr(core, seat, colorMap, colorCountMap, supplyType) else print("ERROR: 非法色块补充方案") end if updateList and #updateList > 0 then for _, v in ipairs(updateList) do local x, y = v.x - 1, v.y - 1 self:_set_color(grids, x, y, v.color) end -- 补充万能色块的逻辑 local colorMap2 = utils_bt_grid:grids_to_color_map(grids) local linkInfo4 = self:_get_link_len_info(seat, colorMap2, 4) local more4, count4 = linkInfo4.moreLen, linkInfo4.countLen local msg = string.format("色块补充日志:补充后状态 连线长度为4的数量: %d, 是否有长度超过4的连线: %s", count4, more4) log2Client(core, msg) local maxCount4 = is2v2 and 2 or 1 if count4 <= maxCount4 and not more4 then local pos = updateList[math.random(#updateList)] local x, y = pos.x - 1, pos.y - 1 self:_set_color(grids, x, y, battleConst.COLOR_TYPE.ALL) local msg = string.format("色块补充日志:符合变万能色块逻辑 (%d, %d) 变为万能色块", x, y) log2Client(core, msg) end end end -- 色块掉落。grids里,x:0~4,y:0~9 function root:_drop(seat, grids) --[[ seat: 当前回合操作的座位 1:下方操作,色块往下掉落,该列非空色块的y -1 2:上方操作,色块往上掉落,该列非空色块的y +1 ]] local tempGridMap = {} local maxX = 0 local maxY = 0 for _, v in ipairs(grids) do local row, col = v.y + 1, v.x + 1 if not tempGridMap[row] then tempGridMap[row] = {} end tempGridMap[row][col] = v maxX = math.max(maxX, col) maxY = math.max(maxY, row) end local w, h = maxX, maxY local startY, endY, stepY if seat == 1 then startY, endY, stepY = 1, h, 1 else startY, endY, stepY = h, 1, -1 end for col = 1, w do local emptyCount = 0 for row = startY, endY, stepY do local grid = tempGridMap[row][col] if grid.color == 0 then emptyCount = emptyCount + 1 -- 例如:第2格空的,补充到倒数第2行。y=10-1*(2-1) grid.y = endY - stepY * (emptyCount - 1) - 1 else -- 例如:第9行往下掉2格。y=9-1*2 grid.y = grid.y - stepY * emptyCount end end end end --[[ 判断“当前操作的敌方”可连线长度的情况 moreLen: 连线长度为 len 的数量 countLen: 是否有长度超过 len 的连线 ]] function root:_get_link_len_info(seat, colorMap, len) local otherSeat = seat == 1 and 2 or 1 local links = utils_bt_grid:get_map_max_link_list(otherSeat, colorMap) local countLen = 0 local moreLen = false for _, v in ipairs(links) do if #v > len then moreLen = true break elseif #v == len then countLen = countLen + 1 end end return {countLen = countLen, moreLen = moreLen} end -- L类色块补充,半场均衡。x:1~4,y:1~10 function root:_supply_l(core, seat, colorMap, colorCountMap, supplyType) local ret = {} -- 特殊补充色块一方:当前操作的我方。随机补充 local supplyPosList2 = self:_get_supply_pos_list(seat, colorMap) for _, v in ipairs(supplyPosList2) do local color = math.random(1, 4) table.insert(ret, {x = v.x, y = v.y, color = color}) end -- 正常补充色块一方:当前操作的敌方。按方案补充 local otherSeat = seat == 1 and 2 or 1 local halfMap = utils_bt_grid:get_half_map(otherSeat, colorMap) local supplyPosList1 = self:_get_supply_pos_list(otherSeat, colorMap) -- 半场每个颜色的数量记录 local halfCountMap = {0, 0, 0, 0} for _, v in ipairs(halfMap) do for _, vv in ipairs(v) do if vv >= 1 and vv <= 4 then halfCountMap[vv] = halfCountMap[vv] + 1 end end end -- 排序一下 table.sort( supplyPosList1, function(a, b) if a.y ~= b.y then if otherSeat == 1 then return a.y > b.y else return a.y < b.y end else return a.x < b.x end end ) for _, v in ipairs(supplyPosList1) do local x, y = v.x, v.y local okColorList = {1, 2, 3, 4} local okColorWeightList = {} for _, v in ipairs(okColorList) do local allCount = halfCountMap[v] local weight = battleAdapt:getColorWeight(allCount, supplyType) table.insert(okColorWeightList, {v, weight}) end local tempColor = self:random_with_weight(okColorWeightList) local msg = string.format("色块补充日志:L类色块补充权重: %s, 色块补充颜色: %s", tostring(okColorWeightList), tempColor) log2Client(core, msg) halfCountMap[tempColor] = halfCountMap[tempColor] + 1 halfMap[y][x] = tempColor table.insert(ret, {x = x, y = y, color = tempColor}) end return ret end -- L类色块补充,全场均衡。x:1~4,y:1~10 function root:_supply_wr(core, seat, colorMap, colorCountMap, supplyType) local ret = {} -- 每个颜色补充的数量记录 local suppleCountMap = {0, 0, 0, 0} -- 特殊补充色块一方:当前操作的我方。随机补充 local supplyPosList2 = self:_get_supply_pos_list(seat, colorMap) for _, v in ipairs(supplyPosList2) do local color = math.random(1, 4) table.insert(ret, {x = v.x, y = v.y, color = color}) suppleCountMap[color] = suppleCountMap[color] + 1 end -- 正常补充色块一方:当前操作的敌方。按方案补充 local otherSeat = seat == 1 and 2 or 1 local halfMap = utils_bt_grid:get_half_map(otherSeat, colorMap) local supplyPosList1 = self:_get_supply_pos_list(otherSeat, colorMap) -- 排序一下 table.sort( supplyPosList1, function(a, b) if a.y ~= b.y then if otherSeat == 1 then return a.y > b.y else return a.y < b.y end else return a.x < b.x end end ) for _, v in ipairs(supplyPosList1) do local x, y = v.x, v.y local okColorList = {1, 2, 3, 4} local okColorWeightList = {} for _, v in ipairs(okColorList) do local allCount = colorCountMap[v] + suppleCountMap[v] local weight = battleAdapt:getColorWeight(allCount, supplyType) table.insert(okColorWeightList, {v, weight}) end local tempColor = self:random_with_weight(okColorWeightList) local msg = string.format("色块补充日志:WR类色块补充权重: %s, 色块补充颜色: %s", tostring(okColorWeightList), tempColor) log2Client(core, msg) suppleCountMap[tempColor] = suppleCountMap[tempColor] + 1 halfMap[y][x] = tempColor table.insert(ret, {x = x, y = y, color = tempColor}) end return ret end -- A类、B类色块补充,全场均衡。x:1~4,y:1~10 function root:_supply_ab(core, seat, colorMap, colorCountMap, supplyType) local ret = {} -- 每个颜色补充的数量记录 local suppleCountMap = {0, 0, 0, 0} -- 特殊补充色块一方:当前操作的我方。随机补充 local supplyPosList2 = self:_get_supply_pos_list(seat, colorMap) for _, v in ipairs(supplyPosList2) do local color = math.random(1, 4) table.insert(ret, {x = v.x, y = v.y, color = color}) suppleCountMap[color] = suppleCountMap[color] + 1 end -- 正常补充色块一方:当前操作的敌方。按方案补充 local otherSeat = seat == 1 and 2 or 1 local halfMap = utils_bt_grid:get_half_map(otherSeat, colorMap) local supplyPosList1 = self:_get_supply_pos_list(otherSeat, colorMap) -- 排序一下 table.sort( supplyPosList1, function(a, b) if a.y ~= b.y then if otherSeat == 1 then return a.y > b.y else return a.y < b.y end else return a.x < b.x end end ) for _, v in ipairs(supplyPosList1) do local x, y = v.x, v.y local okColorList = {} local maxLen = 4 for color = 1, 4 do halfMap[y][x] = color local sameList = {} local nextPos = {x = x, y = y} self:_find_same_color_list(halfMap, sameList, nextPos, color) if #sameList <= maxLen then table.insert(okColorList, color) end end if #okColorList == 0 then okColorList = {1, 2, 3, 4} end local okColorWeightList = {} for _, v in ipairs(okColorList) do local allCount = colorCountMap[v] + suppleCountMap[v] local weight = battleAdapt:getColorWeight(allCount, supplyType) table.insert(okColorWeightList, {v, weight}) end local tempColor = self:random_with_weight(okColorWeightList) local msg = string.format("色块补充日志:AB类色块补充权重: %s, 色块补充颜色: %s", tostring(okColorWeightList), tempColor) log2Client(core, msg) suppleCountMap[tempColor] = suppleCountMap[tempColor] + 1 halfMap[y][x] = tempColor table.insert(ret, {x = x, y = y, color = tempColor}) end return ret end function root:_get_supply_pos_list(seat, colorMap) local maxH = #colorMap local minY, maxY if seat == 1 then minY, maxY = 1, maxH / 2 else minY, maxY = maxH / 2 + 1, maxH end local ret = {} for y = minY, maxY do local oneRow = colorMap[y] for x, color in ipairs(oneRow) do if color == 0 then table.insert(ret, {x = x, y = y}) end end end return ret end function root:_find_same_color_list(map, sameList, nextPos, color) local x1 = nextPos.x local y1 = nextPos.y for _, v in ipairs(sameList) do if v.x == x1 and v.y == y1 then -- 已经添加过了,跳过 return end end table.insert(sameList, nextPos) -- 九宫格示例 -- 1 2 3 -- 4 x 6 -- 7 8 9 local deltaList = { {dx = -1, dy = 1}, {dx = 0, dy = 1}, {dx = 1, dy = 1}, {dx = -1, dy = 0}, {dx = 1, dy = 0}, {dx = -1, dy = -1}, {dx = 0, dy = -1}, {dx = 1, dy = -1} } for _, v in ipairs(deltaList) do local x2 = x1 + v.dx local y2 = y1 + v.dy if map[y2] and map[y2][x2] and (map[y2][x2] == color or map[y2][x2] == 5) then self:_find_same_color_list(map, sameList, {x = x2, y = y2}, color) end end end function root:_set_color(grids, x, y, color) for _, v in ipairs(grids) do if x == v.x and y == v.y then v.color = color break end end end function root:_get_weight(count, supplyType) if count > 15 then return 0 else return 15 - count end end function root:random_index_with_weights(list) local sum = 0 for _, v in ipairs(list) do sum = sum + v end local ret = 1 if sum > 0 then local r = math.random(1, sum) local didSum = 0 for i, v in ipairs(list) do didSum = didSum + v if r <= didSum then ret = i break end end end return ret end -- data: {{3,10},{4,10},{5,10},{6,10},{7,10}} function root:random_with_weight(data) local weights = {} for _, v in ipairs(data) do table.insert(weights, v[2]) end local index = self:random_index_with_weights(weights) return data[index][1] end function root:test() local seat = 1 local grids = {} local supplyType = "A" for x = 0, 4 do for y = 0, 9 do table.insert(grids, {x = x, y = y, color = math.random(1, 5)}) end end local list = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} for _, v in ipairs(list) do grids[v].color = 0 end local colorMap = utils_bt_grid:grids_to_color_map(grids) utils_bt_grid:print_map("===1 %s", colorMap) self:supply_grids(nil, seat, grids, supplyType, false) local colorMap = utils_bt_grid:grids_to_color_map(grids) utils_bt_grid:print_map("===2 %s", colorMap) end -- root:test() return root