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,466 @@
1
+ // 圈地对战 bot
2
+ // 策略核心:
3
+ // 1) 圈地判定是「从边界泛洪、够不到的格子全归我」,所以画一个尽量大的闭合回路就能一次吞掉整块区域。
4
+ // 本 bot 每次都规划一个「矩形回路」:矩形必须严格包住自己的领地 bbox,
5
+ // 从 bbox 的某个角出发绕矩形一周再回到该角 → 回路内部(= 整个矩形)全部变成我的领地。
6
+ // 领地因此像滚雪球一样扩张,几步之内吃掉大半个棋盘。
7
+ // 2) 分数只看名次,所以优先选「收益/步数」最大且能在剩余回合内跑完的矩形。
8
+ // 3) 对手可能反过来用一个大圈把我包住(领地会被抢走,只剩保护区),
9
+ // 所以每回合检测「某个对手这回合圈地是否会吞掉我的领地」,一旦成立立刻冲过去切断它的轨迹。
10
+ // 4) 顺手切对手:轨迹是它这轮全部积累,踩一脚就让它白跑,所以近身有机会必切。
11
+ // 5) 画圈期间被切断 = 阵亡回到出生点(领地保留),损失只是时间;计划每回合校验,非法即重排。
12
+ #include <bits/stdc++.h>
13
+ using namespace std;
14
+
15
+ static int W, H, MAXT, N, ME, MOVE_MS, INIT_MS;
16
+ static const int DX[4] = {0, 0, -1, 1};
17
+ static const int DY[4] = {-1, 1, 0, 0};
18
+ static const char DCH[4] = {'U', 'D', 'L', 'R'};
19
+ static int MEc;
20
+
21
+ static vector<signed char> own, trl;
22
+ static int spx[8], spy[8];
23
+ static int pX[8], pY[8], pD[8], pTL[8], pA[8], pDe[8];
24
+ static int TURN;
25
+
26
+ static int bfsD[4096], bfsF[4096], qb[4096];
27
+ static int lastDist;
28
+ static bool bfsOwnOnly = false; // 只走自己的领地(画圈前的回家路径)
29
+ static int edist[4096]; // 到最近对手头部的纯网格距离
30
+ static vector<signed char> seen;
31
+
32
+ static vector<int> plan; // 剩余执行的方向序列
33
+ static bool planActive = false; // 计划是否已开始执行
34
+ static bool wasOutside = false; // 本轮计划中是否已经离开过领地
35
+
36
+ static inline bool inb(int x, int y) { return x >= 0 && x < W && y >= 0 && y < H; }
37
+ static inline int dOf(char c) { return c == 'U' ? 0 : c == 'D' ? 1 : c == 'L' ? 2 : 3; }
38
+
39
+ // ---------------------------------------------------------------- BFS
40
+ // 从头部出发,禁止踩自己的轨迹,禁止第一步掉头。
41
+ // mode 0: 全程;mode 1: 找最近的对手轨迹格;mode 2: 找最近的自有领地格
42
+ static int bfsRun(int mode, int targetPlayer) {
43
+ lastDist = -1;
44
+ int n = W * H;
45
+ int s = pY[ME] * W + pX[ME];
46
+ for (int k = 0; k < n; k++) bfsD[k] = -1;
47
+ bfsD[s] = 0;
48
+ bfsF[s] = -1;
49
+ int qh = 0, qt = 0;
50
+ qb[qt++] = s;
51
+ int back = pD[ME] ^ 1;
52
+ int found = -1;
53
+ while (qh < qt) {
54
+ int k = qb[qh++];
55
+ if (mode == 1 && trl[k] >= 0 && trl[k] != MEc) { found = k; break; }
56
+ if (mode == 2 && own[k] == MEc) { found = k; break; }
57
+ int x = k % W, y = k / W;
58
+ for (int d = 0; d < 4; d++) {
59
+ if (k == s && d == back) continue;
60
+ int nx = x + DX[d], ny = y + DY[d];
61
+ if (!inb(nx, ny)) continue;
62
+ int nk = ny * W + nx;
63
+ if (bfsD[nk] != -1) continue;
64
+ if (trl[nk] == MEc) continue; // 踩自己的轨迹 = 自杀
65
+ if (bfsOwnOnly && own[nk] != MEc) continue;
66
+ bfsD[nk] = bfsD[k] + 1;
67
+ bfsF[nk] = (k == s ? d : bfsF[k]);
68
+ qb[qt++] = nk;
69
+ }
70
+ }
71
+ if (mode == 0) return 0;
72
+ if (found < 0) return -1;
73
+ lastDist = bfsD[found];
74
+ return bfsF[found];
75
+ }
76
+
77
+ // -------------------------------------------------- 对手是否要把我围死
78
+ // 用对手的领地+轨迹当墙,从边界泛洪;泛洪不到的我的领地格 = 它这一圈会吞掉的地方。
79
+ static bool enemyEnclosesMe(int j) {
80
+ int n = W * H;
81
+ int ch = j;
82
+ for (int k = 0; k < n; k++)
83
+ seen[k] = (own[k] == ch || trl[k] == ch) ? 1 : 0;
84
+ int qh = 0, qt = 0;
85
+ for (int x = 0; x < W; x++) {
86
+ int a = x, b = (H - 1) * W + x;
87
+ if (!seen[a]) { seen[a] = 1; qb[qt++] = a; }
88
+ if (!seen[b]) { seen[b] = 1; qb[qt++] = b; }
89
+ }
90
+ for (int y = 0; y < H; y++) {
91
+ int a = y * W, b = y * W + W - 1;
92
+ if (!seen[a]) { seen[a] = 1; qb[qt++] = a; }
93
+ if (!seen[b]) { seen[b] = 1; qb[qt++] = b; }
94
+ }
95
+ while (qh < qt) {
96
+ int k = qb[qh++];
97
+ int x = k % W, y = k / W;
98
+ for (int d = 0; d < 4; d++) {
99
+ int nx = x + DX[d], ny = y + DY[d];
100
+ if (!inb(nx, ny)) continue;
101
+ int nk = ny * W + nx;
102
+ if (seen[nk]) continue;
103
+ seen[nk] = 1;
104
+ qb[qt++] = nk;
105
+ }
106
+ }
107
+ int hx = pX[ME], hy = pY[ME];
108
+ if (!seen[hy * W + hx]) return true;
109
+ for (int k = 0; k < n; k++)
110
+ if (own[k] == MEc && !seen[k]) return true;
111
+ return false;
112
+ }
113
+
114
+ // ---------------------------------------------------------------- 规划
115
+ // 一个「圈」= 从自己领地上某个角 s 出发,绕一个矩形一整圈,再踩回 s。
116
+ // 矩形的一条近边必须紧贴 s(否则回路接不回领地),远边任意(只要整条边都不是自己的格子)。
117
+ // 绕完一圈后回路内部(含自己领地)全部被围住 = 一次吃掉整块区域。
118
+ static int pref[64][64]; // 自己领地的前缀和,用来 O(1) 算矩形里有多少自己的格子
119
+
120
+ static void buildPlan() {
121
+ plan.clear();
122
+ planActive = false;
123
+ wasOutside = false;
124
+
125
+ int x0 = W, y0 = H, x1 = -1, y1 = -1;
126
+ for (int y = 0; y < H; y++)
127
+ for (int x = 0; x < W; x++)
128
+ if (own[y * W + x] == MEc) {
129
+ if (x < x0) x0 = x;
130
+ if (x > x1) x1 = x;
131
+ if (y < y0) y0 = y;
132
+ if (y > y1) y1 = y;
133
+ }
134
+ if (x1 < 0) return;
135
+ for (int y = 0; y < H; y++)
136
+ for (int x = 0; x < W; x++)
137
+ pref[y + 1][x + 1] = pref[y][x + 1] + pref[y + 1][x] - pref[y][x] + (own[y * W + x] == MEc);
138
+
139
+ int rem = MAXT - TURN;
140
+ if (rem < 5) return;
141
+ // 手上有轨迹(人在外面)时不画圈:先回家。回路要靠这条路径接回领地,
142
+ // 路径和回路一旦撞上就是自杀,限制成只走自己的领地就永远不会撞。
143
+ if (pTL[ME] > 0 || own[pY[ME] * W + pX[ME]] != MEc) return;
144
+
145
+ bfsOwnOnly = true;
146
+ bfsRun(0, 0);
147
+ bfsOwnOnly = false;
148
+ int head = pY[ME] * W + pX[ME];
149
+
150
+ // 候选起点:自己领地边界上的「凸角」——某一侧相邻的两个格子都空着。
151
+ // 先放 bbox 的四个角(向外扩收益最大),再从整条边界上均匀取样,
152
+ // 否则只会一路往上顶, territory 长到顶以后就没圈可画了。
153
+ int cand[4][12], nc[4] = {0, 0, 0, 0};
154
+ for (int o = 0; o < 4; o++) {
155
+ int ex = o & 1, ey = o >> 1;
156
+ int k = (o == 0 ? y0 * W + x0 : o == 1 ? y0 * W + x1 : o == 2 ? y1 * W + x0 : y1 * W + x1);
157
+ int x = k % W, y = k / W;
158
+ int ax = ex ? x + 1 : x - 1, ay = ey ? y + 1 : y - 1;
159
+ if (inb(ax, ay) && own[ay * W + ax] != MEc) cand[o][nc[o]++] = k;
160
+ }
161
+ for (int o = 0; o < 4; o++) {
162
+ int ex = o & 1, ey = o >> 1;
163
+ int all[400], na = 0;
164
+ for (int y = 0; y < H; y++)
165
+ for (int x = 0; x < W; x++) {
166
+ if (own[y * W + x] != MEc) continue;
167
+ int ax = ex ? x + 1 : x - 1, ay = ey ? y + 1 : y - 1;
168
+ if (!inb(ax, ay) || own[ay * W + ax] == MEc) continue;
169
+ if (na < 400) all[na++] = y * W + x;
170
+ }
171
+ int room = 12 - nc[o];
172
+ if (room <= 0) continue;
173
+ if (na <= room) {
174
+ for (int q = 0; q < na; q++) cand[o][nc[o]++] = all[q];
175
+ } else {
176
+ for (int q = 0; q < room; q++)
177
+ cand[o][nc[o]++] = all[(int)((long)na * q / room)];
178
+ }
179
+ }
180
+
181
+ // 开局领地小,一个大圈就能吃掉半个棋盘,这时值得押上全部剩余回合;
182
+ // 领地大了以后再画超长圈只是白送人头,所以收紧。
183
+ const int CAP = (N == 2) ? 140 : 60;
184
+ const double ALPHA = 1.0;
185
+ double bestScore = -1e18;
186
+ int bS = -1, bEx = 0, bEy = 0, bBw = 0, bBh = 0, bStop = 0;
187
+ const int SAMP = 9;
188
+
189
+ for (int o = 0; o < 4; o++) {
190
+ int ex = o & 1, ey = o >> 1;
191
+ for (int ci = 0; ci < nc[o]; ci++) {
192
+ int sIdx = cand[o][ci], sx = sIdx % W, sy = sIdx / W;
193
+ if (bfsD[sIdx] < 0) continue;
194
+ int approach = bfsD[sIdx];
195
+ int xlo = ex ? sx + 1 : sx - 1, ylo = ey ? sy + 1 : sy - 1;
196
+ if (!inb(xlo, sy) || !inb(sx, ylo)) continue;
197
+ int fx0 = ex ? 0 : sx, fx1 = ex ? sx - 1 : W - 1;
198
+ int fy0 = ey ? 0 : sy, fy1 = ey ? sy - 1 : H - 1;
199
+ if (fx0 > fx1 || fy0 > fy1) continue;
200
+ int dIn = ex ? 3 : 2, dA1 = ey ? 0 : 1, dH2 = ex ? 2 : 3, dUp = ey ? 1 : 0, dH5 = ex ? 3 : 2;
201
+ for (int a = 0; a < SAMP; a++) {
202
+ int farX = fx0 + (int)((long)(fx1 - fx0) * a / (SAMP - 1));
203
+ int bw = abs(farX - sx);
204
+ for (int b = 0; b < SAMP; b++) {
205
+ int farY = fy0 + (int)((long)(fy1 - fy0) * b / (SAMP - 1));
206
+ int bh = abs(farY - sy);
207
+ int P = 2 * bw + 2 * bh + 4;
208
+ int rx0 = min(xlo, farX), rx1 = max(xlo, farX);
209
+ int ry0 = min(ylo, farY), ry1 = max(ylo, farY);
210
+ int mine = pref[ry1 + 1][rx1 + 1] - pref[ry0][rx1 + 1] - pref[ry1 + 1][rx0] + pref[ry0][rx0];
211
+ int pc = 0;
212
+ for (int j = 0; j < N; j++) {
213
+ if (j == ME) continue;
214
+ int ox = min(rx1, spx[j] + 1) - max(rx0, spx[j] - 1) + 1;
215
+ int oy = min(ry1, spy[j] + 1) - max(ry0, spy[j] - 1) + 1;
216
+ if (ox > 0 && oy > 0) pc += ox * oy;
217
+ }
218
+ int gain = (rx1 - rx0 + 1) * (ry1 - ry0 + 1) - mine - pc;
219
+ if (gain <= 0) continue;
220
+ // 走一遍回路。撞到自己领地 = 这一圈到此为止(踩进去就结算,顺带把这条带子圈下来),
221
+ // 撞到自己的轨迹/回家路径 = 同格自杀,这个候选作废。
222
+ int risk = 0, kill = 0, stopT = 0, t = 0, x = sx, y = sy;
223
+ auto stepTo = [&](int d) {
224
+ x += DX[d]; y += DY[d]; t++;
225
+ int k = y * W + x;
226
+ if (own[k] == MEc) { stopT = t; return; }
227
+ // 会被切断 = 白跑 t 回合,代价按已投入的工作量算
228
+ if (edist[k] < t) risk += t;
229
+ if (trl[k] >= 0 && pTL[trl[k]] >= 3) kill += 2 * pTL[trl[k]] + 20;
230
+ };
231
+ stepTo(dIn);
232
+ for (int i = 0; i < bh && !stopT; i++) stepTo(dA1);
233
+ for (int i = 0; i < bw + 1 && !stopT; i++) stepTo(dH2);
234
+ for (int i = 0; i < bh + 1 && !stopT; i++) stepTo(dUp);
235
+ for (int i = 0; i < bw && !stopT; i++) stepTo(dH5);
236
+ int planLen = stopT ? stopT : P;
237
+ int total = approach + planLen;
238
+ if (total + 2 > rem) continue;
239
+ if (total > CAP) continue;
240
+ // 半途截断的圈只能吃到已经围住的那条带子,收益按比例打折
241
+ int gain2 = stopT ? (int)(gain * pow((double)stopT / (P + 1), ALPHA)) : gain;
242
+ if (gain2 <= 0) continue;
243
+ const double PWR = 0.85, KLP = 0.35, QRSK = 0.02;
244
+ double score = (double)gain2 / pow((double)(total + 6), PWR) - QRSK * risk + KLP * kill;
245
+ if (score > bestScore) {
246
+ bestScore = score;
247
+ bS = sIdx; bEx = ex; bEy = ey; bBw = bw; bBh = bh; bStop = stopT;
248
+ }
249
+ }
250
+ }
251
+ }
252
+ }
253
+ if (bS < 0) return;
254
+
255
+ // 拼出:回家路径 + 回路
256
+ {
257
+ vector<int> rev;
258
+ int k = bS;
259
+ while (k != head) {
260
+ int d = bfsD[k], x = k % W, y = k / W, pk = -1;
261
+ for (int dd = 0; dd < 4; dd++) {
262
+ int nx = x + DX[dd], ny = y + DY[dd];
263
+ if (inb(nx, ny) && bfsD[ny * W + nx] == d - 1) { pk = ny * W + nx; break; }
264
+ }
265
+ if (pk < 0) { plan.clear(); return; }
266
+ rev.push_back(pk);
267
+ k = pk;
268
+ }
269
+ int x = pX[ME], y = pY[ME];
270
+ for (int i = (int)rev.size() - 1; i >= 0; i--) {
271
+ int tx = rev[i] % W, ty = rev[i] / W;
272
+ for (int dd = 0; dd < 4; dd++)
273
+ if (x + DX[dd] == tx && y + DY[dd] == ty) { plan.push_back(dd); break; }
274
+ x = tx; y = ty;
275
+ }
276
+ }
277
+ int dIn = bEx ? 3 : 2, dA1 = bEy ? 0 : 1, dH2 = bEx ? 2 : 3, dUp = bEy ? 1 : 0, dH5 = bEx ? 3 : 2;
278
+ vector<int> ring;
279
+ ring.push_back(dIn);
280
+ for (int i = 0; i < bBh; i++) ring.push_back(dA1);
281
+ for (int i = 0; i < bBw + 1; i++) ring.push_back(dH2);
282
+ for (int i = 0; i < bBh + 1; i++) ring.push_back(dUp);
283
+ for (int i = 0; i < bBw; i++) ring.push_back(dH5);
284
+ ring.push_back(dA1);
285
+ int nRing = bStop ? bStop : (int)ring.size();
286
+ for (int i = 0; i < nRing && i < (int)ring.size(); i++) plan.push_back(ring[i]);
287
+ }
288
+
289
+ // ---------------------------------------------------------------- 决策
290
+ static int decide() {
291
+ int hx = pX[ME], hy = pY[ME], hd = pD[ME];
292
+ int back = hd ^ 1;
293
+
294
+ // 合法:不能掉头、不能出界、不能踩自己的轨迹
295
+ auto legal = [&](int d, int& nx, int& ny) {
296
+ if (d == back) return false;
297
+ nx = hx + DX[d]; ny = hy + DY[d];
298
+ if (!inb(nx, ny)) return false;
299
+ if (trl[ny * W + nx] == MEc) return false;
300
+ return true;
301
+ };
302
+ // 走上去会和一个贴脸的首领换位 = 同归于尽
303
+ auto swapDie = [&](int nx, int ny) {
304
+ for (int j = 0; j < N; j++) {
305
+ if (j == ME) continue;
306
+ if (pX[j] == nx && pY[j] == ny && abs(pX[j] - hx) + abs(pY[j] - hy) == 1) return true;
307
+ }
308
+ return false;
309
+ };
310
+ auto tryStep = [&](int d) {
311
+ int nx, ny;
312
+ return legal(d, nx, ny) && !swapDie(nx, ny);
313
+ };
314
+ int nx, ny;
315
+
316
+ // 提前圈地(半路踩回自己领地):原计划作废
317
+ if (planActive && wasOutside && pTL[ME] == 0 && own[hy * W + hx] == MEc) {
318
+ plan.clear();
319
+ planActive = false;
320
+ }
321
+
322
+ // 紧急:某个对手这一圈下来会把我整块吞掉,只能去踩断它的轨迹
323
+ for (int j = 0; j < N; j++) {
324
+ if (j == ME || pTL[j] == 0) continue;
325
+ if (!enemyEnclosesMe(j)) continue;
326
+ int d = bfsRun(1, j);
327
+ if (d >= 0 && tryStep(d)) {
328
+ plan.clear();
329
+ planActive = false;
330
+ return d;
331
+ }
332
+ break;
333
+ }
334
+
335
+ // 切人:对手轨迹就是它这一轮全部积累,踩一脚等于让它白跑几十回合。
336
+ // 手上有东西(正在画圈)时只有贴脸才切;空手时可以为了一口大鱼多跑几步。
337
+ if (plan.size() <= 3 || pTL[ME] <= 1) {
338
+ bool idle = (plan.empty() || plan.size() <= 3) && pTL[ME] <= 1;
339
+ int maxD = idle ? 6 : 3, minTL = idle ? 4 : 6;
340
+ for (int j = 0; j < N; j++) {
341
+ if (j == ME || pTL[j] < minTL) continue;
342
+ int d = bfsRun(1, j);
343
+ if (d < 0 || lastDist > maxD) continue;
344
+ if (tryStep(d)) { plan.clear(); planActive = false; return d; }
345
+ }
346
+ }
347
+
348
+ if (plan.empty()) {
349
+ buildPlan();
350
+ planActive = !plan.empty();
351
+ wasOutside = false;
352
+ }
353
+ if (!plan.empty()) {
354
+ int d = plan[0];
355
+ if (tryStep(d)) {
356
+ plan.erase(plan.begin());
357
+ int tx = hx + DX[d], ty = hy + DY[d];
358
+ if (own[ty * W + tx] != MEc) wasOutside = true;
359
+ if (plan.empty()) planActive = false;
360
+ return d;
361
+ }
362
+ plan.clear(); // 计划被堵死,重排
363
+ planActive = false;
364
+ buildPlan();
365
+ planActive = !plan.empty();
366
+ wasOutside = false;
367
+ if (!plan.empty()) {
368
+ int d = plan[0];
369
+ if (tryStep(d)) {
370
+ plan.erase(plan.begin());
371
+ int tx = hx + DX[d], ty = hy + DY[d];
372
+ if (own[ty * W + tx] != MEc) wasOutside = true;
373
+ if (plan.empty()) planActive = false;
374
+ return d;
375
+ }
376
+ plan.clear();
377
+ planActive = false;
378
+ }
379
+ }
380
+
381
+ // 兜底:回家;在领地里就沿着领地晃(领地内移动不掉血)
382
+ {
383
+ int d = bfsRun(2, 0);
384
+ if (d >= 0 && tryStep(d)) return d;
385
+ }
386
+ if (own[hy * W + hx] == MEc) {
387
+ for (int d = 0; d < 4; d++)
388
+ if (tryStep(d) && own[(hy + DY[d]) * W + hx + DX[d]] == MEc) return d;
389
+ }
390
+ for (int d = 0; d < 4; d++) if (tryStep(d)) return d;
391
+ return hd;
392
+ }
393
+
394
+ static bool readState() {
395
+ string tok;
396
+ if (!(cin >> tok)) return false;
397
+ if (!(cin >> TURN)) return false;
398
+ for (int i = 0; i < N; i++) {
399
+ int id, x, y, tl, ar, de; char dc;
400
+ cin >> tok >> id >> x >> y >> dc >> tl >> ar >> de;
401
+ pX[id] = x; pY[id] = y; pD[id] = dOf(dc); pTL[id] = tl; pA[id] = ar; pDe[id] = de;
402
+ }
403
+ cin >> tok; // OWNER
404
+ {
405
+ string row;
406
+ for (int y = 0; y < H; y++) {
407
+ cin >> row;
408
+ signed char* o = own.data() + y * W;
409
+ for (int x = 0; x < W; x++) o[x] = (row[x] == '.') ? -1 : (signed char)(row[x] - '0');
410
+ }
411
+ }
412
+ cin >> tok; // TRAIL
413
+ {
414
+ string row;
415
+ for (int y = 0; y < H; y++) {
416
+ cin >> row;
417
+ signed char* o = trl.data() + y * W;
418
+ for (int x = 0; x < W; x++) o[x] = (row[x] == '.') ? -1 : (signed char)(row[x] - '0');
419
+ }
420
+ }
421
+ cin >> tok; // END
422
+ return true;
423
+ }
424
+
425
+ int main() {
426
+ ios::sync_with_stdio(false);
427
+ cin.tie(nullptr);
428
+ string tok;
429
+ if (!(cin >> tok)) return 0; // INIT
430
+ if (!(cin >> W >> H >> MAXT >> N >> ME >> MOVE_MS >> INIT_MS)) return 0;
431
+ MEc = ME;
432
+ for (int i = 0; i < N; i++) {
433
+ int id, x, y;
434
+ cin >> tok >> id >> x >> y;
435
+ spx[id] = x; spy[id] = y;
436
+ }
437
+ own.assign(W * H, -1);
438
+ trl.assign(W * H, -1);
439
+ seen.assign(W * H, 0);
440
+
441
+ while (readState()) {
442
+ // 到最近对手头部的距离(纯网格 BFS,取最小)
443
+ for (int k = 0; k < W * H; k++) edist[k] = 1 << 20;
444
+ for (int j = 0; j < N; j++) {
445
+ if (j == ME) continue;
446
+ int qh = 0, qt = 0;
447
+ int s = pY[j] * W + pX[j];
448
+ if (edist[s] != 0) { edist[s] = 0; qb[qt++] = s; }
449
+ while (qh < qt) {
450
+ int k = qb[qh++];
451
+ int x = k % W, y = k / W;
452
+ for (int dd = 0; dd < 4; dd++) {
453
+ int ax = x + DX[dd], ay = y + DY[dd];
454
+ if (!inb(ax, ay)) continue;
455
+ int nk = ay * W + ax;
456
+ if (edist[nk] != 0) continue;
457
+ edist[nk] = edist[k] + 1;
458
+ qb[qt++] = nk;
459
+ }
460
+ }
461
+ }
462
+ int d = decide();
463
+ cout << TURN << ' ' << DCH[d] << endl;
464
+ }
465
+ return 0;
466
+ }