local skynet = require "skynet" local battleConst = require "battle.battleConst" local battleLog = require "battle.battleLog" local battleUtils = require "battle.battleUtils" local battleAdapt = require "adapt.battleAdapt" local battleDefine = require "battle.battleDefine" local battleAiUtils = require "battleAiUtils" local utils_bt_supply = require "utils_bt_supply" local root = {} local Total_Weight = {2, 8, 11, 9, 7, 3} local Grid_Color_Weights = { {num = 7, colors = {{p1 = 4, p2 = 3}, {p1 = 3, p2 = 4}}}, {num = 8, colors = {{p1 = 4, p2 = 4}}}, {num = 9, colors = {{p1 = 5, p2 = 4}, {p1 = 4, p2 = 5}}}, {num = 10, colors = {{p1 = 5, p2 = 5}}}, {num = 11, colors = {{p1 = 5, p2 = 6}, {p1 = 6, p2 = 5}, {p1 = 7, p2 = 4}, {p1 = 4, p2 = 7}}}, {num = 12, colors = {{p1 = 6, p2 = 6}, {p1 = 7, p2 = 5}, {p1 = 5, p2 = 7}}}, {num = 13, colors = {{p1 = 7, p2 = 6}, {p1 = 6, p2 = 7}, {p1 = 8, p2 = 5}, {p1 = 5, p2 = 8}}}, {num = 14, colors = {{p1 = 7, p2 = 7}, {p1 = 8, p2 = 6}, {p1 = 6, p2 = 8}}}, {num = 15, colors = {{p1 = 8, p2 = 7}, {p1 = 7, p2 = 8}, {p1 = 9, p2 = 6}, {p1 = 6, p2 = 9}}}, {num = 16, colors = {{p1 = 8, p2 = 8}, {p1 = 9, p2 = 7}, {p1 = 7, p2 = 9}}}, {num = 17, colors = {{p1 = 9, p2 = 8}}}, {num = 18, colors = {{p1 = 9, p2 = 9}}}, {num = 19, colors = {{p1 = 10, p2 = 9}}}, {num = 20, colors = {{p1 = 10, p2 = 10}}} } ----------------------------------------------- ------------------色块生成逻辑------------------ --[[ 生成50个色块 ]] function root:initGrid(core) self:printToConsole("-->initGrid...") local needColorData1, needColorData2 = self:getGridTotalColorNum(core) local grids1 = self:createGridColor(core, 0, needColorData1) or {} local grids2 = self:createGridColor(core, 1, needColorData2) or {} self:printToConsole(string.format("结果1:%s", table.concat(grids1, ", "))) self:printToConsole(string.format("结果2:%s", table.concat(grids2, ", "))) return self:tableConcat(grids1, grids2) -- {3, 2, 3, 2, 4, 1, 4, 3, 2, 4, 2, 1, 4, 1, 1, 2, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 2, 3, 2, 4, 1, 4, 3, 2, 4, 2, 1, 4, 1, 1, 2, 3, 2, 3, 2, 3, 3, 2, 3, 3} end -- 获取双方 四种颜色总数 function root:getGridTotalColorNum(core) local totalWeight = Total_Weight local totalStartIndex = 9 local gridColorWeights = Grid_Color_Weights local totalRedIndex = self:randomWeightToIndex(totalWeight) local totalRed = totalStartIndex + totalRedIndex local totalGreenIndex = self:randomWeightToIndex(totalWeight) local totalGreen = totalStartIndex + totalGreenIndex local totalBlueIndex = self:randomWeightToIndex(totalWeight) local totalBlue = totalStartIndex + totalBlueIndex local total = core.areaW * core.areaH * 2 local totalYellow = total - totalRed - totalGreen - totalBlue -- self:printToConsole( string.format("totalRed=%d, totalGreen=%d, totalBlue=%d, totalYellow=%d", totalRed, totalGreen, totalBlue, totalYellow) ) local needColorData1 = {red = 0, green = 0, blue = 0, yellow = 0} local needColorData2 = {red = 0, green = 0, blue = 0, yellow = 0} local colorNum = self:getGridColorNumByColor(gridColorWeights, totalRed) needColorData1.red = colorNum.p1 needColorData2.red = colorNum.p2 colorNum = self:getGridColorNumByColor(gridColorWeights, totalGreen) needColorData1.green = colorNum.p1 needColorData2.green = colorNum.p2 colorNum = self:getGridColorNumByColor(gridColorWeights, totalBlue) needColorData1.blue = colorNum.p1 needColorData2.blue = colorNum.p2 colorNum = self:getGridColorNumByColor(gridColorWeights, totalYellow) needColorData1.yellow = colorNum.p1 needColorData2.yellow = colorNum.p2 -- self:printToConsole( string.format("needColorData1=%d,%d,%d,%d", needColorData1.red, needColorData1.yellow, needColorData1.green, needColorData1.blue) ); -- self:printToConsole( string.format("needColorData2=%d,%d,%d,%d", needColorData2.red, needColorData2.yellow, needColorData2.green, needColorData2.blue) ); return needColorData1, needColorData2 end function root:getGridColorNumByColor(gridColorWeights, totalNum) for i, v in ipairs(gridColorWeights) do if v.num == totalNum then local randomIndex = math.random(1, #v.colors) local colorObj = v.colors[randomIndex] return colorObj end end return {p1 = 0, p2 = 0} end -- 创建格子颜色(1红,2黄,3绿,4蓝) function root:createGridColor(core, castleIndex, needColorData) local gridColorList = {} local printGridCount = {0, 0, 0, 0} local colorWeights = {10, 10, 10, 10} local isCanLink = false local total = core.areaW * core.areaH for i = 1, total do colorWeights[1] = needColorData.red > 0 and 10 or 0 colorWeights[2] = needColorData.yellow > 0 and 10 or 0 colorWeights[3] = needColorData.green > 0 and 10 or 0 colorWeights[4] = needColorData.blue > 0 and 10 or 0 local tempColorWeights if not isCanLink and i >= total - 2 then colorWeights = {10, 0, 0, 0} if i == total then self:printToConsole("-------- 强制生成三块红色 --------") end else tempColorWeights = self:checkNearGridColor(gridColorList, colorWeights) end if colorWeights[1] == 0 and colorWeights[2] == 0 and colorWeights[3] == 0 and colorWeights[4] == 0 then -- self:printToConsole("重新初始化权重") colorWeights = {10, 10, 10, 10} if tempColorWeights[1].w == 0 and tempColorWeights[2].w == 0 and tempColorWeights[3].w == 0 and tempColorWeights[4].w == 0 then -- self:printToConsole('### 相邻色块都超过5 ###') else for j = 1, 4 do if tempColorWeights[j].w == 0 then colorWeights[j] = 0 end end end end local colorType = self:randomWeightToIndex(colorWeights) table.insert(gridColorList, colorType) printGridCount[colorType] = printGridCount[colorType] + 1 if colorType == 1 then needColorData.red = needColorData.red - 1 elseif colorType == 2 then needColorData.yellow = needColorData.yellow - 1 elseif colorType == 3 then needColorData.green = needColorData.green - 1 elseif colorType == 4 then needColorData.blue = needColorData.blue - 1 end if tempColorWeights and tempColorWeights[colorType].n >= 3 then isCanLink = true end end -- self:printToConsole( string.format("玩家%d:红-%d, 黄-%d,绿-%d, 蓝-%d", castleIndex, printGridCount[1], printGridCount[2], printGridCount[3], printGridCount[4]) ) return gridColorList end -- 找出相邻4种色块长度 function root:checkNearGridColor(gridColorList, colorWeights) local tempColorWeights = {{w = 10, n = 0}, {w = 10, n = 0}, {w = 10, n = 0}, {w = 10, n = 0}} if #gridColorList < 4 then return tempColorWeights end for i = 1, 4 do local nearGridColorCount = self:getNearGridColorCount(gridColorList, i) if nearGridColorCount > 5 then colorWeights[i] = 0 tempColorWeights[i].w = 0 -- self:printToConsole( string.format(" %d 相邻色块超过5,把权重调0", #gridColorList) ) end tempColorWeights[i].n = nearGridColorCount end return tempColorWeights end -- 找出某种色块相邻长度 function root:getNearGridColorCount(gridColorList, color, index) local gridIndex = index ~= nil and index or #gridColorList local list = {gridIndex} local index = 1 while index <= #list do local checkIndex = list[index] index = index + 1 local gridX = checkIndex % 5 local gridY = math.floor(checkIndex / 5) for i = -1, 1 do for j = -1, 1 do if (i ~= 0 or j ~= 0) and (gridX + i) >= 0 and (gridY + j) >= 0 and (gridX + i < 5) and (gridY + j < 5) then local tempIndex = self:getGridIndexByXY(gridX + i, gridY + j) local tempColor = gridColorList[tempIndex + 1] if tempColor and self:checkIsSameColor(tempColor, color) and self:findGridIndex(list, tempIndex) <= 0 then table.insert(list, tempIndex) if color == battleConst.COLOR_TYPE.ALL then color = tempColor end end end end end end -- self:printToConsole( string.format("[%d] color=%d, data=%s, list=%s", gridIndex, color, table.concat(gridColorList, "," ), table.concat(list, "," )) ) return #list end -- 判断色块是否相同,5是万能色块 function root:checkIsSameColor(tempColor, color) return tempColor == battleConst.COLOR_TYPE.ALL or color == battleConst.COLOR_TYPE.ALL or tempColor == color end function root:findGridIndex(list, tempIndex) for i, v in ipairs(list) do if tempIndex == v then return i end end return 0 end function root:getGridIndexByXY(gridX, gridY) return gridY * 5 + gridX end local function log2Client(core, logStr) if not logStr then return end battleLog:logClient(logStr) core:notifyClientLog(logStr) end ----------------------------------------------- ------------------色块补充逻辑------------------ function root:supplyGrids(core, actionCastle) local grids = core.map local curRound = core:getCurRound() -- 将需要补充的色块,重置颜色为0 for _, block in ipairs(grids) do if block.status == battleConst.BLOCK_STATUS.NEEDUPDATE then block.color = battleConst.COLOR_TYPE.INVAILD block:clear() end end local enemyCastle = core:getEnemyCastle(actionCastle) local supplyRound = enemyCastle.supplyRound local supplyWeight1 = enemyCastle.supplyWeight1 local supplyWeight2 = enemyCastle.supplyWeight2 local supplyWeight = curRound <= supplyRound and supplyWeight1 or supplyWeight2 local supplyType = getRandomWithWeight(supplyWeight) supplyType = "A57" local seat = actionCastle.seat local is2v2 = core.is2v2 utils_bt_supply:supply_grids(core, seat, grids, supplyType, is2v2) end -- 根据权重随机下标 function root:randomWeightToIndex(list) if list == nil or #list == 0 then return 1 end local sum = 0 for i, weight in ipairs(list) do sum = sum + weight end if sum <= 0 then return 1 end local ret = 1 local r = math.random(1, sum) local didSum = 0 for index, q in ipairs(list) do didSum = didSum + q if r <= didSum then ret = index break end end return ret end -- 获取可连线选择的龙 local function getOptionLinks(core, actionCastle) local allLinks = battleUtils:getAllLinkBlocks2(core, core.map, actionCastle.seat) table.sort( allLinks, function(a, b) return #a.linkIds > #b.linkIds end ) for i = #allLinks, 1, -1 do for j = 1, i - 1 do local member = true for _, v in ipairs(allLinks[i].linkIds) do if not table.member(allLinks[j].linkIds, v) then member = false break end end if member then table.remove(allLinks, i) break end end end return allLinks end local link = class("link") function link:ctor() self.ids = {} self.size = 0 self.lastY = 0 end local function createLink(core, actionCastle, linkIds, isFool) local l = link.new() l.ids = battleUtils:reverse(core.map, actionCastle.seat, linkIds, isFool) l.size = #linkIds local lastBlock = battleUtils:getColorBlockByID(core.map, l.ids[l.size]) l.lastY = lastBlock.y return l end local function findGridSuppressRoute(core, actionCastle) local nowTime = skynet.time() local allLinks = getOptionLinks(core, actionCastle) if table.empty(allLinks) then battleLog:logInfo(string.format("findGridSuppressRoute empty links error, uid %s", actionCastle.uid)) return end local result = {} local exceptLinks = {} local enableExSkill = core:getEnableExSkill(actionCastle) for _, v in ipairs(allLinks) do local ret, exSkillGridId, except = battleAiUtils:getLongEvaluate(core, actionCastle, v.linkIds, v.color, false, enableExSkill) if ret >= 1000000 then battleLog:logInfo(string.format("findGridSuppressRoute time cost %s", skynet.time() - nowTime)) return v.linkIds, exSkillGridId end if except then table.link( exceptLinks, battleUtils:getLinkBlocksWithoutExceptBlocks( core, core.map, actionCastle.seat, except.blocks, except.exceptBlocks ) ) end table.insert(result, {ids = v.linkIds, size = #v.linkIds, allPower = ret, exSkillGridId = exSkillGridId}) local linkIds = table.reverse(v.linkIds) ret, exSkillGridId = battleAiUtils:getLongEvaluate(core, actionCastle, linkIds, v.color, true, enableExSkill) if ret >= 1000000 then battleLog:logInfo(string.format("findGridSuppressRoute time cost %s", skynet.time() - nowTime)) return linkIds, exSkillGridId end table.insert(result, {ids = linkIds, size = #linkIds, allPower = ret, exSkillGridId = exSkillGridId}) end for _, v in ipairs(exceptLinks) do local ret, exSkillGridId = battleAiUtils:getLongEvaluate(core, actionCastle, v.linkIds, v.color, true, enableExSkill) if ret >= 1000000 then battleLog:logInfo(string.format("findGridSuppressRoute time cost %s", skynet.time() - nowTime)) return v.linkIds, exSkillGridId end table.insert(result, {ids = v.linkIds, size = #v.linkIds, allPower = ret, exSkillGridId = exSkillGridId}) local linkIds = table.reverse(v.linkIds) ret, exSkillGridId = battleAiUtils:getLongEvaluate(core, actionCastle, linkIds, v.color, true, enableExSkill) if ret >= 1000000 then battleLog:logInfo(string.format("findGridSuppressRoute time cost %s", skynet.time() - nowTime)) return linkIds, exSkillGridId end table.insert(result, {ids = linkIds, size = #linkIds, allPower = ret, exSkillGridId = exSkillGridId}) end table.sort( result, function(a, b) if a.allPower ~= b.allPower then return a.allPower > b.allPower end return a.size > b.size end ) battleLog:logInfo(string.format("findGridSuppressRoute time cost %s", skynet.time() - nowTime)) return result[1].ids, result[1].exSkillGridId end local function findGridCommonRoute(core, actionCastle) local nowTime = skynet.time() local allLinks = getOptionLinks(core, actionCastle) if table.empty(allLinks) then battleLog:logInfo(string.format("findGridCommonRoute empty links error, uid %s", actionCastle.uid)) return end local result = {} for _, v in ipairs(allLinks) do table.insert(result, createLink(core, actionCastle, v.linkIds, false)) end table.sort( result, function(a, b) if a.size ~= b.size then return a.size > b.size end if actionCastle.seat == battleConst.BATTLE_SEAT.DOWN then return a.lastY < b.lastY else return a.lastY > b.lastY end end ) local ids = result[1].ids local exSkillGridId local enableExSkill = core:getEnableExSkill(actionCastle) if enableExSkill then exSkillGridId = battleAiUtils:getNormatlExSkillGridId(core, actionCastle, ids) end battleLog:logInfo(string.format("findGridCommonRoute time cost %s", skynet.time() - nowTime)) return ids, exSkillGridId end -- 笨笨的连线AI local function findGridFoolRoute(core, actionCastle) local nowTime = skynet.time() -- 获取全部连线 local allLinks = getOptionLinks(core, actionCastle) if table.empty(allLinks) then battleLog:logInfo(string.format("findGridFoolRoute empty links error, uid %s", actionCastle.uid)) return end -- 愚蠢取落点低的规则:对手(真人)游戏局数小于5局,或者30%概率 local enemyCastle = core:getEnemyCastle(actionCastle) local mainPlayer = enemyCastle:getMainPlayer() local isFool = false if mainPlayer.battleCount < 5 then isFool = true else isFool = math.random(100) <= 30 end -- 全部连线结构化 local result = {} for _, v in ipairs(allLinks) do table.insert(result, createLink(core, actionCastle, v.linkIds, isFool)) end -- 连线排序:优先长度,其次落点 table.sort( result, function(a, b) if a.size ~= b.size then return a.size > b.size end if isFool then if actionCastle.seat == battleConst.BATTLE_SEAT.UP then return a.lastY < b.lastY else return a.lastY > b.lastY end else if actionCastle.seat == battleConst.BATTLE_SEAT.UP then return a.lastY > b.lastY else return a.lastY < b.lastY end end end ) -- 获取长度最长的连线 local linkIds = result[1].ids -- 10%的概率漏连。漏连数量在 BattleCommonConfig 配置 if math.random(100) <= 10 then local lessWeights = battleAdapt:getLessLinkWeights() local lessCount = RandomWithWeight(lessWeights) for i = 1, lessCount do if #linkIds == battleDefine.MIN_LINK_BLOCK then break end table.remove(linkIds, 1) end end local ids = linkIds local exSkillGridId local enableExSkill = core:getEnableExSkill(actionCastle) if enableExSkill then exSkillGridId = battleAiUtils:getNormatlExSkillGridId(core, actionCastle, ids) end battleLog:logInfo(string.format("findGridFoolRoute time cost %s", skynet.time() - nowTime)) return ids, exSkillGridId end local function findGridStupidRoute(core, actionCastle) local nowTime = skynet.time() -- 获取全部连线 local allLinks = getOptionLinks(core, actionCastle) if table.empty(allLinks) then battleLog:logInfo(string.format("findGridStupidRoute empty links error, uid %s", actionCastle.uid)) return end local isFool = true -- 全部连线结构化 local result = {} for _, v in ipairs(allLinks) do table.insert(result, createLink(core, actionCastle, v.linkIds, isFool)) end local ids local exSkillGridId = nil -- 随机一条连线 local linkIds = result[math.random(#result)].ids if #linkIds > 3 then ids = {} for i = 1, 3 do table.insert(ids, linkIds[i]) end else ids = linkIds end battleLog:logInfo(string.format("findGridStupidRoute time cost %s", skynet.time() - nowTime)) return ids, exSkillGridId end ----------------------------------------------- ------------------色块寻路逻辑------------------ --[[寻找最长的路线 ]] function root:findGridLongRoute(core, actionCastle, aiLinkType) if not aiLinkType then log.error("findGridLongRoute aiLinkType is nil") return end -- if aiLinkType == "W" and math.random(100) <= 20 then -- aiLinkType = "R" -- elseif aiLinkType == "R" and math.random(100) <= 20 then -- aiLinkType = "W" -- end -- aiLinkType = "R" log2Client(core, string.format("当前回合%s aiLinkType=%s", core:getCurRound(), aiLinkType)) if aiLinkType == "W" then return findGridSuppressRoute(core, actionCastle) elseif aiLinkType == "R" then return findGridCommonRoute(core, actionCastle) elseif aiLinkType == "L" then return findGridFoolRoute(core, actionCastle) elseif aiLinkType == "S" then return findGridStupidRoute(core, actionCastle) end battleLog:logInfo(string.format("findGridLongRoute error aiLinkType = %s", aiLinkType)) end -- 数组拷贝 function root:tableConcat(dest, src) local begin = #dest + 1 local len = #src for i = 0, len - 1 do dest[i + begin] = src[i + 1] end return dest end ------------------------- function root:printToConsole(str) battleLog:logInfo(str) end return root