dsh-eval-guard 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +91 -13
  2. package/assets/bomberman/workspace.zip +0 -0
  3. package/assets/commit0/instance.json +30 -0
  4. package/assets/commit0/workspace.zip +0 -0
  5. package/assets/ctf/workspace.zip +0 -0
  6. package/assets/featurebench/hidden/test_regression.py +690 -0
  7. package/assets/featurebench/instance.json +16 -0
  8. package/assets/featurebench/workspace.zip +0 -0
  9. package/assets/swe-bench-pro/hidden/test.patch +36 -0
  10. package/assets/swe-bench-pro/instance.json +10 -0
  11. package/assets/swe-bench-pro/workspace.zip +0 -0
  12. package/assets/tank/workspace.zip +0 -0
  13. package/eval/README.md +18 -0
  14. package/eval/arena/arena/README.md +21 -0
  15. package/eval/arena/arena/bt.py +104 -0
  16. package/eval/arena/arena/clock.py +15 -0
  17. package/eval/arena/arena/core.py +265 -0
  18. package/eval/arena/arena/run.cmd +24 -0
  19. package/eval/arena/arena/run.sh +11 -0
  20. package/eval/arena/arena/schedule.py +79 -0
  21. package/eval/arena/arena/tournament.py +183 -0
  22. package/eval/arena/bomberman/bots/README.md +16 -0
  23. package/eval/arena/bomberman/bots/deepseek-v4.1-flash.cpp +447 -0
  24. package/eval/arena/bomberman/bots/doubao-seed-2.1.cpp +542 -0
  25. package/eval/arena/bomberman/bots/glm-5.3.cpp +406 -0
  26. package/eval/arena/bomberman/bots/gpt-6-astra.cpp +768 -0
  27. package/eval/arena/bomberman/bots/gpt-6-sol.cpp +444 -0
  28. package/eval/arena/bomberman/bots/kimi-k3.cpp +432 -0
  29. package/eval/arena/bomberman/bots/mimo-v2.6-pro.cpp +529 -0
  30. package/eval/arena/bomberman/bots/opus-5.5.cpp +548 -0
  31. package/eval/arena/bomberman/bots/qwen-3.8-max.cpp +836 -0
  32. package/eval/arena/bomberman/tournament/README.md +11 -0
  33. package/eval/arena/bomberman/tournament/bt.py +56 -0
  34. package/eval/arena/bomberman/tournament/evaluate.py +199 -0
  35. package/eval/arena/bomberman/tournament/run.py +79 -0
  36. package/eval/arena/bomberman/tournament/schedule-2to10.json.gz +0 -0
  37. package/eval/arena/bomberman/workspace/MANIFEST.json +13 -0
  38. package/eval/arena/bomberman/workspace/README.md +29 -0
  39. package/eval/arena/bomberman/workspace/RULES.md +100 -0
  40. package/eval/arena/bomberman/workspace/baseline.cpp +240 -0
  41. package/eval/arena/bomberman/workspace/clock.py +25 -0
  42. package/eval/arena/bomberman/workspace/engine/arena.py +198 -0
  43. package/eval/arena/bomberman/workspace/engine/build.py +35 -0
  44. package/eval/arena/bomberman/workspace/engine/engine.py +256 -0
  45. package/eval/arena/bomberman/workspace/engine/verify_replay.py +24 -0
  46. package/eval/arena/bomberman/workspace/run.cmd +28 -0
  47. package/eval/arena/bomberman/workspace/run.sh +16 -0
  48. package/eval/arena/bomberman/workspace/viewer/index.html +42 -0
  49. package/eval/arena/ctf/bots/README.md +18 -0
  50. package/eval/arena/ctf/bots/deepseek-v4.1-flash.cpp +601 -0
  51. package/eval/arena/ctf/bots/doubao-seed-2.1-turbo.cpp +320 -0
  52. package/eval/arena/ctf/bots/fable-5.1.cpp +634 -0
  53. package/eval/arena/ctf/bots/glm-5.3.cpp +689 -0
  54. package/eval/arena/ctf/bots/gpt-6-astra.cpp +657 -0
  55. package/eval/arena/ctf/bots/gpt-6.1-sol.cpp +725 -0
  56. package/eval/arena/ctf/bots/kimi-k3.cpp +667 -0
  57. package/eval/arena/ctf/bots/mimo-v2.6-pro.cpp +533 -0
  58. package/eval/arena/ctf/bots/opus-5.5.cpp +645 -0
  59. package/eval/arena/ctf/bots/qwen-3.8-max.cpp +726 -0
  60. package/eval/arena/ctf/bots/sonnet-5.5.cpp +569 -0
  61. package/eval/arena/ctf/tournament/README.md +15 -0
  62. package/eval/arena/ctf/tournament/formal-2to8.json +31 -0
  63. package/eval/arena/ctf/tournament/formal-9to15.json +31 -0
  64. package/eval/arena/ctf/workspace/README.md +41 -0
  65. package/eval/arena/ctf/workspace/RULES.md +119 -0
  66. package/eval/arena/ctf/workspace/arena.py +186 -0
  67. package/eval/arena/ctf/workspace/baseline.cpp +257 -0
  68. package/eval/arena/ctf/workspace/clock.py +15 -0
  69. package/eval/arena/ctf/workspace/core.py +265 -0
  70. package/eval/arena/ctf/workspace/engine.py +389 -0
  71. package/eval/arena/ctf/workspace/run.cmd +24 -0
  72. package/eval/arena/ctf/workspace/run.sh +11 -0
  73. package/eval/arena/ctf/workspace/viewer.html +71 -0
  74. package/eval/arena/land/bots/README.md +17 -0
  75. package/eval/arena/land/bots/deepseek-4.1f@workbuddy#1/bot.cpp +608 -0
  76. package/eval/arena/land/bots/glm-5.3@workbuddy#1/bot.cpp +521 -0
  77. package/eval/arena/land/bots/gpt-6-astra@codex#1/bot.cpp +373 -0
  78. package/eval/arena/land/bots/gpt-6-sol@codex#1/bot.cpp +341 -0
  79. package/eval/arena/land/bots/kimi-k3@workbuddy#1/bot.cpp +492 -0
  80. package/eval/arena/land/bots/mimo-2.6-pro@zcode#1/bot.cpp +652 -0
  81. package/eval/arena/land/bots/mystery-model@zcode#1/bot.cpp +466 -0
  82. package/eval/arena/land/bots/opus-5.5@claude-code#1/bot.cpp +630 -0
  83. package/eval/arena/land/bots/sonnet-5@claude-code#1/bot.cpp +619 -0
  84. package/eval/arena/land/tournament/make_replay_page.py +17 -0
  85. package/eval/arena/land/tournament/rate.py +290 -0
  86. package/eval/arena/land/tournament/round_robin.py +172 -0
  87. package/eval/arena/land/tournament/sparring.cpp +356 -0
  88. package/eval/arena/land/workspace/RULES.md +114 -0
  89. package/eval/arena/land/workspace/TASK.md +46 -0
  90. package/eval/arena/land/workspace/anchors/.build/greedy_f2e6d2dea5ca +0 -0
  91. package/eval/arena/land/workspace/anchors/greedy.cpp +194 -0
  92. package/eval/arena/land/workspace/anchors/random.cpp +80 -0
  93. package/eval/arena/land/workspace/clock.py +64 -0
  94. package/eval/arena/land/workspace/engine/build.py +33 -0
  95. package/eval/arena/land/workspace/engine/game.py +273 -0
  96. package/eval/arena/land/workspace/engine/referee.py +308 -0
  97. package/eval/arena/land/workspace/starter/.build/bot_be32b45b4699 +0 -0
  98. package/eval/arena/land/workspace/starter/bot.cpp +82 -0
  99. package/eval/arena/land/workspace/viewer/viewer.html +210 -0
  100. package/eval/arena/tank/bots/README.md +24 -0
  101. package/eval/arena/tank/bots/half1/deepseek-v4.1-flash.cpp +367 -0
  102. package/eval/arena/tank/bots/half1/doubao-seed-evolving.cpp +402 -0
  103. package/eval/arena/tank/bots/half1/gemini-4-argon.cpp +1132 -0
  104. package/eval/arena/tank/bots/half1/glm-5.3.cpp +551 -0
  105. package/eval/arena/tank/bots/half1/gpt-6-astra.cpp +233 -0
  106. package/eval/arena/tank/bots/half1/gpt-6.1-sol-ultrafast.cpp +350 -0
  107. package/eval/arena/tank/bots/half1/gpt-6.1-sol.cpp +78 -0
  108. package/eval/arena/tank/bots/half1/grok-4.7.cpp +1099 -0
  109. package/eval/arena/tank/bots/half1/haiku-5.5.cpp +210 -0
  110. package/eval/arena/tank/bots/half1/kimi-k3.cpp +353 -0
  111. package/eval/arena/tank/bots/half1/mimo-v2.6-pro.cpp +336 -0
  112. package/eval/arena/tank/bots/half1/muse-wonder-full.cpp +560 -0
  113. package/eval/arena/tank/bots/half1/opus-5.5.cpp +435 -0
  114. package/eval/arena/tank/bots/half1/qwen-3.8-max.cpp +537 -0
  115. package/eval/arena/tank/bots/half2/deepseek-v4.1-flash.cpp +425 -0
  116. package/eval/arena/tank/bots/half2/doubao-seed-evolving.cpp +308 -0
  117. package/eval/arena/tank/bots/half2/gemini-4-argon.cpp +1390 -0
  118. package/eval/arena/tank/bots/half2/glm-5.3.cpp +651 -0
  119. package/eval/arena/tank/bots/half2/gpt-6-astra.cpp +241 -0
  120. package/eval/arena/tank/bots/half2/gpt-6.1-sol-ultrafast.cpp +356 -0
  121. package/eval/arena/tank/bots/half2/gpt-6.1-sol.cpp +87 -0
  122. package/eval/arena/tank/bots/half2/grok-4.7.cpp +1205 -0
  123. package/eval/arena/tank/bots/half2/haiku-5.5.cpp +210 -0
  124. package/eval/arena/tank/bots/half2/kimi-k3.cpp +487 -0
  125. package/eval/arena/tank/bots/half2/mimo-v2.6-pro.cpp +336 -0
  126. package/eval/arena/tank/bots/half2/muse-wonder-full.cpp +560 -0
  127. package/eval/arena/tank/bots/half2/opus-5.5.cpp +476 -0
  128. package/eval/arena/tank/bots/half2/qwen-3.8-max.cpp +392 -0
  129. package/eval/arena/tank/tournament/README.md +24 -0
  130. package/eval/arena/tank/tournament/bt.py +218 -0
  131. package/eval/arena/tank/tournament/final.json +202 -0
  132. package/eval/arena/tank/tournament/halftime.json +146 -0
  133. package/eval/arena/tank/tournament/progress.json +911 -0
  134. package/eval/arena/tank/tournament/schedule.py +100 -0
  135. package/eval/arena/tank/tournament/sparring.cpp +928 -0
  136. package/eval/arena/tank/tournament/tournament.py +1426 -0
  137. package/eval/arena/tank/workspace/README.md +169 -0
  138. package/eval/arena/tank/workspace/RULES.md +443 -0
  139. package/eval/arena/tank/workspace/arena.py +862 -0
  140. package/eval/arena/tank/workspace/baseline.cpp +259 -0
  141. package/eval/arena/tank/workspace/clock.py +103 -0
  142. package/eval/arena/tank/workspace/core.py +712 -0
  143. package/eval/arena/tank/workspace/engine.py +573 -0
  144. package/eval/arena/tank/workspace/history/.lock +0 -0
  145. package/eval/arena/tank/workspace/history/20261017-193610-08715287f91f-bot.cpp +109 -0
  146. package/eval/arena/tank/workspace/history/20261017-193619-f00b2d5635fa-gpt-6-astra.cpp +241 -0
  147. package/eval/arena/tank/workspace/history/20261017-193643-63319e0a2b1a-gpt-6_1-sol-ultrafast.cpp +356 -0
  148. package/eval/arena/tank/workspace/history/20261017-193647-41c1341d0a8a-gemini-4-argon.cpp +1390 -0
  149. package/eval/arena/tank/workspace/history/20261017-193652-e34c0f45539a-gpt-6_1-sol.cpp +87 -0
  150. package/eval/arena/tank/workspace/history/20261017-193654-c026348ce96e-opus-5_5.cpp +476 -0
  151. package/eval/arena/tank/workspace/history/20261017-193655-4a21366e94d1-muse-wonder-full.cpp +560 -0
  152. package/eval/arena/tank/workspace/history/20261017-193657-dbc4e9969c52-mimo-v2_6-pro.cpp +336 -0
  153. package/eval/arena/tank/workspace/history/20261017-193703-723cd036eb31-grok-4_7.cpp +1205 -0
  154. package/eval/arena/tank/workspace/history/20261017-193707-1ebbb227be68-deepseek-v4_1-flash.cpp +425 -0
  155. package/eval/arena/tank/workspace/history/20261017-193709-aeb0e7202ad5-doubao-seed-evolving.cpp +308 -0
  156. package/eval/arena/tank/workspace/history/20261017-193710-b21ebeb9bc76-kimi-k3.cpp +487 -0
  157. package/eval/arena/tank/workspace/history/20261017-193712-54cd86531905-haiku-5_5.cpp +210 -0
  158. package/eval/arena/tank/workspace/history/20261017-193714-efdb8e35c0bf-qwen-3_8-max.cpp +392 -0
  159. package/eval/arena/tank/workspace/history/20261017-193715-681423c23fdb-glm-5_3.cpp +651 -0
  160. package/eval/arena/tank/workspace/history/20261017-193717-1a8b3c75181d-sparring.cpp +928 -0
  161. package/eval/arena/tank/workspace/history/20261017-193720-1e0803a541e8-baseline.cpp +259 -0
  162. package/eval/arena/tank/workspace/history/log.jsonl +103 -0
  163. package/eval/arena/tank/workspace/judge/cycles.hpp +53 -0
  164. package/eval/arena/tank/workspace/judge/fast.cpp +337 -0
  165. package/eval/arena/tank/workspace/judge/referee.cpp +125 -0
  166. package/eval/arena/tank/workspace/judge/speed.cpp +99 -0
  167. package/eval/arena/tank/workspace/run.cmd +31 -0
  168. package/eval/arena/tank/workspace/run.sh +23 -0
  169. package/eval/arena/tank/workspace/tank.hpp +1762 -0
  170. package/eval/arena/tank/workspace/tank_main.cpp +215 -0
  171. package/eval/arena/tank/workspace/viewer.html +1150 -0
  172. package/eval/arena/warehouse/workspace/SPEC.md +130 -0
  173. package/eval/arena/warehouse/workspace/TASK.md +71 -0
  174. package/eval/arena/warehouse/workspace/baseline/common.h +88 -0
  175. package/eval/arena/warehouse/workspace/baseline/main.cpp +27 -0
  176. package/eval/arena/warehouse/workspace/baseline/old_stuff.cpp +87 -0
  177. package/eval/arena/warehouse/workspace/baseline/sim.cpp +427 -0
  178. package/eval/arena/warehouse/workspace/baseline/util.cpp +220 -0
  179. package/eval/arena/warehouse/workspace/clock.py +42 -0
  180. package/eval/arena/warehouse/workspace/src/common.h +88 -0
  181. package/eval/arena/warehouse/workspace/src/main.cpp +27 -0
  182. package/eval/arena/warehouse/workspace/src/old_stuff.cpp +87 -0
  183. package/eval/arena/warehouse/workspace/src/sim.cpp +427 -0
  184. package/eval/arena/warehouse/workspace/src/util.cpp +220 -0
  185. package/eval/arena/warehouse/workspace/tools/bench.py +119 -0
  186. package/eval/arena/warehouse/workspace/tools/check_input.py +161 -0
  187. package/eval/arena/warehouse/workspace/tools/gen.py +132 -0
  188. package/eval/arena/warehouse/workspace/tools/measure.py +107 -0
  189. package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.in +1420 -0
  190. package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.out +9162 -0
  191. package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.in +1465 -0
  192. package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.out +3439 -0
  193. package/eval/arena/warehouse/workspace/workloads/public/pub_flood.in +2757 -0
  194. package/eval/arena/warehouse/workspace/workloads/public/pub_flood.out +3126 -0
  195. package/eval/arena/warehouse/workspace/workloads/public/pub_small.in +731 -0
  196. package/eval/arena/warehouse/workspace/workloads/public/pub_small.out +2578 -0
  197. package/eval/arena/warehouse/workspace/workloads/public/pub_wide.in +528 -0
  198. package/eval/arena/warehouse/workspace/workloads/public/pub_wide.out +2026 -0
  199. package/eval/bomberman.py +20 -0
  200. package/eval/commit0.py +21 -0
  201. package/eval/common.py +61 -0
  202. package/eval/ctf.py +20 -0
  203. package/eval/featurebench.py +25 -0
  204. package/eval/land.py +20 -0
  205. package/eval/legacy/bomberman-prices.json +4 -0
  206. package/eval/legacy/bomberman.py +161 -0
  207. package/eval/legacy/commit0.py +91 -0
  208. package/eval/legacy/ctf-prices.json +4 -0
  209. package/eval/legacy/ctf.py +178 -0
  210. package/eval/legacy/featurebench.py +103 -0
  211. package/eval/legacy/land-prices.json +4 -0
  212. package/eval/legacy/land.py +177 -0
  213. package/eval/legacy/swe_bench_pro.py +116 -0
  214. package/eval/legacy/tank-prices.json +3 -0
  215. package/eval/legacy/tank.py +408 -0
  216. package/eval/legacy/warehouse-prices.json +4 -0
  217. package/eval/legacy/warehouse.py +365 -0
  218. package/eval/swe-bench-pro.py +25 -0
  219. package/eval/tank.py +20 -0
  220. package/eval/warehouse.py +20 -0
  221. package/lib/client/index.js +376 -63
  222. package/lib/client/index.js.map +1 -1
  223. package/lib/index.js +684 -27
  224. package/package.json +2 -1
