dsh-eval-guard 0.2.3 → 0.3.1

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 (221) hide show
  1. package/README.md +91 -13
  2. package/assets/commit0/instance.json +30 -0
  3. package/assets/commit0/workspace.zip +0 -0
  4. package/assets/featurebench/hidden/test_regression.py +690 -0
  5. package/assets/featurebench/instance.json +16 -0
  6. package/assets/featurebench/workspace.zip +0 -0
  7. package/assets/swe-bench-pro/hidden/test.patch +36 -0
  8. package/assets/swe-bench-pro/instance.json +10 -0
  9. package/assets/swe-bench-pro/workspace.zip +0 -0
  10. package/eval/README.md +18 -0
  11. package/eval/arena/arena/README.md +21 -0
  12. package/eval/arena/arena/bt.py +104 -0
  13. package/eval/arena/arena/clock.py +15 -0
  14. package/eval/arena/arena/core.py +265 -0
  15. package/eval/arena/arena/run.cmd +24 -0
  16. package/eval/arena/arena/run.sh +11 -0
  17. package/eval/arena/arena/schedule.py +79 -0
  18. package/eval/arena/arena/tournament.py +183 -0
  19. package/eval/arena/bomberman/bots/README.md +16 -0
  20. package/eval/arena/bomberman/bots/deepseek-v4.1-flash.cpp +447 -0
  21. package/eval/arena/bomberman/bots/doubao-seed-2.1.cpp +542 -0
  22. package/eval/arena/bomberman/bots/glm-5.3.cpp +406 -0
  23. package/eval/arena/bomberman/bots/gpt-6-astra.cpp +768 -0
  24. package/eval/arena/bomberman/bots/gpt-6-sol.cpp +444 -0
  25. package/eval/arena/bomberman/bots/kimi-k3.cpp +432 -0
  26. package/eval/arena/bomberman/bots/mimo-v2.6-pro.cpp +529 -0
  27. package/eval/arena/bomberman/bots/opus-5.5.cpp +548 -0
  28. package/eval/arena/bomberman/bots/qwen-3.8-max.cpp +836 -0
  29. package/eval/arena/bomberman/tournament/README.md +11 -0
  30. package/eval/arena/bomberman/tournament/bt.py +56 -0
  31. package/eval/arena/bomberman/tournament/evaluate.py +199 -0
  32. package/eval/arena/bomberman/tournament/run.py +79 -0
  33. package/eval/arena/bomberman/tournament/schedule-2to10.json.gz +0 -0
  34. package/eval/arena/bomberman/workspace/MANIFEST.json +13 -0
  35. package/eval/arena/bomberman/workspace/README.md +29 -0
  36. package/eval/arena/bomberman/workspace/RULES.md +100 -0
  37. package/eval/arena/bomberman/workspace/baseline.cpp +240 -0
  38. package/eval/arena/bomberman/workspace/clock.py +25 -0
  39. package/eval/arena/bomberman/workspace/engine/arena.py +198 -0
  40. package/eval/arena/bomberman/workspace/engine/build.py +35 -0
  41. package/eval/arena/bomberman/workspace/engine/engine.py +256 -0
  42. package/eval/arena/bomberman/workspace/engine/verify_replay.py +24 -0
  43. package/eval/arena/bomberman/workspace/run.cmd +28 -0
  44. package/eval/arena/bomberman/workspace/run.sh +16 -0
  45. package/eval/arena/bomberman/workspace/viewer/index.html +42 -0
  46. package/eval/arena/ctf/bots/README.md +18 -0
  47. package/eval/arena/ctf/bots/deepseek-v4.1-flash.cpp +601 -0
  48. package/eval/arena/ctf/bots/doubao-seed-2.1-turbo.cpp +320 -0
  49. package/eval/arena/ctf/bots/fable-5.1.cpp +634 -0
  50. package/eval/arena/ctf/bots/glm-5.3.cpp +689 -0
  51. package/eval/arena/ctf/bots/gpt-6-astra.cpp +657 -0
  52. package/eval/arena/ctf/bots/gpt-6.1-sol.cpp +725 -0
  53. package/eval/arena/ctf/bots/kimi-k3.cpp +667 -0
  54. package/eval/arena/ctf/bots/mimo-v2.6-pro.cpp +533 -0
  55. package/eval/arena/ctf/bots/opus-5.5.cpp +645 -0
  56. package/eval/arena/ctf/bots/qwen-3.8-max.cpp +726 -0
  57. package/eval/arena/ctf/bots/sonnet-5.5.cpp +569 -0
  58. package/eval/arena/ctf/tournament/README.md +15 -0
  59. package/eval/arena/ctf/tournament/formal-2to8.json +31 -0
  60. package/eval/arena/ctf/tournament/formal-9to15.json +31 -0
  61. package/eval/arena/ctf/workspace/README.md +41 -0
  62. package/eval/arena/ctf/workspace/RULES.md +119 -0
  63. package/eval/arena/ctf/workspace/arena.py +186 -0
  64. package/eval/arena/ctf/workspace/baseline.cpp +257 -0
  65. package/eval/arena/ctf/workspace/clock.py +15 -0
  66. package/eval/arena/ctf/workspace/core.py +265 -0
  67. package/eval/arena/ctf/workspace/engine.py +389 -0
  68. package/eval/arena/ctf/workspace/run.cmd +24 -0
  69. package/eval/arena/ctf/workspace/run.sh +11 -0
  70. package/eval/arena/ctf/workspace/viewer.html +71 -0
  71. package/eval/arena/land/bots/README.md +17 -0
  72. package/eval/arena/land/bots/deepseek-4.1f@workbuddy#1/bot.cpp +608 -0
  73. package/eval/arena/land/bots/glm-5.3@workbuddy#1/bot.cpp +521 -0
  74. package/eval/arena/land/bots/gpt-6-astra@codex#1/bot.cpp +373 -0
  75. package/eval/arena/land/bots/gpt-6-sol@codex#1/bot.cpp +341 -0
  76. package/eval/arena/land/bots/kimi-k3@workbuddy#1/bot.cpp +492 -0
  77. package/eval/arena/land/bots/mimo-2.6-pro@zcode#1/bot.cpp +652 -0
  78. package/eval/arena/land/bots/mystery-model@zcode#1/bot.cpp +466 -0
  79. package/eval/arena/land/bots/opus-5.5@claude-code#1/bot.cpp +630 -0
  80. package/eval/arena/land/bots/sonnet-5@claude-code#1/bot.cpp +619 -0
  81. package/eval/arena/land/tournament/make_replay_page.py +17 -0
  82. package/eval/arena/land/tournament/rate.py +290 -0
  83. package/eval/arena/land/tournament/round_robin.py +172 -0
  84. package/eval/arena/land/tournament/sparring.cpp +356 -0
  85. package/eval/arena/land/workspace/RULES.md +114 -0
  86. package/eval/arena/land/workspace/TASK.md +46 -0
  87. package/eval/arena/land/workspace/anchors/.build/greedy_f2e6d2dea5ca +0 -0
  88. package/eval/arena/land/workspace/anchors/greedy.cpp +194 -0
  89. package/eval/arena/land/workspace/anchors/random.cpp +80 -0
  90. package/eval/arena/land/workspace/clock.py +64 -0
  91. package/eval/arena/land/workspace/engine/build.py +33 -0
  92. package/eval/arena/land/workspace/engine/game.py +273 -0
  93. package/eval/arena/land/workspace/engine/referee.py +308 -0
  94. package/eval/arena/land/workspace/starter/.build/bot_be32b45b4699 +0 -0
  95. package/eval/arena/land/workspace/starter/bot.cpp +82 -0
  96. package/eval/arena/land/workspace/viewer/viewer.html +210 -0
  97. package/eval/arena/tank/bots/README.md +24 -0
  98. package/eval/arena/tank/bots/half1/deepseek-v4.1-flash.cpp +367 -0
  99. package/eval/arena/tank/bots/half1/doubao-seed-evolving.cpp +402 -0
  100. package/eval/arena/tank/bots/half1/gemini-4-argon.cpp +1132 -0
  101. package/eval/arena/tank/bots/half1/glm-5.3.cpp +551 -0
  102. package/eval/arena/tank/bots/half1/gpt-6-astra.cpp +233 -0
  103. package/eval/arena/tank/bots/half1/gpt-6.1-sol-ultrafast.cpp +350 -0
  104. package/eval/arena/tank/bots/half1/gpt-6.1-sol.cpp +78 -0
  105. package/eval/arena/tank/bots/half1/grok-4.7.cpp +1099 -0
  106. package/eval/arena/tank/bots/half1/haiku-5.5.cpp +210 -0
  107. package/eval/arena/tank/bots/half1/kimi-k3.cpp +353 -0
  108. package/eval/arena/tank/bots/half1/mimo-v2.6-pro.cpp +336 -0
  109. package/eval/arena/tank/bots/half1/muse-wonder-full.cpp +560 -0
  110. package/eval/arena/tank/bots/half1/opus-5.5.cpp +435 -0
  111. package/eval/arena/tank/bots/half1/qwen-3.8-max.cpp +537 -0
  112. package/eval/arena/tank/bots/half2/deepseek-v4.1-flash.cpp +425 -0
  113. package/eval/arena/tank/bots/half2/doubao-seed-evolving.cpp +308 -0
  114. package/eval/arena/tank/bots/half2/gemini-4-argon.cpp +1390 -0
  115. package/eval/arena/tank/bots/half2/glm-5.3.cpp +651 -0
  116. package/eval/arena/tank/bots/half2/gpt-6-astra.cpp +241 -0
  117. package/eval/arena/tank/bots/half2/gpt-6.1-sol-ultrafast.cpp +356 -0
  118. package/eval/arena/tank/bots/half2/gpt-6.1-sol.cpp +87 -0
  119. package/eval/arena/tank/bots/half2/grok-4.7.cpp +1205 -0
  120. package/eval/arena/tank/bots/half2/haiku-5.5.cpp +210 -0
  121. package/eval/arena/tank/bots/half2/kimi-k3.cpp +487 -0
  122. package/eval/arena/tank/bots/half2/mimo-v2.6-pro.cpp +336 -0
  123. package/eval/arena/tank/bots/half2/muse-wonder-full.cpp +560 -0
  124. package/eval/arena/tank/bots/half2/opus-5.5.cpp +476 -0
  125. package/eval/arena/tank/bots/half2/qwen-3.8-max.cpp +392 -0
  126. package/eval/arena/tank/tournament/README.md +24 -0
  127. package/eval/arena/tank/tournament/bt.py +218 -0
  128. package/eval/arena/tank/tournament/final.json +202 -0
  129. package/eval/arena/tank/tournament/halftime.json +146 -0
  130. package/eval/arena/tank/tournament/progress.json +911 -0
  131. package/eval/arena/tank/tournament/schedule.py +100 -0
  132. package/eval/arena/tank/tournament/sparring.cpp +928 -0
  133. package/eval/arena/tank/tournament/tournament.py +1426 -0
  134. package/eval/arena/tank/workspace/README.md +169 -0
  135. package/eval/arena/tank/workspace/RULES.md +443 -0
  136. package/eval/arena/tank/workspace/arena.py +862 -0
  137. package/eval/arena/tank/workspace/baseline.cpp +259 -0
  138. package/eval/arena/tank/workspace/clock.py +103 -0
  139. package/eval/arena/tank/workspace/core.py +712 -0
  140. package/eval/arena/tank/workspace/engine.py +573 -0
  141. package/eval/arena/tank/workspace/history/.lock +0 -0
  142. package/eval/arena/tank/workspace/history/20261017-193610-08715287f91f-bot.cpp +109 -0
  143. package/eval/arena/tank/workspace/history/20261017-193619-f00b2d5635fa-gpt-6-astra.cpp +241 -0
  144. package/eval/arena/tank/workspace/history/20261017-193643-63319e0a2b1a-gpt-6_1-sol-ultrafast.cpp +356 -0
  145. package/eval/arena/tank/workspace/history/20261017-193647-41c1341d0a8a-gemini-4-argon.cpp +1390 -0
  146. package/eval/arena/tank/workspace/history/20261017-193652-e34c0f45539a-gpt-6_1-sol.cpp +87 -0
  147. package/eval/arena/tank/workspace/history/20261017-193654-c026348ce96e-opus-5_5.cpp +476 -0
  148. package/eval/arena/tank/workspace/history/20261017-193655-4a21366e94d1-muse-wonder-full.cpp +560 -0
  149. package/eval/arena/tank/workspace/history/20261017-193657-dbc4e9969c52-mimo-v2_6-pro.cpp +336 -0
  150. package/eval/arena/tank/workspace/history/20261017-193703-723cd036eb31-grok-4_7.cpp +1205 -0
  151. package/eval/arena/tank/workspace/history/20261017-193707-1ebbb227be68-deepseek-v4_1-flash.cpp +425 -0
  152. package/eval/arena/tank/workspace/history/20261017-193709-aeb0e7202ad5-doubao-seed-evolving.cpp +308 -0
  153. package/eval/arena/tank/workspace/history/20261017-193710-b21ebeb9bc76-kimi-k3.cpp +487 -0
  154. package/eval/arena/tank/workspace/history/20261017-193712-54cd86531905-haiku-5_5.cpp +210 -0
  155. package/eval/arena/tank/workspace/history/20261017-193714-efdb8e35c0bf-qwen-3_8-max.cpp +392 -0
  156. package/eval/arena/tank/workspace/history/20261017-193715-681423c23fdb-glm-5_3.cpp +651 -0
  157. package/eval/arena/tank/workspace/history/20261017-193717-1a8b3c75181d-sparring.cpp +928 -0
  158. package/eval/arena/tank/workspace/history/20261017-193720-1e0803a541e8-baseline.cpp +259 -0
  159. package/eval/arena/tank/workspace/history/log.jsonl +103 -0
  160. package/eval/arena/tank/workspace/judge/cycles.hpp +53 -0
  161. package/eval/arena/tank/workspace/judge/fast.cpp +337 -0
  162. package/eval/arena/tank/workspace/judge/referee.cpp +125 -0
  163. package/eval/arena/tank/workspace/judge/speed.cpp +99 -0
  164. package/eval/arena/tank/workspace/run.cmd +31 -0
  165. package/eval/arena/tank/workspace/run.sh +23 -0
  166. package/eval/arena/tank/workspace/tank.hpp +1762 -0
  167. package/eval/arena/tank/workspace/tank_main.cpp +215 -0
  168. package/eval/arena/tank/workspace/viewer.html +1150 -0
  169. package/eval/arena/warehouse/workspace/SPEC.md +130 -0
  170. package/eval/arena/warehouse/workspace/TASK.md +71 -0
  171. package/eval/arena/warehouse/workspace/baseline/common.h +88 -0
  172. package/eval/arena/warehouse/workspace/baseline/main.cpp +27 -0
  173. package/eval/arena/warehouse/workspace/baseline/old_stuff.cpp +87 -0
  174. package/eval/arena/warehouse/workspace/baseline/sim.cpp +427 -0
  175. package/eval/arena/warehouse/workspace/baseline/util.cpp +220 -0
  176. package/eval/arena/warehouse/workspace/clock.py +42 -0
  177. package/eval/arena/warehouse/workspace/src/common.h +88 -0
  178. package/eval/arena/warehouse/workspace/src/main.cpp +27 -0
  179. package/eval/arena/warehouse/workspace/src/old_stuff.cpp +87 -0
  180. package/eval/arena/warehouse/workspace/src/sim.cpp +427 -0
  181. package/eval/arena/warehouse/workspace/src/util.cpp +220 -0
  182. package/eval/arena/warehouse/workspace/tools/bench.py +119 -0
  183. package/eval/arena/warehouse/workspace/tools/check_input.py +161 -0
  184. package/eval/arena/warehouse/workspace/tools/gen.py +132 -0
  185. package/eval/arena/warehouse/workspace/tools/measure.py +107 -0
  186. package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.in +1420 -0
  187. package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.out +9162 -0
  188. package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.in +1465 -0
  189. package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.out +3439 -0
  190. package/eval/arena/warehouse/workspace/workloads/public/pub_flood.in +2757 -0
  191. package/eval/arena/warehouse/workspace/workloads/public/pub_flood.out +3126 -0
  192. package/eval/arena/warehouse/workspace/workloads/public/pub_small.in +731 -0
  193. package/eval/arena/warehouse/workspace/workloads/public/pub_small.out +2578 -0
  194. package/eval/arena/warehouse/workspace/workloads/public/pub_wide.in +528 -0
  195. package/eval/arena/warehouse/workspace/workloads/public/pub_wide.out +2026 -0
  196. package/eval/bomberman.py +20 -0
  197. package/eval/commit0.py +21 -0
  198. package/eval/common.py +61 -0
  199. package/eval/ctf.py +20 -0
  200. package/eval/featurebench.py +25 -0
  201. package/eval/land.py +20 -0
  202. package/eval/legacy/bomberman-prices.json +4 -0
  203. package/eval/legacy/bomberman.py +161 -0
  204. package/eval/legacy/commit0.py +91 -0
  205. package/eval/legacy/ctf-prices.json +4 -0
  206. package/eval/legacy/ctf.py +178 -0
  207. package/eval/legacy/featurebench.py +103 -0
  208. package/eval/legacy/land-prices.json +4 -0
  209. package/eval/legacy/land.py +177 -0
  210. package/eval/legacy/swe_bench_pro.py +116 -0
  211. package/eval/legacy/tank-prices.json +3 -0
  212. package/eval/legacy/tank.py +408 -0
  213. package/eval/legacy/warehouse-prices.json +4 -0
  214. package/eval/legacy/warehouse.py +365 -0
  215. package/eval/swe-bench-pro.py +25 -0
  216. package/eval/tank.py +20 -0
  217. package/eval/warehouse.py +20 -0
  218. package/lib/client/index.js +376 -63
  219. package/lib/client/index.js.map +1 -1
  220. package/lib/index.js +684 -27
  221. package/package.json +2 -1
