utils_bt_supply.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. -- local utils_bt_grid = require("servers.battle.lib.utils_bt_grid")
  2. -- require("lib.lualib.luaext")
  3. local utils_bt_grid = require("utils_bt_grid")
  4. local battleAdapt = require "adapt.battleAdapt"
  5. local battleConst = require "battle.battleConst"
  6. local root = {}
  7. local function log2Client(core, logStr)
  8. if not core then
  9. print(logStr)
  10. return
  11. end
  12. core:notifyClientLog(logStr)
  13. end
  14. -- 色块补充。grids里,x:0~4,y:0~9
  15. function root:supply_grids(core, seat, grids, supplyType, is2v2)
  16. -- 每个颜色的数量
  17. local colorCountMap = {0, 0, 0, 0}
  18. local hasUpdate = false
  19. for _, v in ipairs(grids) do
  20. local color = v.color
  21. if color >= 1 and color <= 4 then
  22. colorCountMap[color] = colorCountMap[color] + 1
  23. elseif color == 0 then
  24. hasUpdate = true
  25. end
  26. end
  27. if not hasUpdate then
  28. -- 无需色块补充
  29. return
  30. end
  31. self:_drop(seat, grids)
  32. local colorMap = utils_bt_grid:grids_to_color_map(grids)
  33. -- 判断A类和B类是否启用,不启动的话,需要替换成L类
  34. if string.find(supplyType, "A") == 1 or string.find(supplyType, "B") == 1 then
  35. local linkInfo5 = self:_get_link_len_info(seat, colorMap, 5)
  36. local more5, count5 = linkInfo5.moreLen, linkInfo5.countLen
  37. local msg = string.format("色块补充日志:补充前状态 连线长度为5的数量: %d, 是否有长度超过5的连线: %s", count5, more5)
  38. log2Client(core, msg)
  39. if string.find(supplyType, "A") == 1 then
  40. if not (more5 or count5 >= 2) then
  41. -- A类色块补充,替换为L类色块补充
  42. supplyType = string.gsub(supplyType, "A", "L")
  43. else
  44. supplyType = "A"
  45. end
  46. else
  47. if not (more5 or count5 >= 1) then
  48. -- B类色块补充,替换为L类色块补充
  49. supplyType = string.gsub(supplyType, "B", "L")
  50. else
  51. supplyType = "B"
  52. end
  53. end
  54. end
  55. log2Client(core, string.format("色块补充日志:色块补充方案: %s", supplyType))
  56. -- updateList里,x:1~5,y:1~10
  57. local updateList
  58. if supplyType == "A" or supplyType == "B" then
  59. updateList = self:_supply_ab(core, seat, colorMap, colorCountMap, supplyType)
  60. elseif string.find(supplyType, "L") == 1 then
  61. updateList = self:_supply_l(core, seat, colorMap, colorCountMap, supplyType)
  62. elseif string.find(supplyType, "W") == 1 or string.find(supplyType, "R") == 1 then
  63. updateList = self:_supply_wr(core, seat, colorMap, colorCountMap, supplyType)
  64. else
  65. print("ERROR: 非法色块补充方案")
  66. end
  67. if updateList and #updateList > 0 then
  68. for _, v in ipairs(updateList) do
  69. local x, y = v.x - 1, v.y - 1
  70. self:_set_color(grids, x, y, v.color)
  71. end
  72. -- 补充万能色块的逻辑
  73. local colorMap2 = utils_bt_grid:grids_to_color_map(grids)
  74. local linkInfo4 = self:_get_link_len_info(seat, colorMap2, 4)
  75. local more4, count4 = linkInfo4.moreLen, linkInfo4.countLen
  76. local msg = string.format("色块补充日志:补充后状态 连线长度为4的数量: %d, 是否有长度超过4的连线: %s", count4, more4)
  77. log2Client(core, msg)
  78. local maxCount4 = is2v2 and 2 or 1
  79. if count4 <= maxCount4 and not more4 then
  80. local pos = updateList[math.random(#updateList)]
  81. local x, y = pos.x - 1, pos.y - 1
  82. self:_set_color(grids, x, y, battleConst.COLOR_TYPE.ALL)
  83. local msg = string.format("色块补充日志:符合变万能色块逻辑 (%d, %d) 变为万能色块", x, y)
  84. log2Client(core, msg)
  85. end
  86. end
  87. end
  88. -- 色块掉落。grids里,x:0~4,y:0~9
  89. function root:_drop(seat, grids)
  90. --[[
  91. seat: 当前回合操作的座位
  92. 1:下方操作,色块往下掉落,该列非空色块的y -1
  93. 2:上方操作,色块往上掉落,该列非空色块的y +1
  94. ]]
  95. local tempGridMap = {}
  96. local maxX = 0
  97. local maxY = 0
  98. for _, v in ipairs(grids) do
  99. local row, col = v.y + 1, v.x + 1
  100. if not tempGridMap[row] then
  101. tempGridMap[row] = {}
  102. end
  103. tempGridMap[row][col] = v
  104. maxX = math.max(maxX, col)
  105. maxY = math.max(maxY, row)
  106. end
  107. local w, h = maxX, maxY
  108. local startY, endY, stepY
  109. if seat == 1 then
  110. startY, endY, stepY = 1, h, 1
  111. else
  112. startY, endY, stepY = h, 1, -1
  113. end
  114. for col = 1, w do
  115. local emptyCount = 0
  116. for row = startY, endY, stepY do
  117. local grid = tempGridMap[row][col]
  118. if grid.color == 0 then
  119. emptyCount = emptyCount + 1
  120. -- 例如:第2格空的,补充到倒数第2行。y=10-1*(2-1)
  121. grid.y = endY - stepY * (emptyCount - 1) - 1
  122. else
  123. -- 例如:第9行往下掉2格。y=9-1*2
  124. grid.y = grid.y - stepY * emptyCount
  125. end
  126. end
  127. end
  128. end
  129. --[[ 判断“当前操作的敌方”可连线长度的情况
  130. moreLen: 连线长度为 len 的数量
  131. countLen: 是否有长度超过 len 的连线
  132. ]]
  133. function root:_get_link_len_info(seat, colorMap, len)
  134. local otherSeat = seat == 1 and 2 or 1
  135. local links = utils_bt_grid:get_map_max_link_list(otherSeat, colorMap)
  136. local countLen = 0
  137. local moreLen = false
  138. for _, v in ipairs(links) do
  139. if #v > len then
  140. moreLen = true
  141. break
  142. elseif #v == len then
  143. countLen = countLen + 1
  144. end
  145. end
  146. return {countLen = countLen, moreLen = moreLen}
  147. end
  148. -- L类色块补充,半场均衡。x:1~4,y:1~10
  149. function root:_supply_l(core, seat, colorMap, colorCountMap, supplyType)
  150. local ret = {}
  151. -- 特殊补充色块一方:当前操作的我方。随机补充
  152. local supplyPosList2 = self:_get_supply_pos_list(seat, colorMap)
  153. for _, v in ipairs(supplyPosList2) do
  154. local color = math.random(1, 4)
  155. table.insert(ret, {x = v.x, y = v.y, color = color})
  156. end
  157. -- 正常补充色块一方:当前操作的敌方。按方案补充
  158. local otherSeat = seat == 1 and 2 or 1
  159. local halfMap = utils_bt_grid:get_half_map(otherSeat, colorMap)
  160. local supplyPosList1 = self:_get_supply_pos_list(otherSeat, colorMap)
  161. -- 半场每个颜色的数量记录
  162. local halfCountMap = {0, 0, 0, 0}
  163. for _, v in ipairs(halfMap) do
  164. for _, vv in ipairs(v) do
  165. if vv >= 1 and vv <= 4 then
  166. halfCountMap[vv] = halfCountMap[vv] + 1
  167. end
  168. end
  169. end
  170. -- 排序一下
  171. table.sort(
  172. supplyPosList1,
  173. function(a, b)
  174. if a.y ~= b.y then
  175. if otherSeat == 1 then
  176. return a.y > b.y
  177. else
  178. return a.y < b.y
  179. end
  180. else
  181. return a.x < b.x
  182. end
  183. end
  184. )
  185. for _, v in ipairs(supplyPosList1) do
  186. local x, y = v.x, v.y
  187. local okColorList = {1, 2, 3, 4}
  188. local okColorWeightList = {}
  189. for _, v in ipairs(okColorList) do
  190. local allCount = halfCountMap[v]
  191. local weight = battleAdapt:getColorWeight(allCount, supplyType)
  192. table.insert(okColorWeightList, {v, weight})
  193. end
  194. local tempColor = self:random_with_weight(okColorWeightList)
  195. local msg = string.format("色块补充日志:L类色块补充权重: %s, 色块补充颜色: %s", tostring(okColorWeightList), tempColor)
  196. log2Client(core, msg)
  197. halfCountMap[tempColor] = halfCountMap[tempColor] + 1
  198. halfMap[y][x] = tempColor
  199. table.insert(ret, {x = x, y = y, color = tempColor})
  200. end
  201. return ret
  202. end
  203. -- L类色块补充,全场均衡。x:1~4,y:1~10
  204. function root:_supply_wr(core, seat, colorMap, colorCountMap, supplyType)
  205. local ret = {}
  206. -- 每个颜色补充的数量记录
  207. local suppleCountMap = {0, 0, 0, 0}
  208. -- 特殊补充色块一方:当前操作的我方。随机补充
  209. local supplyPosList2 = self:_get_supply_pos_list(seat, colorMap)
  210. for _, v in ipairs(supplyPosList2) do
  211. local color = math.random(1, 4)
  212. table.insert(ret, {x = v.x, y = v.y, color = color})
  213. suppleCountMap[color] = suppleCountMap[color] + 1
  214. end
  215. -- 正常补充色块一方:当前操作的敌方。按方案补充
  216. local otherSeat = seat == 1 and 2 or 1
  217. local halfMap = utils_bt_grid:get_half_map(otherSeat, colorMap)
  218. local supplyPosList1 = self:_get_supply_pos_list(otherSeat, colorMap)
  219. -- 排序一下
  220. table.sort(
  221. supplyPosList1,
  222. function(a, b)
  223. if a.y ~= b.y then
  224. if otherSeat == 1 then
  225. return a.y > b.y
  226. else
  227. return a.y < b.y
  228. end
  229. else
  230. return a.x < b.x
  231. end
  232. end
  233. )
  234. for _, v in ipairs(supplyPosList1) do
  235. local x, y = v.x, v.y
  236. local okColorList = {1, 2, 3, 4}
  237. local okColorWeightList = {}
  238. for _, v in ipairs(okColorList) do
  239. local allCount = colorCountMap[v] + suppleCountMap[v]
  240. local weight = battleAdapt:getColorWeight(allCount, supplyType)
  241. table.insert(okColorWeightList, {v, weight})
  242. end
  243. local tempColor = self:random_with_weight(okColorWeightList)
  244. local msg = string.format("色块补充日志:WR类色块补充权重: %s, 色块补充颜色: %s", tostring(okColorWeightList), tempColor)
  245. log2Client(core, msg)
  246. suppleCountMap[tempColor] = suppleCountMap[tempColor] + 1
  247. halfMap[y][x] = tempColor
  248. table.insert(ret, {x = x, y = y, color = tempColor})
  249. end
  250. return ret
  251. end
  252. -- A类、B类色块补充,全场均衡。x:1~4,y:1~10
  253. function root:_supply_ab(core, seat, colorMap, colorCountMap, supplyType)
  254. local ret = {}
  255. -- 每个颜色补充的数量记录
  256. local suppleCountMap = {0, 0, 0, 0}
  257. -- 特殊补充色块一方:当前操作的我方。随机补充
  258. local supplyPosList2 = self:_get_supply_pos_list(seat, colorMap)
  259. for _, v in ipairs(supplyPosList2) do
  260. local color = math.random(1, 4)
  261. table.insert(ret, {x = v.x, y = v.y, color = color})
  262. suppleCountMap[color] = suppleCountMap[color] + 1
  263. end
  264. -- 正常补充色块一方:当前操作的敌方。按方案补充
  265. local otherSeat = seat == 1 and 2 or 1
  266. local halfMap = utils_bt_grid:get_half_map(otherSeat, colorMap)
  267. local supplyPosList1 = self:_get_supply_pos_list(otherSeat, colorMap)
  268. -- 排序一下
  269. table.sort(
  270. supplyPosList1,
  271. function(a, b)
  272. if a.y ~= b.y then
  273. if otherSeat == 1 then
  274. return a.y > b.y
  275. else
  276. return a.y < b.y
  277. end
  278. else
  279. return a.x < b.x
  280. end
  281. end
  282. )
  283. for _, v in ipairs(supplyPosList1) do
  284. local x, y = v.x, v.y
  285. local okColorList = {}
  286. local maxLen = 4
  287. for color = 1, 4 do
  288. halfMap[y][x] = color
  289. local sameList = {}
  290. local nextPos = {x = x, y = y}
  291. self:_find_same_color_list(halfMap, sameList, nextPos, color)
  292. if #sameList <= maxLen then
  293. table.insert(okColorList, color)
  294. end
  295. end
  296. if #okColorList == 0 then
  297. okColorList = {1, 2, 3, 4}
  298. end
  299. local okColorWeightList = {}
  300. for _, v in ipairs(okColorList) do
  301. local allCount = colorCountMap[v] + suppleCountMap[v]
  302. local weight = battleAdapt:getColorWeight(allCount, supplyType)
  303. table.insert(okColorWeightList, {v, weight})
  304. end
  305. local tempColor = self:random_with_weight(okColorWeightList)
  306. local msg = string.format("色块补充日志:AB类色块补充权重: %s, 色块补充颜色: %s", tostring(okColorWeightList), tempColor)
  307. log2Client(core, msg)
  308. suppleCountMap[tempColor] = suppleCountMap[tempColor] + 1
  309. halfMap[y][x] = tempColor
  310. table.insert(ret, {x = x, y = y, color = tempColor})
  311. end
  312. return ret
  313. end
  314. function root:_get_supply_pos_list(seat, colorMap)
  315. local maxH = #colorMap
  316. local minY, maxY
  317. if seat == 1 then
  318. minY, maxY = 1, maxH / 2
  319. else
  320. minY, maxY = maxH / 2 + 1, maxH
  321. end
  322. local ret = {}
  323. for y = minY, maxY do
  324. local oneRow = colorMap[y]
  325. for x, color in ipairs(oneRow) do
  326. if color == 0 then
  327. table.insert(ret, {x = x, y = y})
  328. end
  329. end
  330. end
  331. return ret
  332. end
  333. function root:_find_same_color_list(map, sameList, nextPos, color)
  334. local x1 = nextPos.x
  335. local y1 = nextPos.y
  336. for _, v in ipairs(sameList) do
  337. if v.x == x1 and v.y == y1 then
  338. -- 已经添加过了,跳过
  339. return
  340. end
  341. end
  342. table.insert(sameList, nextPos)
  343. -- 九宫格示例
  344. -- 1 2 3
  345. -- 4 x 6
  346. -- 7 8 9
  347. local deltaList = {
  348. {dx = -1, dy = 1},
  349. {dx = 0, dy = 1},
  350. {dx = 1, dy = 1},
  351. {dx = -1, dy = 0},
  352. {dx = 1, dy = 0},
  353. {dx = -1, dy = -1},
  354. {dx = 0, dy = -1},
  355. {dx = 1, dy = -1}
  356. }
  357. for _, v in ipairs(deltaList) do
  358. local x2 = x1 + v.dx
  359. local y2 = y1 + v.dy
  360. if map[y2] and map[y2][x2] and (map[y2][x2] == color or map[y2][x2] == 5) then
  361. self:_find_same_color_list(map, sameList, {x = x2, y = y2}, color)
  362. end
  363. end
  364. end
  365. function root:_set_color(grids, x, y, color)
  366. for _, v in ipairs(grids) do
  367. if x == v.x and y == v.y then
  368. v.color = color
  369. break
  370. end
  371. end
  372. end
  373. function root:_get_weight(count, supplyType)
  374. if count > 15 then
  375. return 0
  376. else
  377. return 15 - count
  378. end
  379. end
  380. function root:random_index_with_weights(list)
  381. local sum = 0
  382. for _, v in ipairs(list) do
  383. sum = sum + v
  384. end
  385. local ret = 1
  386. if sum > 0 then
  387. local r = math.random(1, sum)
  388. local didSum = 0
  389. for i, v in ipairs(list) do
  390. didSum = didSum + v
  391. if r <= didSum then
  392. ret = i
  393. break
  394. end
  395. end
  396. end
  397. return ret
  398. end
  399. -- data: {{3,10},{4,10},{5,10},{6,10},{7,10}}
  400. function root:random_with_weight(data)
  401. local weights = {}
  402. for _, v in ipairs(data) do
  403. table.insert(weights, v[2])
  404. end
  405. local index = self:random_index_with_weights(weights)
  406. return data[index][1]
  407. end
  408. function root:test()
  409. local seat = 1
  410. local grids = {}
  411. local supplyType = "A"
  412. for x = 0, 4 do
  413. for y = 0, 9 do
  414. table.insert(grids, {x = x, y = y, color = math.random(1, 5)})
  415. end
  416. end
  417. local list = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
  418. for _, v in ipairs(list) do
  419. grids[v].color = 0
  420. end
  421. local colorMap = utils_bt_grid:grids_to_color_map(grids)
  422. utils_bt_grid:print_map("===1 %s", colorMap)
  423. self:supply_grids(nil, seat, grids, supplyType, false)
  424. local colorMap = utils_bt_grid:grids_to_color_map(grids)
  425. utils_bt_grid:print_map("===2 %s", colorMap)
  426. end
  427. -- root:test()
  428. return root