@@ -0,0 +1,492 @@
1
+ // 圈地对战 bot —— "bulldozer"
2
+ // 策略概要:
3
+ // - 在家(领地内、无轨迹)时:BFS 搜遍领地边界,枚举「出门 a 步、侧移 b 步、回家」的矩形圈地方案,
4
+ // 按 (中立收益 + 2.2*敌方领地收益 + 切断奖励) / 总步数 打分,并用敌人 BFS 距离场做暴露度检查。
5
+ // - 在外(带轨迹)时:威胁 = 敌人到我轨迹的最短 BFS 距离;若 威胁 <= 回家距离+1 立即撤退。
6
+ // - 机会主义切断:邻近敌轨迹直接切;敌轨迹在攻击半径内且自身安全时主动猎杀。
7
+ // - 撞头规避:根据目标格与敌头的曼哈顿距离加权惩罚,轨迹越长越保守。
8
+ // - 终局:剩余回合不足以往返时立即回家,最后几回合在领地内安全打转。
9
+ #include <bits/stdc++.h>
10
+ using namespace std;
11
+
12
+ static const int DX[4] = {0, 0, -1, 1};
13
+ static const int DY[4] = {-1, 1, 0, 0};
14
+ static const char DC[4] = {'U', 'D', 'L', 'R'};
15
+ int dirIndex(char c) { return (int)string("UDLR").find(c); }
16
+
17
+ struct Player { int x, y, dir, trailLen, area, deaths; };
18
+
19
+ int W, H, MAXT, N, ME, MOVE_MS, INIT_MS;
20
+ vector<pair<int, int>> spawnPos;
21
+ vector<Player> ps;
22
+ vector<int> ownerG, trailG; // 每格: -1 中立/无, 否则玩家编号
23
+ int TURN = 0;
24
+
25
+ uint64_t rngState = 88172645463325252ULL;
26
+ static inline uint64_t xr() { rngState ^= rngState << 13; rngState ^= rngState >> 7; rngState ^= rngState << 17; return rngState; }
27
+
28
+ static inline bool inb(int x, int y) { return x >= 0 && x < W && y >= 0 && y < H; }
29
+ static inline int manh(int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); }
30
+
31
+ vector<int> enemyDist, distHome;
32
+ vector<char> grudge; // 曾被敌方抢走的格子:优先抢回
33
+
34
+ // 多源 BFS:所有敌头的最短距离场(全图可通过,对敌人乐观 = 对我保守)
35
+ void bfsEnemy() {
36
+ enemyDist.assign(W * H, -1);
37
+ deque<int> q;
38
+ for (int i = 0; i < N; i++) {
39
+ if (i == ME) continue;
40
+ int k = ps[i].y * W + ps[i].x;
41
+ if (enemyDist[k] != 0) { enemyDist[k] = 0; q.push_back(k); }
42
+ }
43
+ while (!q.empty()) {
44
+ int k = q.front(); q.pop_front();
45
+ int x = k % W, y = k / W;
46
+ for (int d = 0; d < 4; d++) {
47
+ int nx = x + DX[d], ny = y + DY[d];
48
+ if (!inb(nx, ny)) continue;
49
+ int nk = ny * W + nx;
50
+ if (enemyDist[nk] == -1) { enemyDist[nk] = enemyDist[k] + 1; q.push_back(nk); }
51
+ }
52
+ }
53
+ }
54
+
55
+ // 多源 BFS:从我的全部领地出发、不穿过自己轨迹的距离场 = 每格回家距离
56
+ void bfsHome() {
57
+ distHome.assign(W * H, -1);
58
+ deque<int> q;
59
+ for (int k = 0; k < W * H; k++)
60
+ if (ownerG[k] == ME) { distHome[k] = 0; q.push_back(k); }
61
+ while (!q.empty()) {
62
+ int k = q.front(); q.pop_front();
63
+ int x = k % W, y = k / W;
64
+ for (int d = 0; d < 4; d++) {
65
+ int nx = x + DX[d], ny = y + DY[d];
66
+ if (!inb(nx, ny)) continue;
67
+ int nk = ny * W + nx;
68
+ if (distHome[nk] == -1 && trailG[nk] != ME) { distHome[nk] = distHome[k] + 1; q.push_back(nk); }
69
+ }
70
+ }
71
+ }
72
+
73
+ // BFS:从头出发(第一步禁止掉头、不穿自己轨迹)到满足 goal 的最近格,返回首步方向;失败 -1
74
+ template <class F>
75
+ int bfsFirstStep(F goal, int& outDist, int* outCell = nullptr) {
76
+ int SZ = W * H;
77
+ vector<int> dist(SZ, -1), first(SZ, -1);
78
+ deque<int> q;
79
+ int sx = ps[ME].x, sy = ps[ME].y;
80
+ for (int d = 0; d < 4; d++) {
81
+ if (d == (ps[ME].dir ^ 1)) continue;
82
+ int nx = sx + DX[d], ny = sy + DY[d];
83
+ if (!inb(nx, ny)) continue;
84
+ int nk = ny * W + nx;
85
+ if (trailG[nk] == ME || dist[nk] != -1) continue;
86
+ dist[nk] = 1; first[nk] = d; q.push_back(nk);
87
+ }
88
+ while (!q.empty()) {
89
+ int k = q.front(); q.pop_front();
90
+ int x = k % W, y = k / W;
91
+ if (goal(x, y, k)) { outDist = dist[k]; if (outCell) *outCell = k; return first[k]; }
92
+ for (int d = 0; d < 4; d++) {
93
+ int nx = x + DX[d], ny = y + DY[d];
94
+ if (!inb(nx, ny)) continue;
95
+ int nk = ny * W + nx;
96
+ if (dist[nk] == -1 && trailG[nk] != ME) { dist[nk] = dist[k] + 1; first[nk] = first[k]; q.push_back(nk); }
97
+ }
98
+ }
99
+ outDist = 1e9;
100
+ return -1;
101
+ }
102
+
103
+ deque<int> plan; // 计划的方向序列
104
+
105
+ struct MV { int d, tx, ty, k; };
106
+
107
+ int decide() {
108
+ bfsEnemy();
109
+ bfsHome();
110
+ const Player& me = ps[ME];
111
+ bool outside = me.trailLen > 0;
112
+
113
+ vector<MV> legal;
114
+ for (int d = 0; d < 4; d++) {
115
+ if (d == (me.dir ^ 1)) continue;
116
+ int nx = me.x + DX[d], ny = me.y + DY[d];
117
+ if (!inb(nx, ny)) continue;
118
+ int k = ny * W + nx;
119
+ if (trailG[k] == ME) continue;
120
+ legal.push_back({d, nx, ny, k});
121
+ }
122
+ if (legal.empty()) return me.dir; // 必死,随缘
123
+
124
+ int myEscape = 1e9;
125
+ for (auto& m : legal) {
126
+ int dh = distHome[m.k];
127
+ if (dh >= 0) myEscape = min(myEscape, dh + 1);
128
+ }
129
+ int threat = 1e9;
130
+ if (outside) {
131
+ for (int k = 0; k < W * H; k++)
132
+ if (trailG[k] == ME) threat = min(threat, enemyDist[k]);
133
+ }
134
+ // 混战敌人多、威胁场饱和,放宽撤退阈值;单挑保持谨慎
135
+ int retreatMargin = (N == 2) ? 1 : 0;
136
+ bool danger = outside && threat <= myEscape + retreatMargin;
137
+
138
+ // 目标格撞头/对换风险评分(越小越安全)
139
+ auto headRisk = [&](const MV& m) -> double {
140
+ double r = 0;
141
+ for (int e = 0; e < N; e++) {
142
+ if (e == ME) continue;
143
+ int md = manh(m.tx, m.ty, ps[e].x, ps[e].y);
144
+ if (md == 0) {
145
+ r += 100; // 目标格是敌头:可能互换双亡(但也可能切死对方)
146
+ // 敌方若直行恰好走进我当前格 → 对换风险极大
147
+ if (ps[e].x + DX[ps[e].dir] == me.x && ps[e].y + DY[ps[e].dir] == me.y) r += 60;
148
+ } else if (md == 1) {
149
+ r += 40; // 敌头可能同回合走进该格
150
+ // 敌方直行预测格就是我的目标格 → 风险加倍
151
+ if (ps[e].x + DX[ps[e].dir] == m.tx && ps[e].y + DY[ps[e].dir] == m.ty) r += 30;
152
+ }
153
+ }
154
+ return r;
155
+ };
156
+
157
+ // 回家(撤退)选步:最小化回家距离,并列时远离敌人、避开敌头邻近格
158
+ auto retreatMove = [&]() -> int {
159
+ double best = -1e18; int bd = legal[0].d;
160
+ for (auto& m : legal) {
161
+ int dh = distHome[m.k];
162
+ double sc;
163
+ if (dh < 0) sc = -1e12;
164
+ else {
165
+ sc = -dh * 100.0 + min(enemyDist[m.k], 12) * 4.0;
166
+ double hr = headRisk(m);
167
+ sc -= hr * (me.trailLen > 6 ? 5.0 : 1.5);
168
+ sc += (int)(xr() % 3);
169
+ }
170
+ if (sc > best) { best = sc; bd = m.d; }
171
+ }
172
+ return bd;
173
+ };
174
+
175
+ // ---- 终局:来不及往返立刻回家 ----
176
+ if (outside && TURN + myEscape + 2 >= MAXT) return retreatMove();
177
+
178
+ // ---- 紧急撤退 ----
179
+ if (danger) { plan.clear(); return retreatMove(); }
180
+
181
+ // ---- 机会主义切断:一步可及的敌轨迹 ----
182
+ {
183
+ double bestVal = 0; int bd = -1;
184
+ for (auto& m : legal) {
185
+ int c = trailG[m.k];
186
+ if (c < 0 || c == ME) continue;
187
+ double val = ps[c].trailLen + 4.0;
188
+ bool isHead = (ps[c].x == m.tx && ps[c].y == m.ty);
189
+ if (isHead && me.trailLen == 0) val += 60; // 无轨迹头槌:对换也不亏
190
+ if (isHead && me.trailLen > 8) val -= 100; // 长轨迹时别赌对换
191
+ val -= headRisk(m) * (me.trailLen > 6 ? 1.5 : 0.3);
192
+ if (val > bestVal) { bestVal = val; bd = m.d; }
193
+ }
194
+ if (bd >= 0 && (!outside || me.trailLen <= 6 || threat > myEscape + 2)) {
195
+ plan.clear();
196
+ return bd;
197
+ }
198
+ }
199
+
200
+ // ---- 主动猎杀:攻击半径内的敌轨迹 ----
201
+ auto tryAttack = [&]() -> int {
202
+ int adist, tgtCell = -1;
203
+ int tgtEnemy = -1;
204
+ int d = bfsFirstStep([&](int x, int y, int k) {
205
+ int c = trailG[k];
206
+ if (c >= 0 && c != ME) { tgtEnemy = c; return true; }
207
+ return false;
208
+ }, adist, &tgtCell);
209
+ if (d < 0) return -1;
210
+ int radius;
211
+ if (N == 2) {
212
+ radius = min(4 + ps[tgtEnemy].trailLen / 2, 10);
213
+ } else {
214
+ // 混战:追杀不产领地,只打「保卫国土」(敌轨迹贴近我领地)和「超长轨迹」的仗
215
+ radius = 2;
216
+ if (ps[tgtEnemy].trailLen >= 20) radius = max(radius, 6);
217
+ if (tgtCell >= 0 && distHome[tgtCell] >= 0) {
218
+ if (distHome[tgtCell] <= 2)
219
+ radius = max(radius, 10); // 敌轨迹深入我领地:全力扑杀
220
+ else if (distHome[tgtCell] <= 4)
221
+ radius = max(radius, 5 + ps[tgtEnemy].trailLen / 4);
222
+ }
223
+ }
224
+ if (TURN > MAXT - 40) radius = min(radius, 5);
225
+ if (adist > radius) return -1;
226
+ if (outside && me.trailLen > 4) return -1; // 带着长轨迹不追杀,先保收割
227
+ if (outside && threat <= myEscape + 2) return -1; // 自身难保不追杀
228
+ return d;
229
+ };
230
+
231
+ if (outside) {
232
+ int ad = tryAttack();
233
+ if (ad >= 0) { plan.clear(); return ad; }
234
+ // 执行计划
235
+ while (!plan.empty()) {
236
+ int d = plan.front();
237
+ int nx = me.x + DX[d], ny = me.y + DY[d];
238
+ bool ok = d != (me.dir ^ 1) && inb(nx, ny) && trailG[ny * W + nx] != ME;
239
+ if (!ok) { plan.clear(); break; }
240
+ // 长轨迹时避开敌头邻近格
241
+ MV m{d, nx, ny, ny * W + nx};
242
+ if (me.trailLen > 10 && headRisk(m) >= 60) { plan.clear(); return retreatMove(); }
243
+ plan.pop_front();
244
+ return d;
245
+ }
246
+ return retreatMove(); // 无计划:直接回家收割
247
+ }
248
+
249
+ // ---- 在家(无轨迹) ----
250
+ int ad = tryAttack();
251
+ if (ad >= 0) return ad;
252
+
253
+ if (TURN >= MAXT - 10) {
254
+ // 终局打转:留在领地内,远离敌人
255
+ double best = -1e18; int bd = legal[0].d;
256
+ for (auto& m : legal) {
257
+ double sc = (ownerG[m.k] == ME ? 50 : 0) + min(enemyDist[m.k], 12) * 4.0 - headRisk(m) * 2.0 + (int)(xr() % 3);
258
+ if (sc > best) { best = sc; bd = m.d; }
259
+ }
260
+ return bd;
261
+ }
262
+
263
+ if (plan.empty()) {
264
+ // ============ 圈地规划搜索 ============
265
+ int SZ = W * H;
266
+ vector<int> dT(SZ, -1), from(SZ, -1), fdir(SZ, -1);
267
+ deque<int> q;
268
+ int start = me.y * W + me.x;
269
+ dT[start] = 0; from[start] = start; q.push_back(start);
270
+ while (!q.empty()) {
271
+ int k = q.front(); q.pop_front();
272
+ int x = k % W, y = k / W;
273
+ for (int d = 0; d < 4; d++) {
274
+ int nx = x + DX[d], ny = y + DY[d];
275
+ if (!inb(nx, ny)) continue;
276
+ int nk = ny * W + nx;
277
+ if (ownerG[nk] == ME && dT[nk] == -1) { dT[nk] = dT[k] + 1; from[nk] = k; fdir[nk] = d; q.push_back(nk); }
278
+ }
279
+ }
280
+ // 局势判断
281
+ bool behind = false;
282
+ if (N == 2) behind = ps[ME].area < ps[1 - ME].area;
283
+ else { int rk = 0; for (int e = 0; e < N; e++) if (e != ME && ps[e].area > ps[ME].area) rk++; behind = rk >= 2; }
284
+ bool endgameLead = false;
285
+ if (TURN > MAXT - 100) {
286
+ if (N == 2) endgameLead = ps[ME].area > ps[1 - ME].area;
287
+ else { int rk = 0; for (int e = 0; e < N; e++) if (e != ME && ps[e].area > ps[ME].area) rk++; endgameLead = rk == 0; }
288
+ }
289
+ int turnBudget = MAXT - 6 - TURN;
290
+
291
+ double bestScore = 0, bestValue = 0;
292
+ int bF = -1, bD = 0, bA = 0, bS = 0, bB = 0;
293
+ // 两档暴露度搜索:先安全档,找不到再放宽(混战整体放宽一档)
294
+ int exp0 = (N == 2) ? (behind ? 1 : 2) : 1;
295
+ for (int needExposure = exp0; needExposure >= 1 && bF < 0; needExposure--)
296
+ for (int f = 0; f < SZ; f++) {
297
+ if (dT[f] < 0) continue;
298
+ int fx = f % W, fy = f / W;
299
+ // 局部威胁决定该出口的圈地尺寸上限(远处放心大圈,近敌小圈快跑)
300
+ int lt = enemyDist[f];
301
+ bool late = TURN > MAXT - 120;
302
+ int aCap = 22;
303
+ if (late) aCap = endgameLead ? 6 : 24; // 残局:领先收小圈保胜,落后开大圈豪赌
304
+ int scale = (N == 2) ? lt / 2 : lt; // 混战死亡便宜,尺寸钳制放宽
305
+ int amax = clamp(scale, 2, aCap);
306
+ int bmax = clamp(scale, 2, 15);
307
+ for (int d = 0; d < 4; d++) {
308
+ int ex = fx + DX[d], ey = fy + DY[d];
309
+ if (!inb(ex, ey) || ownerG[ey * W + ex] == ME) continue;
310
+ int perp0 = (d < 2) ? 2 : 0, perp1 = (d < 2) ? 3 : 1;
311
+ for (int a = 1; a <= amax; a++) {
312
+ int farx = ex + DX[d] * (a - 1), fary = ey + DY[d] * (a - 1);
313
+ if (!inb(farx, fary)) break;
314
+ for (int sp = 0; sp < 2; sp++) {
315
+ int s = sp ? perp1 : perp0;
316
+ for (int b = 1; b <= bmax; b++) {
317
+ int cx = farx + DX[s] * b, cy = fary + DY[s] * b;
318
+ if (!inb(cx, cy)) break;
319
+ int rx = fx + DX[s] * b, ry = fy + DY[s] * b;
320
+ if (!inb(rx, ry) || ownerG[ry * W + rx] != ME) continue;
321
+ int total = dT[f] + 2 * a + b;
322
+ if (total > turnBudget) continue;
323
+ // 暴露度:敌人到轨迹格的距离 - 我到达该格的回合数
324
+ int exposure = 1e9, t = dT[f];
325
+ int cutBonus = 0;
326
+ for (int k2 = 0; k2 < a; k2++) {
327
+ int px = ex + DX[d] * k2, py = ey + DY[d] * k2; t++;
328
+ int pk = py * W + px;
329
+ exposure = min(exposure, enemyDist[pk] - t);
330
+ int c = trailG[pk]; if (c >= 0 && c != ME) cutBonus += ps[c].trailLen + 8;
331
+ }
332
+ for (int j = 1; j <= b; j++) {
333
+ int px = farx + DX[s] * j, py = fary + DY[s] * j; t++;
334
+ int pk = py * W + px;
335
+ exposure = min(exposure, enemyDist[pk] - t);
336
+ int c = trailG[pk]; if (c >= 0 && c != ME) cutBonus += ps[c].trailLen + 8;
337
+ }
338
+ for (int k2 = 1; k2 <= a - 1; k2++) {
339
+ int px = cx - DX[d] * k2, py = cy - DY[d] * k2; t++;
340
+ int pk = py * W + px;
341
+ exposure = min(exposure, enemyDist[pk] - t);
342
+ int c = trailG[pk]; if (c >= 0 && c != ME) cutBonus += ps[c].trailLen + 8;
343
+ }
344
+ if (exposure < needExposure) continue;
345
+ // 收益:矩形框内非我格数,敌领地双倍价值
346
+ int x0 = min(ex, cx), x1 = max(ex, cx), y0 = min(ey, cy), y1 = max(ey, cy);
347
+ double value = cutBonus;
348
+ for (int yy = y0; yy <= y1; yy++)
349
+ for (int xx = x0; xx <= x1; xx++) {
350
+ int kk = yy * W + xx;
351
+ int o = ownerG[kk];
352
+ if (o == ME) continue;
353
+ if (o == -1) value += 1.0;
354
+ else {
355
+ // 抢领头者价值更高(混战压名次)
356
+ double w = (N > 2 && grudge[kk]) ? 3.2 : 2.2; // 单挑不记仇:回抢低效
357
+ if (N > 2 && ps[o].area >= ps[ME].area) w += 0.6;
358
+ value += w;
359
+ }
360
+ }
361
+ if (value <= 0) continue;
362
+ double score = value / (total + 1.0);
363
+ if (score > bestScore) { bestScore = score; bestValue = value; bF = f; bD = d; bA = a; bS = s; bB = b; }
364
+ }
365
+ }
366
+ }
367
+ }
368
+ }
369
+ if (bF >= 0) {
370
+ // —— 验收:对选中方案做真实泛洪圈地模拟,防止估计失真(领地被撕裂/凹陷)——
371
+ auto simulateGain = [&]() -> int {
372
+ int fx = bF % W, fy = bF / W;
373
+ vector<char> wall(SZ, 0);
374
+ for (int k = 0; k < SZ; k++)
375
+ if (ownerG[k] == ME || trailG[k] == ME) wall[k] = 1;
376
+ int px = fx, py = fy;
377
+ auto step = [&](int d) { px += DX[d]; py += DY[d]; wall[py * W + px] = 1; };
378
+ for (int i = 0; i < bA; i++) step(bD);
379
+ for (int i = 0; i < bB; i++) step(bS);
380
+ for (int i = 0; i < bA - 1; i++) step(bD ^ 1); // 最后一步踏入领地,不算墙
381
+ vector<char> seen(SZ, 0);
382
+ deque<int> qq;
383
+ auto seed = [&](int k) { if (!wall[k] && !seen[k]) { seen[k] = 1; qq.push_back(k); } };
384
+ for (int x = 0; x < W; x++) { seed(x); seed((H - 1) * W + x); }
385
+ for (int y = 0; y < H; y++) { seed(y * W); seed(y * W + W - 1); }
386
+ while (!qq.empty()) {
387
+ int k = qq.front(); qq.pop_front();
388
+ int x = k % W, y = k / W;
389
+ for (int d = 0; d < 4; d++) {
390
+ int nx = x + DX[d], ny = y + DY[d];
391
+ if (!inb(nx, ny)) continue;
392
+ int nk = ny * W + nx;
393
+ if (!wall[nk] && !seen[nk]) { seen[nk] = 1; qq.push_back(nk); }
394
+ }
395
+ }
396
+ int gain = 0;
397
+ for (int k = 0; k < SZ; k++)
398
+ if (!wall[k] && !seen[k] && ownerG[k] != ME) gain++;
399
+ return gain + 2 * bA + bB; // 加上轨迹本身变领地
400
+ };
401
+ int realGain = simulateGain();
402
+ if (realGain <= 2) bF = -1; // 只会漏水的方案才放弃(防止领地被撕裂后白跑)
403
+ }
404
+ if (bF >= 0) {
405
+ vector<int> path;
406
+ for (int c = bF; c != start; c = from[c]) path.push_back(fdir[c]);
407
+ reverse(path.begin(), path.end());
408
+ for (int d2 : path) plan.push_back(d2);
409
+ for (int i = 0; i < bA; i++) plan.push_back(bD);
410
+ for (int i = 0; i < bB; i++) plan.push_back(bS);
411
+ for (int i = 0; i < bA; i++) plan.push_back(bD ^ 1);
412
+ }
413
+ }
414
+ if (!plan.empty()) {
415
+ int d = plan.front();
416
+ int nx = me.x + DX[d], ny = me.y + DY[d];
417
+ if (d != (me.dir ^ 1) && inb(nx, ny) && trailG[ny * W + nx] != ME) {
418
+ plan.pop_front();
419
+ return d;
420
+ }
421
+ plan.clear();
422
+ }
423
+ // 游荡兜底:走向安全的非我格
424
+ double best = -1e18; int bd = legal[0].d;
425
+ for (auto& m : legal) {
426
+ double sc = min(enemyDist[m.k], 12) * 3.0 + (ownerG[m.k] != ME ? 8 : 0) - headRisk(m) + (int)(xr() % 4);
427
+ if (sc > best) { best = sc; bd = m.d; }
428
+ }
429
+ return bd;
430
+ }
431
+
432
+ bool readState() {
433
+ string tok;
434
+ if (!(cin >> tok)) return false; // TURN
435
+ cin >> TURN;
436
+ ps.assign(N, {});
437
+ for (int i = 0; i < N; i++) {
438
+ int id; char d; Player q;
439
+ cin >> tok >> id >> q.x >> q.y >> d >> q.trailLen >> q.area >> q.deaths;
440
+ q.dir = dirIndex(d);
441
+ ps[id] = q;
442
+ }
443
+ vector<int> prev;
444
+ prev.swap(ownerG);
445
+ ownerG.assign(W * H, -1);
446
+ trailG.assign(W * H, -1);
447
+ cin >> tok; // OWNER
448
+ string row;
449
+ for (int y = 0; y < H; y++) {
450
+ cin >> row;
451
+ for (int x = 0; x < W; x++) {
452
+ if (row[x] == '.') continue;
453
+ int k = y * W + x;
454
+ ownerG[k] = row[x] - '0';
455
+ if (!prev.empty()) {
456
+ if (prev[k] == ME && ownerG[k] != ME) grudge[k] = 1; // 被抢,记仇
457
+ else if (ownerG[k] == ME && prev[k] != ME) grudge[k] = 0; // 已抢回
458
+ }
459
+ }
460
+ }
461
+ cin >> tok; // TRAIL
462
+ for (int y = 0; y < H; y++) {
463
+ cin >> row;
464
+ for (int x = 0; x < W; x++) if (row[x] != '.') trailG[y * W + x] = row[x] - '0';
465
+ }
466
+ cin >> tok; // END
467
+ return true;
468
+ }
469
+
470
+ int main() {
471
+ ios::sync_with_stdio(false);
472
+ cin.tie(nullptr);
473
+ string tok;
474
+ cin >> tok; // INIT
475
+ cin >> W >> H >> MAXT >> N >> ME >> MOVE_MS >> INIT_MS;
476
+ spawnPos.resize(N);
477
+ for (int i = 0; i < N; i++) {
478
+ int id, x, y;
479
+ cin >> tok >> id >> x >> y;
480
+ spawnPos[id] = {x, y};
481
+ }
482
+ grudge.assign(W * H, 0);
483
+ rngState ^= (uint64_t)(ME * 7919 + spawnPos[ME].first * 131 + spawnPos[ME].second * 313 + 17);
484
+ bool wasOutside = false;
485
+ while (readState()) {
486
+ bool outside = ps[ME].trailLen > 0;
487
+ if (!outside && wasOutside) plan.clear(); // 刚完成收割或刚复活
488
+ wasOutside = outside;
489
+ int d = decide();
490
+ cout << TURN << ' ' << DC[d] << endl;
491
+ }
492
+ }