@@ -0,0 +1,308 @@
1
+ // bot.cpp —— 坦克大战 bot(下半场:baseline 式可靠推进 + 躲闪 + 抢星 + 专守装甲)
2
+ //
3
+ // 上半场教训:联合 maximin 过度保守,三辆车在中线反复横跳、从不点基地(很多图中轴有钢墙,
4
+ // 必须绕侧翼),被对手慢慢磨掉基地。本版用"已被证明能走到基地"的 BFS 推进核:
5
+ // 距离场 = 从敌方基地做 BFS,空地、砖都可走(砖能打掉),钢/水/基地不可走。
6
+ // 沿距离场下降方向走;下一格是砖就先开炮;炮线能到基地就点基地。
7
+ // 在这个核上叠加:
8
+ // - FAST:开局直冲中线抢第一批星(速度 2,约 T3 到、T11 吃到),之后变侧翼攻击手;
9
+ // - FIRE:主攻,沿场推进、清砖、点基地;
10
+ // - ARMOR:默认一起进攻;当敌车逼近我方基地时回防,朝最危险敌车 EMPTY-BFS 拦截并击杀;
11
+ // - 所有车:本回合会被在飞子弹命中时,优先选"仍朝目标前进"的安全躲闪;躲不掉才开炮抵消或硬扛最小损失;
12
+ // - 开炮优先级:能直接点基地(炮线无钢)> 打威胁我方基地/高等级的敌车 > 清挡路砖;不朝队友炮线开炮。
13
+ #include "tank.hpp"
14
+
15
+ #include <algorithm>
16
+
17
+ using namespace tank;
18
+
19
+ namespace {
20
+
21
+ constexpr int INF = 1000000;
22
+ int G_ME;
23
+
24
+ int g_atk[2][CELLS]; // 从基地出发、穿空地+砖的 BFS
25
+ int g_starBfs[MAX_SUPPLY][CELLS]; // 从补给点出发、只走空地的 BFS
26
+ uint64_t g_wall_hash = ~0ULL;
27
+
28
+ // 从 src 做 BFS:passBrick=true 时空地与砖都可走(砖代价1),否则只走空地。
29
+ void bfs_from(const State& s, int src, int* dist, bool passBrick) {
30
+ for (int c = 0; c < CELLS; ++c) dist[c] = INF;
31
+ int q[CELLS], hh = 0, tt = 0;
32
+ dist[src] = 0; q[tt++] = src;
33
+ while (hh < tt) {
34
+ const int c = q[hh++];
35
+ for (int d = 0; d < 4; ++d) {
36
+ const int n = c + DIR_DELTA[d];
37
+ const uint8_t g = s.grid[n];
38
+ const bool ok = (g == EMPTY) || (passBrick && g == BRICK);
39
+ if (ok && dist[n] == INF) { dist[n] = dist[c] + 1; q[tt++] = n; }
40
+ }
41
+ }
42
+ }
43
+
44
+ void ensure_dist(const State& s) {
45
+ if (s.wall_hash == g_wall_hash) return;
46
+ g_wall_hash = s.wall_hash;
47
+ bfs_from(s, s.base_pos[0], g_atk[0], true);
48
+ bfs_from(s, s.base_pos[1], g_atk[1], true);
49
+ for (int k = 0; k < s.n_supply; ++k) bfs_from(s, s.supply[k], g_starBfs[k], false);
50
+ }
51
+
52
+ inline int adist(int base, int c) { int d = g_atk[base][c]; return d >= INF ? 999 : d; }
53
+
54
+ // ---------------- 射线 ----------------
55
+ struct Ray { int kind, tank, seat, cell, dist; };
56
+ Ray raycast(const State& s, int pos, int d) {
57
+ int c = pos;
58
+ for (int k = 1; k <= 16; ++k) {
59
+ c += DIR_DELTA[d];
60
+ const int tv = tank_at(s, c);
61
+ if (tv >= 0) return {1, tv, -1, c, k};
62
+ const uint8_t g = s.grid[c];
63
+ if (g == BASE0 || g == BASE1) return {2, -1, g - BASE0, c, k};
64
+ if (g == BRICK) return {3, -1, -1, c, k};
65
+ if (g == STEEL) return {4, -1, -1, c, k};
66
+ if (g == OUTSIDE) return {6, -1, -1, c, k};
67
+ }
68
+ return {0, -1, -1, NO_CELL, 0};
69
+ }
70
+
71
+ // 不考虑坦克,炮线能否打到某基地(中间只有空/水/砖,无钢、无界外、无另一基地)
72
+ bool base_lane(const State& s, int pos, int d, int baseSeat) {
73
+ for (int c = pos + DIR_DELTA[d];; c += DIR_DELTA[d]) {
74
+ const uint8_t g = s.grid[c];
75
+ if (g == BASE0 + baseSeat) return true;
76
+ if (g == STEEL || g == OUTSIDE || g == BASE0 + (1 - baseSeat)) return false;
77
+ }
78
+ }
79
+
80
+ // 仅这辆车行动(其余全部 STAY,敌方不开新炮)后是否挨打——用于判断"在飞子弹"的威胁。
81
+ bool would_hit(const State& s, int i, Cmd c) {
82
+ State t = s;
83
+ Orders o[2];
84
+ o[seat_of(i)].cmd[type_of(i)] = c;
85
+ step(t, o[0], o[1]);
86
+ return !t.tank[i].alive || t.tank[i].hp < s.tank[i].hp;
87
+ }
88
+
89
+ bool safe_cmd(const State& s, int i, Cmd c) { return !would_hit(s, i, c); }
90
+
91
+ // 敌车这一回合若原地朝 target 开火能否命中 target 格(不考虑它会不会真的开,只看几何)。
92
+ bool enemy_aims_cell(const State& s, int j, int target) {
93
+ if (!s.tank[j].alive || !can_fire(s, j)) return false;
94
+ const int from = s.tank[j].pos;
95
+ if (from == target) return false;
96
+ const int fx = cell_x(from), fy = cell_y(from), tx = cell_x(target), ty = cell_y(target);
97
+ if (fx != tx && fy != ty) return false;
98
+ const int d = fx == tx ? (ty < fy ? UP : DOWN) : (tx < fx ? LEFT : RIGHT);
99
+ for (int c = from + DIR_DELTA[d]; c != target; c += DIR_DELTA[d]) {
100
+ const uint8_t g = s.grid[c];
101
+ if (g == STEEL || g == OUTSIDE || g == BASE0 || g == BASE1) return false;
102
+ if (tank_at(s, c) >= 0) return false;
103
+ }
104
+ return true;
105
+ }
106
+
107
+ // ---------------- 角色 ----------------
108
+ // 0=攻击(沿 g_atk[foe]),1=抢星,2=专守基地
109
+ int role_of(const State& s, int i) {
110
+ const int ty = type_of(i), me = seat_of(i), foe = 1 - me;
111
+ if (ty == ARMOR) {
112
+ int threat = INF;
113
+ for (int j = 3 * foe; j < 3 * foe + 3; ++j)
114
+ if (s.tank[j].alive) threat = std::min(threat, adist(me, s.tank[j].pos));
115
+ return threat <= 16 ? 2 : 0;
116
+ }
117
+ if (ty == FIRE) return 0;
118
+ // FAST
119
+ if (s.tank[i].level >= 2) return 0;
120
+ bool starSoon = false;
121
+ if (s.star_mask) {
122
+ for (int k = 0; k < s.n_supply; ++k) if ((s.star_mask >> k) & 1) starSoon = true;
123
+ } else {
124
+ for (int kk = s.turn + 1; kk <= s.turn + 7; ++kk)
125
+ if (kk >= s.P.supply_first && (kk - s.P.supply_first) % s.P.supply_period == 0) { starSoon = true; break; }
126
+ }
127
+ return starSoon ? 1 : 0;
128
+ }
129
+
130
+ // 选目标距离场(防守时动态算到最危险敌车的 EMPTY BFS)
131
+ const int* role_field(const State& s, int i, int role, int tmp[CELLS]) {
132
+ const int me = seat_of(i), foe = 1 - me;
133
+ if (role == 0) return g_atk[foe];
134
+ if (role == 1) {
135
+ int sk = -1;
136
+ for (int k = 0; k < s.n_supply; ++k)
137
+ if (((s.star_mask >> k) & 1) && (sk < 0 || g_starBfs[k][s.tank[i].pos] < g_starBfs[sk][s.tank[i].pos])) sk = k;
138
+ if (sk < 0)
139
+ for (int k = 0; k < s.n_supply; ++k)
140
+ if (sk < 0 || g_starBfs[k][s.tank[i].pos] < g_starBfs[sk][s.tank[i].pos]) sk = k;
141
+ return sk >= 0 ? g_starBfs[sk] : g_atk[foe];
142
+ }
143
+ // 专守:驻到基地侧翼的守卫格;有敌车在我方基地炮线上时,优先走到能打它的位置。
144
+ const int myBase = s.base_pos[me];
145
+ int target = -1;
146
+ int laneThreat = INF;
147
+ for (int j = 3 * foe; j < 3 * foe + 3; ++j) {
148
+ if (!s.tank[j].alive) continue;
149
+ const int d = adist(me, s.tank[j].pos);
150
+ // 已能点我方基地(与基地同行/列且无钢),或已压入我方半场很深
151
+ bool canHitBase = false;
152
+ const int ex = cell_x(s.tank[j].pos), ey = cell_y(s.tank[j].pos);
153
+ const int bx = cell_x(myBase), by = cell_y(myBase);
154
+ if (ex == bx || ey == by) {
155
+ canHitBase = true;
156
+ const int dd = (ex == bx) ? (ey < by ? UP : DOWN) : (ex < bx ? LEFT : RIGHT);
157
+ for (int c = s.tank[j].pos + DIR_DELTA[dd]; c != myBase; c += DIR_DELTA[dd]) {
158
+ const uint8_t g = s.grid[c];
159
+ if (g == STEEL || g == OUTSIDE) { canHitBase = false; break; }
160
+ }
161
+ }
162
+ const bool deep = me == 0 ? ey >= 10 : ey <= 4;
163
+ if ((canHitBase || deep) && d < laneThreat) { laneThreat = d; target = j; }
164
+ }
165
+ if (target >= 0) {
166
+ // 只走到敌车附近、不越过中线;用 EMPTY BFS 靠近
167
+ const int ey = cell_y(s.tank[target].pos);
168
+ const bool myHalf = me == 0 ? ey >= 6 : ey <= 8;
169
+ if (myHalf) { bfs_from(s, s.tank[target].pos, tmp, false); return tmp; }
170
+ }
171
+ // 守卫格:与基地同行的侧翼空格(左/右 k 格),选最近且当前可站的
172
+ const int bx = cell_x(myBase), by = cell_y(myBase);
173
+ int guard = -1, gd = INF;
174
+ for (int k = 2; k <= 6; ++k)
175
+ for (int sx : {-1, 1}) {
176
+ const int xx = bx + sx * k;
177
+ if (xx < 0 || xx > 14) continue;
178
+ const int c = cell_of(xx, by);
179
+ if (s.grid[c] != EMPTY && s.grid[c] != BRICK) continue;
180
+ bfs_from(s, c, tmp, false);
181
+ const int dd = tmp[s.tank[i].pos];
182
+ if (dd < gd) { gd = dd; guard = c; }
183
+ }
184
+ if (guard < 0) return g_atk[me];
185
+ bfs_from(s, guard, tmp, false);
186
+ return tmp;
187
+ }
188
+
189
+ // 朝场下降方向移动:返回命令;要求安全。快速型走两步。允许第一步/第二步踩砖(第二步砖可能本回合被打掉则走 canonical 等步)。
190
+ // 这里只走当前确为空地的格;砖由开炮处理。
191
+ bool move_along(const State& s, int i, const int* field, Cmd& out, bool requireSafe, bool allowSide) {
192
+ const int pos = s.tank[i].pos;
193
+ const bool fast = type_of(i) == FAST;
194
+ struct O { int d1, d2, cell; int gain; };
195
+ O list[40]; int n = 0;
196
+ auto occ = [&](int c) { return s.grid[c] != EMPTY || tank_at(s, c) >= 0; };
197
+ for (int d1 = 0; d1 < 4; ++d1) {
198
+ const int p1 = pos + DIR_DELTA[d1];
199
+ if (occ(p1)) continue;
200
+ int gain1 = field[pos] - field[p1];
201
+ list[n++] = {d1, -1, p1, gain1};
202
+ if (fast) {
203
+ for (int d2 = 0; d2 < 4; ++d2) {
204
+ const int p2 = p1 + DIR_DELTA[d2];
205
+ if (occ(p2)) continue;
206
+ list[n++] = {d1, d2, p2, field[pos] - field[p2]};
207
+ }
208
+ }
209
+ }
210
+ // 先严格按 gain 排序;gain<=0 时若 allowSide,保留横向(gain==0)用于躲闪/绕路
211
+ std::sort(list, list + n, [](const O& a, const O& b) { return a.gain > b.gain; });
212
+ for (int k = 0; k < n; ++k) {
213
+ if (!allowSide && list[k].gain <= 0) break;
214
+ if (allowSide && list[k].gain < 0) break;
215
+ Cmd c = list[k].d2 < 0 ? cmd_move(list[k].d1) : cmd_move2(list[k].d1, list[k].d2);
216
+ if (!requireSafe || safe_cmd(s, i, c)) { out = c; return true; }
217
+ }
218
+ return false;
219
+ }
220
+
221
+ // 最佳开炮方向。优先级:敌基地 > 危险敌车 > 普通敌车 > 挡路砖。返回 -1 无。
222
+ int aim(const State& s, int i, int role, const int* field) {
223
+ const int me = seat_of(i), foe = 1 - me;
224
+ int best = -1; double bv = -1e18;
225
+ for (int d = 0; d < 4; ++d) {
226
+ double v = -1e18;
227
+ // 基地炮线(无钢):先看这条线上会不会先碰到坦克
228
+ if (base_lane(s, s.tank[i].pos, d, foe)) {
229
+ const Ray r = raycast(s, s.tank[i].pos, d);
230
+ if (r.kind == 2 && r.seat == foe) v = 5000 - r.dist;
231
+ else if (r.kind == 1 && seat_of(r.tank) == foe) v = 3500 - r.dist; // 敌车堵在炮线上,清掉它
232
+ else if (r.kind == 3) v = 3200 - r.dist; // 围墙/挡路砖
233
+ } else {
234
+ const Ray r = raycast(s, s.tank[i].pos, d);
235
+ if (r.kind == 1) {
236
+ const int tv = r.tank;
237
+ if (seat_of(tv) == foe) {
238
+ double pri = 2500 - r.dist * 6 + s.tank[tv].level * 80;
239
+ pri += (120 - std::min(120, adist(me, s.tank[tv].pos))) * 8; // 越接近我方基地越该打
240
+ if (role == 2) pri += 2000; // 防守车专注打敌车
241
+ v = pri;
242
+ }
243
+ } else if (r.kind == 3 && field && field[r.cell] < field[s.tank[i].pos]) {
244
+ v = 900 - r.dist; // 清去路上的砖
245
+ }
246
+ }
247
+ if (v > bv) { bv = v; best = d; }
248
+ }
249
+ return bv > 0 ? best : -1;
250
+ }
251
+
252
+ Cmd decide_tank(const State& s, int i) {
253
+ if (!s.tank[i].alive) return STAY;
254
+ const int me = seat_of(i);
255
+ int tmp[CELLS];
256
+ const int role = role_of(s, i);
257
+ const int* field = role_field(s, i, role, tmp);
258
+ const bool threatened = would_hit(s, i, STAY);
259
+
260
+ // 1) 受威胁:优先沿目标方向安全躲闪
261
+ if (threatened) {
262
+ Cmd dodge = STAY;
263
+ if (move_along(s, i, field, dodge, true, true)) return dodge;
264
+ // 尝试开炮抵消/反杀(结算后不掉血)
265
+ if (can_fire(s, i))
266
+ for (int d = 0; d < 4; ++d) { Cmd fc = cmd_fire(d); if (safe_cmd(s, i, fc)) return fc; }
267
+ // 都不行:选结算后血量最高的命令
268
+ Cmd leg[N_CMDS]; int L = legal_commands(s, i, leg), best = STAY, bsc = -100000;
269
+ for (int k = 0; k < L; ++k) {
270
+ State t = s; Orders o[2]; o[me].cmd[type_of(i)] = leg[k]; step(t, o[0], o[1]);
271
+ int sc = t.tank[i].alive ? 1000 + t.tank[i].hp : t.tank[i].hp;
272
+ if (sc > bsc) { bsc = sc; best = leg[k]; }
273
+ }
274
+ return best;
275
+ }
276
+
277
+ // 2) 能开高价值炮就开(点基地 / 敌车)
278
+ if (can_fire(s, i)) {
279
+ const int fd = aim(s, i, role, field);
280
+ if (fd >= 0) { Cmd fc = cmd_fire(fd); if (safe_cmd(s, i, fc)) return fc; }
281
+ }
282
+
283
+ // 3) 沿目标推进
284
+ Cmd mv = STAY;
285
+ if (move_along(s, i, field, mv, true, false)) return mv;
286
+ // 推进方向被砖挡:开炮清砖
287
+ if (can_fire(s, i)) {
288
+ for (int d = 0; d < 4; ++d) {
289
+ const int n = s.tank[i].pos + DIR_DELTA[d];
290
+ if (s.grid[n] == BRICK && field[n] < field[s.tank[i].pos]) { Cmd fc = cmd_fire(d); if (safe_cmd(s, i, fc)) return fc; }
291
+ }
292
+ }
293
+ // 被车/地形卡住:横向换一格(安全)
294
+ if (move_along(s, i, field, mv, true, true)) return mv;
295
+ return STAY;
296
+ }
297
+
298
+ } // namespace
299
+
300
+ void init(const State&, int me) { G_ME = me; g_wall_hash = ~0ULL; }
301
+
302
+ Orders decide(const State& s, int me) {
303
+ G_ME = me;
304
+ ensure_dist(s);
305
+ Orders o;
306
+ for (int ty = 0; ty < 3; ++ty) o.cmd[ty] = decide_tank(s, tank_id(me, ty));
307
+ return o;
308
+ }