verify_all_maps.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #!/usr/bin/env python3
  2. """verify_all_maps.py — 8 张地图全量离线验证: 加载+BFS+A* 通用性证明。
  3. 每张图: 已知锚点(或自动扫可走格) → BFS 最远可达点 → A* 2格步长规划
  4. → 逐腿穿墙检查 → 报告耗时/腿数/结果。
  5. """
  6. from __future__ import annotations
  7. import sys
  8. import time
  9. from collections import deque
  10. sys.path.insert(0, "src")
  11. from pbot.bot.pathfind import LearnedGrid, astar, load_walls_from_map
  12. DIRS = [(0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1)]
  13. MAPS = [
  14. ("等待地图", "0139.map", (24, 30)),
  15. ("比奇大城", "0.map", (330, 330)),
  16. ("盟重土城", "3.map", (342, 338)),
  17. ("天然洞穴一层", "d011.map", None),
  18. ("比奇矿区", "d401.map", (83, 10)),
  19. ("地牢一层东(蜈蚣洞穴)", "d601.map", (198, 28)),
  20. ("沃玛寺庙一层", "d022.map", None),
  21. ("生死之间", "d613.map", None),
  22. ]
  23. def pick_start(walls: set, w: int, h: int) -> tuple[int, int] | None:
  24. for y in range(h // 4, h * 3 // 4, 3):
  25. for x in range(w // 4, w * 3 // 4, 3):
  26. if (x, y) not in walls:
  27. return (x, y)
  28. return None
  29. def bfs_farthest(start: tuple[int, int], walls: set, w: int, h: int
  30. ) -> tuple[tuple[int, int], int, int]:
  31. visited = {start}
  32. dq = deque([(start, 0)])
  33. far, far_d = start, 0
  34. while dq:
  35. (x, y), d = dq.popleft()
  36. if d > far_d:
  37. far, far_d = (x, y), d
  38. for dx, dy in DIRS:
  39. n = (x + dx, y + dy)
  40. if n in visited or not (0 <= n[0] < w and 0 <= n[1] < h):
  41. continue
  42. if n in walls:
  43. continue
  44. visited.add(n)
  45. dq.append((n, d + 1))
  46. return far, far_d, len(visited)
  47. def main() -> int:
  48. print(f"{'地图':<20} {'尺寸':<12} {'起点':<12} {'BFS最远点':<14} "
  49. f"{'可达格':<8} {'A*腿数':<8} {'穿墙':<5} {'耗时'}")
  50. print("-" * 100)
  51. all_ok = True
  52. for name, fname, anchor in MAPS:
  53. t0 = time.time()
  54. import struct
  55. with open(f"assets/maps/{fname}", "rb") as f:
  56. head = f.read(4)
  57. w, h = struct.unpack("<HH", head)
  58. walls = load_walls_from_map(f"assets/maps/{fname}")
  59. t_load = time.time() - t0
  60. start = anchor if anchor and anchor not in walls else pick_start(walls, w, h)
  61. if start is None:
  62. print(f"{name:<20} {w}x{h:<10} — 无可走起点!")
  63. all_ok = False
  64. continue
  65. t0 = time.time()
  66. far, far_d, reach = bfs_farthest(start, walls, w, h)
  67. t_bfs = time.time() - t0
  68. grid = LearnedGrid()
  69. grid.mark_from_map(walls)
  70. t0 = time.time()
  71. path = astar(start, far, grid, max_expand=2_000_000)
  72. t_astar = time.time() - t0
  73. cross = 0
  74. if path:
  75. for a, b in zip(path, path[1:]):
  76. mid = ((a[0] + b[0]) // 2, (a[1] + b[1]) // 2)
  77. if b in walls or (max(abs(b[0]-a[0]), abs(b[1]-a[1])) == 2 and mid in walls):
  78. cross += 1
  79. legs = len(path) - 1
  80. status = "OK" if cross == 0 else f"穿墙{cross}!"
  81. if cross:
  82. all_ok = False
  83. else:
  84. legs, status = 0, "无路!"
  85. all_ok = False
  86. print(f"{name:<20} {w}x{h:<10} {str(start):<12} {str(far):<14} "
  87. f"{reach:<8} {legs:<8} {cross:<5} "
  88. f"load {t_load*1000:.0f}ms bfs {t_bfs*1000:.0f}ms astar {t_astar*1000:.0f}ms")
  89. print("-" * 100)
  90. print("结论:", "★ 全部通过 — 算法对所有地图有效" if all_ok else "存在失败项!")
  91. return 0 if all_ok else 1
  92. if __name__ == "__main__":
  93. sys.exit(main())