utils_bt_grid.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. --[[
  2. 方形之路,格子相关算法处理
  3. ]]
  4. local root = {}
  5. local printf = print
  6. -- 最短的龙大小
  7. local MIN_LONG_SIZE = 3
  8. function root:grids_to_color_map(grids)
  9. local ret = {}
  10. for _, v in ipairs(grids) do
  11. local x, y = v.x + 1, v.y + 1
  12. if not ret[y] then
  13. ret[y] = {}
  14. end
  15. if v:cantLink() then
  16. ret[y][x] = -1
  17. else
  18. ret[y][x] = v.color
  19. end
  20. end
  21. return ret
  22. end
  23. function root:grids_to_id_map(grids)
  24. local ret = {}
  25. for _, v in ipairs(grids) do
  26. local x, y = v.x + 1, v.y + 1
  27. if not ret[y] then
  28. ret[y] = {}
  29. end
  30. ret[y][x] = v.id
  31. end
  32. return ret
  33. end
  34. -- 随机一个地图。1~4是四种颜色,5是万能色块,0是不可以连线的
  35. function root:random_map()
  36. local w, h = 5, 10
  37. local ret = {}
  38. for y = 1, h do
  39. local oneRow = {}
  40. for x = 1, w do
  41. local color = math.random(1, 4)
  42. table.insert(oneRow, color)
  43. end
  44. table.insert(ret, oneRow)
  45. end
  46. -- 随机3~4次万能色块。注意:可能4次都是同一个格子
  47. local allColorCount = math.random(3, 4)
  48. for i = 1, allColorCount do
  49. local y = math.random(h)
  50. local x = math.random(w)
  51. ret[y][x] = 5
  52. end
  53. -- local ret = {
  54. -- {3, 2, 3, 1, 2},
  55. -- {4, 3, 5, 2, 1},
  56. -- {3, 3, 3, 2, 3},
  57. -- {2, 4, 1, 2, 5},
  58. -- {1, 4, 4, 2, 1},
  59. -- {5, 1, 4, 2, 4},
  60. -- {2, 4, 1, 4, 1},
  61. -- {3, 4, 3, 4, 1},
  62. -- {3, 3, 4, 2, 4},
  63. -- {5, 3, 3, 2, 1}
  64. -- }
  65. return ret
  66. end
  67. -- 获取半场地图。seat=1下边,seat=2上边
  68. function root:get_half_map(seat, map)
  69. local maxH = #map
  70. local minY, maxY
  71. if seat == 1 then
  72. minY, maxY = 1, maxH / 2
  73. else
  74. minY, maxY = maxH / 2 + 1, maxH
  75. end
  76. local ret = {}
  77. for y, v in ipairs(map) do
  78. ret[y] = {}
  79. for x, vv in ipairs(v) do
  80. if y >= minY and y <= maxY then
  81. ret[y][x] = vv
  82. else
  83. ret[y][x] = 0
  84. end
  85. end
  86. end
  87. return ret
  88. end
  89. -- 获取所有的龙
  90. function root:get_all_long(halfMap)
  91. local h = #halfMap
  92. local w = #halfMap[1]
  93. -- 将地图分块
  94. local longList = self:split_map(halfMap)
  95. return longList
  96. end
  97. -- 将地图分块,同色连通的放在一块。万能色块可以重复使用
  98. function root:split_map(map)
  99. local ret = {}
  100. local h = #map
  101. local w = #map[1]
  102. -- 同色地图字典
  103. local sameColorMapDict = {
  104. [1] = self:new_zero_map(w, h),
  105. [2] = self:new_zero_map(w, h),
  106. [3] = self:new_zero_map(w, h),
  107. [4] = self:new_zero_map(w, h)
  108. }
  109. for y, oneRow in ipairs(map) do
  110. for x, color in ipairs(oneRow) do
  111. if color >= 1 and color <= 4 then
  112. local sameColorMap = sameColorMapDict[color]
  113. sameColorMap[y][x] = color
  114. elseif color == 5 then
  115. for _, sameColorMap in ipairs(sameColorMapDict) do
  116. sameColorMap[y][x] = color
  117. end
  118. end
  119. end
  120. end
  121. -- 每种颜色进行分割
  122. for _, sameColorMap in ipairs(sameColorMapDict) do
  123. local list = self:split_same_color_map(sameColorMap)
  124. self:array_merge(ret, list)
  125. end
  126. return ret
  127. end
  128. -- 对同色地图进行分割
  129. function root:split_same_color_map(sameColorMap)
  130. local ret = {}
  131. for y, oneRow in ipairs(sameColorMap) do
  132. for x, color in ipairs(oneRow) do
  133. if color >= 1 and color <= 4 then
  134. sameColorMap[y][x] = 0
  135. local pos = {x = x, y = y, color = color}
  136. local oneLong = {pos}
  137. self:pickup_one_long(oneLong, sameColorMap, pos)
  138. if #oneLong >= MIN_LONG_SIZE then
  139. table.insert(ret, oneLong)
  140. end
  141. end
  142. end
  143. end
  144. return ret
  145. end
  146. -- 拾取一条龙。与pos想连的色块加入到oneLong,并被设置为0
  147. function root:pickup_one_long(oneLong, sameColorMap, pos)
  148. local x1 = pos.x
  149. local y1 = pos.y
  150. local nextPosList = {}
  151. -- 九宫格示例
  152. -- 1 2 3
  153. -- 4 x 6
  154. -- 7 8 9
  155. local deltaList = {
  156. {dx = -1, dy = 1},
  157. {dx = 0, dy = 1},
  158. {dx = 1, dy = 1},
  159. {dx = -1, dy = 0},
  160. {dx = 1, dy = 0},
  161. {dx = -1, dy = -1},
  162. {dx = 0, dy = -1},
  163. {dx = 1, dy = -1}
  164. }
  165. for _, v in ipairs(deltaList) do
  166. local x2 = x1 + v.dx
  167. local y2 = y1 + v.dy
  168. if sameColorMap[y2] and sameColorMap[y2][x2] and sameColorMap[y2][x2] > 0 then
  169. local newPos = {x = x2, y = y2, color = sameColorMap[y2][x2]}
  170. table.insert(nextPosList, newPos)
  171. table.insert(oneLong, newPos)
  172. sameColorMap[y2][x2] = 0
  173. end
  174. end
  175. for _, v in ipairs(nextPosList) do
  176. self:pickup_one_long(oneLong, sameColorMap, v)
  177. end
  178. end
  179. -- 获取地图的所有龙(连通色块)
  180. function root:get_map_all_long(seat, map)
  181. local halfMap = self:get_half_map(seat, map)
  182. -- 要求是长度满足的龙
  183. local longList = self:get_all_long(halfMap)
  184. return longList
  185. end
  186. -- 获取地图的所有连线
  187. function root:get_map_all_link(seat, map)
  188. local halfMap = self:get_half_map(seat, map)
  189. local h = #halfMap
  190. local w = #halfMap[1]
  191. local longList = self:get_all_long(halfMap)
  192. local ret = {}
  193. for _, v in ipairs(longList) do
  194. local linkList = self:get_long_all_link(v, w, h)
  195. self:array_merge(ret, linkList)
  196. end
  197. return ret
  198. end
  199. -- 从一片相连的色块中,获取所有的连线
  200. -- 约束:连线间不存在包含关系
  201. function root:get_long_all_link(long, w, h)
  202. local map = self:long_to_map(long, w, h)
  203. local ret = {}
  204. local maxLen = 0
  205. for y, oneRow in ipairs(map) do
  206. for x, color in ipairs(oneRow) do
  207. if color > 0 then
  208. local result = {}
  209. local links = {}
  210. local pos = {x = x, y = y, color = color}
  211. self:dfs(result, links, map, pos)
  212. if #result == maxLen then
  213. if not self:is_same_link(result, ret) then
  214. table.insert(ret, result)
  215. end
  216. elseif #result > maxLen and #result >= MIN_LONG_SIZE then
  217. ret = {result}
  218. maxLen = #result
  219. end
  220. end
  221. end
  222. end
  223. return ret
  224. end
  225. -- 获取地图的最长连线
  226. function root:get_map_max_link(seat, map)
  227. local halfMap = self:get_half_map(seat, map)
  228. local h = #halfMap
  229. local w = #halfMap[1]
  230. local longList = self:get_all_long(halfMap)
  231. table.sort(
  232. longList,
  233. function(a, b)
  234. return #a > #b
  235. end
  236. )
  237. local maxLink = {}
  238. for _, v in ipairs(longList) do
  239. if #maxLink >= #v then
  240. break
  241. end
  242. local link = self:get_long_max_link(v, w, h)
  243. if #link > #maxLink then
  244. maxLink = link
  245. end
  246. end
  247. return maxLink
  248. end
  249. -- 获取地图的最长连线列表(同一片色块只取一个)
  250. function root:get_map_max_link_list(seat, map)
  251. local halfMap = self:get_half_map(seat, map)
  252. local h = #halfMap
  253. local w = #halfMap[1]
  254. local longList = self:get_all_long(halfMap)
  255. local maxLinkList = {}
  256. for _, v in ipairs(longList) do
  257. local link = self:get_long_max_link(v, w, h)
  258. table.insert(maxLinkList, link)
  259. end
  260. return maxLinkList
  261. end
  262. -- 从一片相连的色块中,获取最长的连线
  263. function root:get_long_max_link(long, w, h)
  264. local map = self:long_to_map(long, w, h)
  265. local ret = {}
  266. local maxLen = 0
  267. for y, oneRow in ipairs(map) do
  268. for x, color in ipairs(oneRow) do
  269. if color > 0 then
  270. local result = {}
  271. local links = {}
  272. local pos = {x = x, y = y, color = color}
  273. self:dfs(result, links, map, pos)
  274. if #result > maxLen and #result >= MIN_LONG_SIZE then
  275. ret = result
  276. maxLen = #result
  277. if #ret == #long then
  278. return ret
  279. end
  280. end
  281. end
  282. end
  283. end
  284. return ret
  285. end
  286. -- 拾取一条连线
  287. function root:dfs(result, links, map, pos, nearCountMap)
  288. local x, y, tempColor = pos.x, pos.y, pos.color
  289. map[y][x] = 0
  290. table.insert(links, pos)
  291. local nearMap = {
  292. {x = -1, y = -1},
  293. {x = -1, y = 0},
  294. {x = -1, y = 1},
  295. {x = 0, y = -1},
  296. {x = 0, y = 1},
  297. {x = 1, y = -1},
  298. {x = 1, y = 0},
  299. {x = 1, y = 1}
  300. }
  301. for _, v in ipairs(nearMap) do
  302. local x1 = x + v.x
  303. local y1 = y + v.y
  304. if map[y1] and map[y1][x1] and map[y1][x1] > 0 then
  305. local color1 = map[y1][x1]
  306. local pos1 = {x = x1, y = y1, color = color1}
  307. self:dfs(result, links, map, pos1)
  308. end
  309. end
  310. if #links > #result then
  311. for ii, vv in ipairs(links) do
  312. result[ii] = vv
  313. end
  314. elseif nearCountMap and #links == #result then
  315. local pos1 = links[#links]
  316. local pos2 = result[#result]
  317. if nearCountMap[pos2.y][pos2.x] < nearCountMap[pos1.y][pos1.x] then
  318. for ii, vv in ipairs(links) do
  319. result[ii] = vv
  320. end
  321. end
  322. end
  323. table.remove(links)
  324. map[y][x] = tempColor
  325. end
  326. ------------------------------ 工具方法 ------------------------------
  327. -- 新建一个全0的地图
  328. function root:new_zero_map(w, h)
  329. local ret = {}
  330. for y = 1, h do
  331. local oneRow = {}
  332. for x = 1, w do
  333. table.insert(oneRow, 0)
  334. end
  335. table.insert(ret, oneRow)
  336. end
  337. return ret
  338. end
  339. -- 合并数值
  340. function root:array_merge(dest, src)
  341. for _, v in ipairs(src) do
  342. table.insert(dest, v)
  343. end
  344. end
  345. -- long 转 地图
  346. function root:long_to_map(long, w, h)
  347. local map = self:new_zero_map(w, h)
  348. for _, v in ipairs(long) do
  349. map[v.y][v.x] = v.color
  350. end
  351. return map
  352. end
  353. -- 地图 转 long
  354. function root:map_to_long(map)
  355. local long = {}
  356. for y, oneRow in ipairs(map) do
  357. for x, color in ipairs(oneRow) do
  358. if color > 0 then
  359. table.insert(long, {x = x, y = y, color = color})
  360. end
  361. end
  362. end
  363. return long
  364. end
  365. --[[ 判断是否同一条连线
  366. 条件1:数量一样
  367. 条件2:首尾一样或相反(落点一样)
  368. 条件3:都是一样的格子
  369. ]]
  370. function root:is_same_link(link, list)
  371. local oneLink = list[1]
  372. if #link ~= #oneLink then
  373. -- 不是 数量一样
  374. return false
  375. end
  376. local linkX1, linkY1 = link[1].x, link[1].y
  377. local linkXN, linkYN = link[#link].x, link[#link].y
  378. local linkKey = self:get_link_key(link)
  379. for _, v in ipairs(list) do
  380. local x1, y1 = v[1].x, v[1].y
  381. local xN, yN = v[#v].x, v[#v].y
  382. if
  383. (linkX1 == x1 and linkY1 == y1 and linkXN == xN and linkYN == yN) or
  384. (linkX1 == xN and linkY1 == yN and linkXN == x1 and linkYN == y1)
  385. then
  386. -- 条件2:首尾一样或相反(落点一样)
  387. if linkKey == self:get_link_key(link) then
  388. -- 条件3:都是一样的格子
  389. return true
  390. end
  391. end
  392. end
  393. return false
  394. end
  395. -- 获取连线的key,格子相同字连线key一样
  396. function root:get_link_key(link)
  397. local list = {}
  398. for _, v in ipairs(link) do
  399. local x, y = v.x, v.y
  400. local flag = y * 10 + x
  401. table.insert(list, flag)
  402. end
  403. table.sort(list)
  404. return table.concat(list, "")
  405. end
  406. -- 获取点周围的节点数
  407. function root:get_near_pos_count(map, pos)
  408. local ret = 0
  409. local x, y = pos.x, pos.y
  410. local nearMap = {
  411. {x = -1, y = -1},
  412. {x = -1, y = 0},
  413. {x = -1, y = 1},
  414. {x = 0, y = -1},
  415. {x = 0, y = 1},
  416. {x = 1, y = -1},
  417. {x = 1, y = 0},
  418. {x = 1, y = 1}
  419. }
  420. for _, v in ipairs(nearMap) do
  421. local x1 = x + v.x
  422. local y1 = y + v.y
  423. if map[y1] and map[y1][x1] and map[y1][x1] > 0 then
  424. ret = ret + 1
  425. end
  426. end
  427. return ret
  428. end
  429. -- 打印一条龙
  430. function root:print_long(formatStr, long, w, h)
  431. local map = self:long_to_map(long, w, h)
  432. self:print_map(formatStr, map)
  433. end
  434. -- 打印地图
  435. function root:print_map(formatStr, map)
  436. local middleRow = #map / 2
  437. local rows = {}
  438. -- insert 在前面的原因:第一行输出在最后,即下面
  439. for y, oneRow in ipairs(map) do
  440. local str = string.format("| %s |", table.concat(oneRow, " "))
  441. table.insert(rows, 1, str)
  442. if y == middleRow then
  443. table.insert(rows, 1, "| - - - - - |")
  444. end
  445. end
  446. table.insert(rows, 1, "| - - - - - |")
  447. table.insert(rows, "| - - - - - |")
  448. local msg = table.concat(rows, "\n")
  449. printf(string.format(formatStr, msg))
  450. end
  451. -- 打印地图列表,水平排列
  452. function root:print_map_list(formatStr, mapList)
  453. local height = #mapList[1]
  454. local middleRow = height / 2
  455. local rows = {}
  456. for i = 1, height + 3 do
  457. table.insert(rows, "")
  458. end
  459. local rowMap = {}
  460. -- y: 01 02 03 04 05 | 06 07 08 09 10
  461. -- r: 12 11 10 09 08 | 06 05 04 03 02
  462. for i = 1, height do
  463. if i <= middleRow then
  464. rowMap[i] = height - i + 3 -- 10 - 1 + 3
  465. else
  466. rowMap[i] = height - i + 2 -- 10 - 6 + 2
  467. end
  468. end
  469. for _, v in ipairs(mapList) do
  470. for y, oneRow in ipairs(v) do
  471. local row = rowMap[y]
  472. local str = string.format(" | %s |", table.concat(oneRow, " "))
  473. rows[row] = rows[row] .. str
  474. end
  475. rows[1] = rows[1] .. " | - - - - - |"
  476. rows[middleRow + 2] = rows[middleRow + 2] .. " | - - - - - |"
  477. rows[height + 3] = rows[height + 3] .. " | - - - - - |"
  478. end
  479. local msg = table.concat(rows, "\n")
  480. printf(string.format(formatStr, msg))
  481. end
  482. -- 单元测试
  483. function root:test()
  484. math.randomseed(os.time())
  485. local map = self:random_map()
  486. -- local list = {{1, 1}, {1, 2}, {2, 2}, {3, 2}, {1, 3}, {1, 4}}
  487. -- for _, v in ipairs(list) do
  488. -- map[v[1]][v[2]] = 0
  489. -- end
  490. self:print_map("随机一个地图:\n%s", map)
  491. printf("")
  492. local map1 = self:get_half_map(1, map)
  493. self:print_map("获取下半部分地图:\n%s", map1)
  494. printf("")
  495. local map2 = self:get_half_map(2, map)
  496. self:print_map("获取上半部分地图:\n%s", map2)
  497. printf("")
  498. printf("获取上半部分地图的所有龙:")
  499. local map2 = self:get_half_map(2, map)
  500. local h = #map2
  501. local w = #map2[1]
  502. local longList = self:get_all_long(map2)
  503. for i, v in ipairs(longList) do
  504. local formatStr = "龙" .. i .. ":\n%s"
  505. self:print_long(formatStr, v, w, h)
  506. end
  507. printf("")
  508. printf("获取上半部分地图的所有最长连线:")
  509. local linkList = self:get_map_all_link(2, map)
  510. for i, v in ipairs(linkList) do
  511. local formatStr = "连线" .. i .. ":\n%s"
  512. self:print_long(formatStr, v, w, h)
  513. end
  514. printf("")
  515. printf("获取上半部分地图的最长连线:")
  516. local link = self:get_map_max_link(2, map)
  517. local formatStr = "最长连线:\n%s"
  518. self:print_long(formatStr, link, w, h)
  519. printf("")
  520. printf("获取上半部分地图的最长连线列表:")
  521. local linkList = self:get_map_max_link_list(2, map)
  522. for i, v in ipairs(linkList) do
  523. local formatStr = "最长连线" .. i .. ":\n%s"
  524. self:print_long(formatStr, v, w, h)
  525. end
  526. printf("")
  527. end
  528. function root:test_time(count)
  529. math.randomseed(os.time())
  530. local errorCount = 0
  531. for i = 1, count do
  532. local map = self:random_map()
  533. -- local map2 = self:get_half_map(2, map)
  534. -- self:get_all_long(map2)
  535. local linkList = self:get_map_all_link(2, map)
  536. -- local maxLink1 = {}
  537. -- for _, v in ipairs(linkList) do
  538. -- if #v > #maxLink1 then
  539. -- maxLink1 = v
  540. -- end
  541. -- end
  542. end
  543. printf("error count " .. errorCount)
  544. end
  545. -- root:test()
  546. -- root:test_time(1000)
  547. return root