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,569 @@
1
+ // 夺旗 bot v1:全图 BFS + 任务分配(送旗/截击/取旗/护送/待命)+ 3 角色联合动作评估(威胁、命中、集火、击杀)
2
+ #include <bits/stdc++.h>
3
+ using namespace std;
4
+
5
+ struct Unit { int id, team, x, y, hp, flag, respawn_at; }; // 阵亡时 x = y = -1
6
+ struct Flag { int id; string status; int x, y, holder, return_at; };
7
+ struct Event { string type; vector<int> args; };
8
+
9
+ struct Game {
10
+ int teams = 0, me = 0, size = 0, turns = 0, hp = 0, damage = 0, respawn = 0, flag_return = 0, flag_cooldown = 0;
11
+ vector<string> map;
12
+ vector<pair<int, int>> bases;
13
+ vector<pair<int, int>> spots;
14
+ int turn = 0;
15
+ vector<int> score;
16
+ vector<Unit> units;
17
+ vector<Flag> flags;
18
+ vector<Event> events;
19
+ };
20
+
21
+ bool read_turn(Game& g) {
22
+ string w;
23
+ while (cin >> w) {
24
+ if (w == "INIT") {
25
+ cin >> g.teams >> g.me >> g.size >> g.turns >> g.hp >> g.damage >> g.respawn >> g.flag_return >> g.flag_cooldown;
26
+ } else if (w == "MAP") {
27
+ g.map.assign(g.size, "");
28
+ for (auto& row : g.map) cin >> row;
29
+ } else if (w == "BASES") {
30
+ int k; cin >> k; g.bases.resize(k);
31
+ for (auto& b : g.bases) cin >> b.first >> b.second;
32
+ } else if (w == "SPOTS") {
33
+ int k; cin >> k; g.spots.resize(k);
34
+ for (auto& s : g.spots) cin >> s.first >> s.second;
35
+ } else if (w == "TURN") {
36
+ cin >> g.turn;
37
+ } else if (w == "SCORE") {
38
+ g.score.resize(g.teams);
39
+ for (auto& s : g.score) cin >> s;
40
+ } else if (w == "UNITS") {
41
+ int k; cin >> k; g.units.resize(k);
42
+ for (auto& u : g.units) { string tag; cin >> tag >> u.id >> u.team >> u.x >> u.y >> u.hp >> u.flag >> u.respawn_at; }
43
+ } else if (w == "FLAGS") {
44
+ int k; cin >> k; g.flags.resize(k);
45
+ for (auto& f : g.flags) { string tag; cin >> tag >> f.id >> f.status >> f.x >> f.y >> f.holder >> f.return_at; }
46
+ } else if (w == "EVENTS") {
47
+ int k; cin >> k; g.events.assign(k, {});
48
+ string line; getline(cin, line);
49
+ for (auto& e : g.events) {
50
+ getline(cin, line);
51
+ istringstream in(line);
52
+ string tag; in >> tag >> e.type;
53
+ for (int v; in >> v;) e.args.push_back(v);
54
+ }
55
+ } else if (w == "END") {
56
+ return true;
57
+ }
58
+ }
59
+ return false;
60
+ }
61
+
62
+ // ============================ 参数 ============================
63
+ static double envd(const char* n, double d) {
64
+ #ifdef TUNE
65
+ const char* s = getenv(n);
66
+ if (s) return atof(s);
67
+ #endif
68
+ (void)n;
69
+ return d;
70
+ }
71
+ struct Params {
72
+ double VK, VKC, VD, VDC, VHD, VHT, PICK, CAPT, WG_FETCH, WG_DELIV, WG_HUNT, WG_SUP, WG_STA;
73
+ double P_IN, P_REACH, STAYW, SLACK, ELIG, HUNTSLACK, ENGR, ENGRATIO, WG_ENG, PF1, PF2, FETCHMAXEFF, ESCR, WG_ESC, CTRN, FELIG, FEN;
74
+ void load() {
75
+ VK = envd("VK", 11); VKC = envd("VKC", 22); VD = envd("VD", 5); VDC = envd("VDC", 28);
76
+ VHD = envd("VHD", 3.0); VHT = envd("VHT", 2.0); PICK = envd("PICK", 30); CAPT = envd("CAPT", 100);
77
+ WG_FETCH = envd("WG_FETCH", 1.6); WG_DELIV = envd("WG_DELIV", 1.5); WG_HUNT = envd("WG_HUNT", 1.2);
78
+ WG_SUP = envd("WG_SUP", 0.5); WG_STA = envd("WG_STA", 0.3);
79
+ P_IN = envd("P_IN", 0.9); P_REACH = envd("P_REACH", 0.5); STAYW = envd("STAYW", 0.35); SLACK = envd("SLACK", 5); ELIG = envd("ELIG", 3); HUNTSLACK = envd("HUNTSLACK", 2); ENGR = envd("ENGR", 6); ENGRATIO = envd("ENGRATIO", 1.0); WG_ENG = envd("WG_ENG", 0.8); PF1 = envd("PF1", 1.0); PF2 = envd("PF2", 1.0); FETCHMAXEFF = envd("FETCHMAXEFF", 99); CTRN = envd("CTRN", 4); FELIG = envd("FELIG", 99); FEN = envd("FEN", 4); ESCR = envd("ESCR", 8); WG_ESC = envd("WG_ESC", 1.2);
80
+ }
81
+ } PR;
82
+
83
+ // ============================ 地图 ============================
84
+ static const int MAXC = 49 * 49;
85
+ static const int INFD = 30000;
86
+ static int W, NC, NT, ME;
87
+ static bool WALL[MAXC];
88
+ static int NB[MAXC][5]; // 0 不动 1 上 2 下 3 左 4 右;-1 为墙
89
+ static const int DXs[5] = {0, 0, 0, -1, 1};
90
+ static const int DYs[5] = {0, -1, 1, 0, 0};
91
+ static const char MVC[5] = {'S', 'U', 'D', 'L', 'R'};
92
+ static vector<int16_t> DISTV;
93
+ static int16_t* DIST;
94
+ static vector<vector<int>> BASED; // BASED[team][cell]:到该队基地的最短步数
95
+ static vector<array<int, 9>> BASECELLS;
96
+ static vector<vector<char>> ISBASE;
97
+ static vector<vector<int>> SPAWN;
98
+ static vector<int> SPOTC, BASEC;
99
+ static int CENTER, MYSPOT;
100
+ static bool inited = false;
101
+
102
+ static inline int Cx(int c) { return c % W; }
103
+ static inline int Cy(int c) { return c / W; }
104
+ static inline int MD(int a, int b) { return abs(a % W - b % W) + abs(a / W - b / W); }
105
+ static inline int D2(int a, int b) { return DIST[a * NC + b]; }
106
+
107
+ static bool canAtk(int a, int b) {
108
+ int ax = a % W, ay = a / W, bx = b % W, by = b / W;
109
+ int dx = bx - ax, dy = by - ay;
110
+ if (abs(dx) + abs(dy) > 2) return false;
111
+ if (abs(dx) == 2 && dy == 0) return !WALL[ay * W + ax + dx / 2];
112
+ if (abs(dy) == 2 && dx == 0) return !WALL[(ay + dy / 2) * W + ax];
113
+ if (abs(dx) == 1 && abs(dy) == 1) return !WALL[ay * W + ax + dx] || !WALL[(ay + dy) * W + ax];
114
+ return true;
115
+ }
116
+
117
+ static void bfsFrom(int s, int16_t* d) {
118
+ static int q[MAXC];
119
+ for (int i = 0; i < NC; i++) d[i] = INFD;
120
+ int h = 0, t = 0; q[t++] = s; d[s] = 0;
121
+ while (h < t) {
122
+ int c = q[h++];
123
+ for (int k = 1; k < 5; k++) { int n = NB[c][k]; if (n >= 0 && d[n] == INFD) { d[n] = d[c] + 1; q[t++] = n; } }
124
+ }
125
+ }
126
+
127
+ static void init(const Game& g) {
128
+ PR.load();
129
+ W = g.size; NC = W * W; NT = g.teams; ME = g.me;
130
+ for (int y = 0; y < W; y++) for (int x = 0; x < W; x++) WALL[y * W + x] = g.map[y][x] == '#';
131
+ for (int c = 0; c < NC; c++) {
132
+ int x = c % W, y = c / W;
133
+ for (int k = 0; k < 5; k++) {
134
+ int nx = x + DXs[k], ny = y + DYs[k];
135
+ if (WALL[c] || nx < 0 || ny < 0 || nx >= W || ny >= W || WALL[ny * W + nx]) NB[c][k] = (k == 0 && !WALL[c]) ? c : -1;
136
+ else NB[c][k] = ny * W + nx;
137
+ }
138
+ }
139
+ DISTV.assign((size_t)NC * NC, INFD);
140
+ DIST = DISTV.data();
141
+ for (int s = 0; s < NC; s++) if (!WALL[s]) bfsFrom(s, DIST + (size_t)s * NC);
142
+ CENTER = (W / 2) * W + W / 2;
143
+ BASEC.clear(); BASECELLS.assign(NT, {}); ISBASE.assign(NT, vector<char>(NC, 0)); BASED.assign(NT, vector<int>(NC, INFD)); SPAWN.assign(NT, {});
144
+ for (int t = 0; t < NT; t++) {
145
+ int bx = g.bases[t].first, by = g.bases[t].second;
146
+ BASEC.push_back(by * W + bx);
147
+ int k = 0;
148
+ vector<int> cells;
149
+ for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) { int c = (by + dy) * W + bx + dx; BASECELLS[t][k++] = c; ISBASE[t][c] = 1; cells.push_back(c); }
150
+ for (int c = 0; c < NC; c++) if (!WALL[c]) { int m = INFD; for (int bc : BASECELLS[t]) m = min(m, (int)D2(bc, c)); BASED[t][c] = m; }
151
+ stable_sort(cells.begin(), cells.end(), [&](int a, int b) {
152
+ auto key = [&](int c) { return make_pair(abs(c % W - W / 2) + abs(c / W - W / 2), abs(c % W - bx) + 2 * abs(c / W - by)); };
153
+ return key(a) < key(b);
154
+ });
155
+ SPAWN[t] = cells;
156
+ }
157
+ SPOTC.clear();
158
+ for (auto& s : g.spots) SPOTC.push_back(s.second * W + s.first);
159
+ MYSPOT = SPOTC.empty() ? CENTER : SPOTC[0];
160
+ int best = INFD;
161
+ for (int s : SPOTC) { int d = D2(BASEC[ME], s); if (d < best) { best = d; MYSPOT = s; } }
162
+ inited = true;
163
+ }
164
+
165
+ // ============================ 决策 ============================
166
+ struct En { int id, team, c, hp, flag; bool canAtk; int nm; int mc[5]; };
167
+ struct My {
168
+ int k, id; bool active, spawning; int c, hp, flag;
169
+ int nm; int mv[5]; int mc[5];
170
+ int mode = 0; // 0 待命 1 取旗 2 送旗 3 截击 4 护送/支援
171
+ vector<int> G; double wg = 0; int fcell = -1; int tgtEn = -1;
172
+ string note;
173
+ };
174
+
175
+ static double atLeast(const double* p, int n, int need) {
176
+ if (need <= 0) return 1.0;
177
+ if (n < need) return 0.0;
178
+ double dp[8] = {0}; dp[0] = 1.0;
179
+ for (int i = 0; i < n; i++) {
180
+ for (int k = need; k >= 0; k--) {
181
+ double up = (k > 0 ? dp[k - 1] * p[i] : 0.0);
182
+ if (k == need) dp[k] = dp[k] + up;
183
+ else dp[k] = dp[k] * (1 - p[i]) + up;
184
+ }
185
+ }
186
+ return dp[need];
187
+ }
188
+
189
+ static string decide(const Game& g) {
190
+ if (!inited) init(g);
191
+ const int t = g.turn;
192
+ const int remaining = g.turns - t + 1; // 含本回合
193
+ vector<Unit> us(NT * 3);
194
+ for (auto& u : g.units) if (u.id >= 0 && u.id < NT * 3) us[u.id] = u;
195
+ vector<int> occ(NC, -1);
196
+ for (auto& u : us) if (u.x >= 0) occ[u.y * W + u.x] = u.id;
197
+
198
+ // ---- 敌方 ----
199
+ vector<En> en;
200
+ for (auto& u : us) {
201
+ if (u.team == ME || u.x < 0) continue;
202
+ En e; e.id = u.id; e.team = u.team; e.c = u.y * W + u.x; e.hp = u.hp; e.flag = u.flag; e.canAtk = (u.flag < 0);
203
+ e.nm = 0;
204
+ for (int k = 0; k < 5; k++) if (NB[e.c][k] >= 0) e.mc[e.nm++] = NB[e.c][k];
205
+ en.push_back(e);
206
+ }
207
+ // ---- 己方 ----
208
+ My my[3];
209
+ {
210
+ vector<char> taken(NC, 0);
211
+ for (int c = 0; c < NC; c++) if (occ[c] >= 0) taken[c] = 1;
212
+ for (int k = 0; k < 3; k++) {
213
+ My& m = my[k]; Unit& u = us[3 * ME + k];
214
+ m.k = k; m.id = 3 * ME + k; m.hp = u.hp; m.flag = u.flag; m.active = false; m.spawning = false; m.nm = 0; m.c = -1;
215
+ if (u.x >= 0) { m.active = true; m.c = u.y * W + u.x; }
216
+ else if (u.respawn_at == t) {
217
+ for (int c : SPAWN[ME]) if (!taken[c]) { taken[c] = 1; m.c = c; m.active = true; m.spawning = true; m.hp = g.hp; m.flag = -1; break; }
218
+ }
219
+ }
220
+ }
221
+ // ---- 旗子 ----
222
+ struct FI { int id, c, st, ret; };
223
+ vector<FI> avail; // 可拾取的旗
224
+ vector<int> carriedBy(g.flags.size(), -1);
225
+ for (auto& f : g.flags) {
226
+ if (f.status == "home" && f.x >= 0) avail.push_back({f.id, f.y * W + f.x, 0, 1 << 30});
227
+ else if (f.status == "dropped" && f.x >= 0 && f.return_at > t) avail.push_back({f.id, f.y * W + f.x, 1, f.return_at});
228
+ }
229
+
230
+ // ---- 候选移动 ----
231
+ for (int k = 0; k < 3; k++) {
232
+ My& m = my[k];
233
+ if (!m.active) continue;
234
+ for (int mv = 0; mv < 5; mv++) {
235
+ int nc = NB[m.c][mv];
236
+ if (nc < 0) continue;
237
+ if (mv != 0 && occ[nc] >= 0 && us[occ[nc]].team != ME) continue;
238
+ m.mv[m.nm] = mv; m.mc[m.nm] = nc; m.nm++;
239
+ }
240
+ }
241
+
242
+ // ---- 任务分配 ----
243
+ bool assigned[3] = {false, false, false};
244
+ auto setGoal = [&](My& m, int mode, int cell, double wg) {
245
+ m.mode = mode; m.G.assign(NC, 0);
246
+ for (int c = 0; c < NC; c++) m.G[c] = (cell >= 0) ? D2(cell, c) : 0;
247
+ m.wg = wg;
248
+ };
249
+ // 危险附加代价(用于携旗者绕行)
250
+ vector<int> extra(NC, 0);
251
+ for (auto& e : en) if (e.canAtk) {
252
+ int ex = e.c % W, ey = e.c / W;
253
+ for (int dy = -3; dy <= 3; dy++) for (int dx = -3; dx <= 3; dx++) {
254
+ int d = abs(dx) + abs(dy); if (d > 3) continue;
255
+ int x = ex + dx, y = ey + dy; if (x < 0 || y < 0 || x >= W || y >= W) continue;
256
+ extra[y * W + x] += (d <= 2 ? 3 : 1);
257
+ }
258
+ }
259
+ // 1) 携旗者:送旗(带危险代价的 Dijkstra)
260
+ bool anyCarrier = false; int carrierK = -1;
261
+ {
262
+ bool need = false;
263
+ for (int k = 0; k < 3; k++) if (my[k].active && my[k].flag >= 0) need = true;
264
+ if (need) {
265
+ vector<int> sd(NC, INFD);
266
+ priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
267
+ for (int bc : BASECELLS[ME]) { sd[bc] = 0; pq.push({0, bc}); }
268
+ while (!pq.empty()) {
269
+ auto [d, c] = pq.top(); pq.pop();
270
+ if (d > sd[c]) continue;
271
+ for (int k = 1; k < 5; k++) { int n = NB[c][k]; if (n < 0) continue; int nd = d + 1 + extra[c]; if (nd < sd[n]) { sd[n] = nd; pq.push({nd, n}); } }
272
+ }
273
+ for (int k = 0; k < 3; k++) if (my[k].active && my[k].flag >= 0) {
274
+ My& m = my[k]; m.mode = 2; m.G = sd; m.wg = PR.WG_DELIV; assigned[k] = true; anyCarrier = true; carrierK = k; m.note = "deliver";
275
+ }
276
+ }
277
+ }
278
+ // 2) 截击敌方携旗者
279
+ vector<int> enemyCarriers;
280
+ for (int i = 0; i < (int)en.size(); i++) if (en[i].flag >= 0) enemyCarriers.push_back(i);
281
+ for (int ei : enemyCarriers) {
282
+ const En& e = en[ei];
283
+ // 敌方预测路径
284
+ vector<int> path; int c = e.c; path.push_back(c);
285
+ for (int s = 0; s < 40 && BASED[e.team][c] > 0; s++) {
286
+ int bestn = -1, bd = BASED[e.team][c];
287
+ for (int k = 1; k < 5; k++) { int n = NB[c][k]; if (n >= 0 && BASED[e.team][n] < bd) { bd = BASED[e.team][n]; bestn = n; } }
288
+ if (bestn < 0) break;
289
+ c = bestn; path.push_back(c);
290
+ }
291
+ // 找截击者:所有能赶上的空闲角色
292
+ for (int k = 0; k < 3; k++) {
293
+ if (!my[k].active || assigned[k] || my[k].flag >= 0) continue;
294
+ for (int s = 0; s < (int)path.size(); s++) {
295
+ int d = D2(my[k].c, path[s]);
296
+ if (d <= s + (int)PR.HUNTSLACK && s <= 14) {
297
+ My& m = my[k]; setGoal(m, 3, path[s], PR.WG_HUNT); m.tgtEn = ei; assigned[k] = true; m.note = "hunt";
298
+ break;
299
+ }
300
+ }
301
+ }
302
+ }
303
+ // 3) 取旗
304
+ {
305
+ struct Cand { int k, fi, eta; };
306
+ vector<Cand> cands;
307
+ vector<int> rival(avail.size(), INFD);
308
+ for (int fi = 0; fi < (int)avail.size(); fi++) {
309
+ for (auto& e : en) if (e.flag < 0) rival[fi] = min(rival[fi], (int)D2(e.c, avail[fi].c));
310
+ for (auto& u : us) if (u.team != ME && u.x < 0 && u.respawn_at >= 0) {
311
+ int dd = max(0, u.respawn_at - t) + D2(BASEC[u.team], avail[fi].c);
312
+ rival[fi] = min(rival[fi], dd);
313
+ }
314
+ for (int k = 0; k < 3; k++) {
315
+ if (!my[k].active || assigned[k] || my[k].flag >= 0) continue;
316
+ int eta = D2(my[k].c, avail[fi].c);
317
+ if (avail[fi].st == 1 && eta > avail[fi].ret - t) continue;
318
+ if (eta + (int)BASED[ME][avail[fi].c] > remaining) continue;
319
+ cands.push_back({k, fi, eta});
320
+ }
321
+ }
322
+ sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) { return a.eta < b.eta; });
323
+ vector<char> fdone(avail.size(), 0);
324
+ for (auto& cd : cands) {
325
+ if (assigned[cd.k] || fdone[cd.fi]) continue;
326
+ int margin = rival[cd.fi] - cd.eta;
327
+ if (margin < -PR.SLACK) continue;
328
+ if (NT >= (int)PR.FEN) {
329
+ int mn = INFD;
330
+ for (int tt = 0; tt < NT; tt++) if (tt != ME) mn = min(mn, (int)D2(BASEC[tt], avail[cd.fi].c));
331
+ if (D2(BASEC[ME], avail[cd.fi].c) > mn + (int)PR.FELIG) continue;
332
+ }
333
+ if (BASED[ME][avail[cd.fi].c] > 3) {
334
+ int chasers = 0, guards = 0;
335
+ for (auto& e : en) if (e.canAtk && D2(e.c, avail[cd.fi].c) <= 3) chasers++;
336
+ for (int j = 0; j < 3; j++) if (j != cd.k && my[j].active && !my[j].spawning && D2(my[j].c, avail[cd.fi].c) <= 4) guards++;
337
+ if (chasers - guards >= (int)PR.FETCHMAXEFF) continue;
338
+ }
339
+ My& m = my[cd.k]; setGoal(m, 1, avail[cd.fi].c, PR.WG_FETCH); m.fcell = avail[cd.fi].c; assigned[cd.k] = true; fdone[cd.fi] = 1; m.note = "fetch";
340
+ }
341
+ }
342
+ // 4) 其余:护送 / 分散待命到空旗点
343
+ {
344
+ vector<int> freeK;
345
+ for (int k = 0; k < 3; k++) if (my[k].active && !assigned[k]) freeK.push_back(k);
346
+ if (anyCarrier && carrierK >= 0 && !freeK.empty()) {
347
+ int cc = my[carrierK].c;
348
+ vector<pair<int, int>> th;
349
+ for (int ei = 0; ei < (int)en.size(); ei++) if (en[ei].canAtk && D2(en[ei].c, cc) <= (int)PR.ESCR) th.push_back({D2(en[ei].c, cc), ei});
350
+ sort(th.begin(), th.end());
351
+ if (!th.empty()) {
352
+ sort(freeK.begin(), freeK.end(), [&](int a, int b) { return D2(my[a].c, cc) < D2(my[b].c, cc); });
353
+ vector<int> usedCells;
354
+ int nesc = min((int)freeK.size(), 2);
355
+ for (int idx = 0; idx < nesc; idx++) {
356
+ int k = freeK[idx]; const En& e = en[th[min(idx, (int)th.size() - 1)].second];
357
+ int bestCell = -1; double bv = 1e18;
358
+ int cx = cc % W, cy = cc / W;
359
+ for (int dy = -2; dy <= 2; dy++) for (int dx = -2; dx <= 2; dx++) {
360
+ if (abs(dx) + abs(dy) > 2) continue;
361
+ int x = cx + dx, y = cy + dy; if (x < 0 || y < 0 || x >= W || y >= W) continue;
362
+ int c = y * W + x; if (WALL[c] || c == cc) continue;
363
+ if (find(usedCells.begin(), usedCells.end(), c) != usedCells.end()) continue;
364
+ double v = D2(c, e.c) + 0.3 * D2(c, my[k].c);
365
+ if (v < bv) { bv = v; bestCell = c; }
366
+ }
367
+ if (bestCell < 0) continue;
368
+ usedCells.push_back(bestCell);
369
+ setGoal(my[k], 4, bestCell, PR.WG_ESC); my[k].note = "escort"; assigned[k] = true;
370
+ }
371
+ vector<int> rest;
372
+ for (int k : freeK) if (!assigned[k]) rest.push_back(k);
373
+ freeK = rest;
374
+ }
375
+ }
376
+ // 局部优势时主动接敌
377
+ for (int idx = 0; idx < (int)freeK.size();) {
378
+ int k = freeK[idx]; My& m = my[k];
379
+ int bestE = -1; double bestV = -1e9;
380
+ for (int ei = 0; ei < (int)en.size(); ei++) {
381
+ const En& e = en[ei]; int d = D2(m.c, e.c);
382
+ if (d > (int)PR.ENGR) continue;
383
+ double myP = 0, enP = 0;
384
+ for (int j = 0; j < 3; j++) if (my[j].active && !my[j].spawning && D2(my[j].c, e.c) <= 5) myP += my[j].hp;
385
+ for (auto& e2 : en) if (e2.canAtk && D2(e2.c, e.c) <= 4) enP += e2.hp;
386
+ if (myP < PR.ENGRATIO * enP) continue;
387
+ double v = -d - e.hp * 0.02 + (e.flag >= 0 ? 10 : 0);
388
+ if (v > bestV) { bestV = v; bestE = ei; }
389
+ }
390
+ if (bestE >= 0) { setGoal(m, 5, en[bestE].c, PR.WG_ENG); m.note = "engage"; assigned[k] = true; freeK.erase(freeK.begin() + idx); }
391
+ else idx++;
392
+ }
393
+ vector<int> stations;
394
+ for (int sp : SPOTC) {
395
+ bool hasFlag = false;
396
+ for (auto& f : g.flags) if (f.status == "home" && f.x >= 0 && f.y * W + f.x == sp) hasFlag = true;
397
+ if (hasFlag) continue;
398
+ if (sp == CENTER && NT >= (int)PR.CTRN) continue;
399
+ int myd = D2(BASEC[ME], sp), mn = INFD;
400
+ for (int tt = 0; tt < NT; tt++) if (tt != ME) mn = min(mn, (int)D2(BASEC[tt], sp));
401
+ if (myd <= mn + (int)PR.ELIG) stations.push_back(sp);
402
+ }
403
+ if (stations.empty()) stations.push_back(MYSPOT);
404
+ struct Pr { int k, si, d; };
405
+ vector<Pr> prs;
406
+ for (int k : freeK) for (int si = 0; si < (int)stations.size(); si++) prs.push_back({k, si, (int)D2(my[k].c, stations[si])});
407
+ sort(prs.begin(), prs.end(), [](const Pr& a, const Pr& b) { return a.d < b.d; });
408
+ vector<char> sused(stations.size(), 0);
409
+ for (auto& pr : prs) {
410
+ if (assigned[pr.k] || sused[pr.si]) continue;
411
+ setGoal(my[pr.k], 0, stations[pr.si], PR.WG_STA); my[pr.k].note = "station"; assigned[pr.k] = true; sused[pr.si] = 1;
412
+ }
413
+ for (int k : freeK) if (!assigned[k]) {
414
+ int bd = INFD, bs = stations[0];
415
+ for (int sp : stations) { int d = D2(my[k].c, sp); if (d < bd) { bd = d; bs = sp; } }
416
+ setGoal(my[k], 0, bs, PR.WG_STA); my[k].note = "station2"; assigned[k] = true;
417
+ }
418
+ }
419
+
420
+ // ---- 联合动作评估 ----
421
+ int NE = en.size();
422
+ // 预计算:pa[e][k][mi](敌方 e 攻击我方 k 在候选 mi 的概率),ph[e][k][mi](我方命中 e 的概率)
423
+ static double pa[48][3][5], ph[48][3][5];
424
+ for (int ei = 0; ei < NE; ei++) for (int k = 0; k < 3; k++) {
425
+ My& m = my[k];
426
+ for (int mi = 0; mi < m.nm; mi++) {
427
+ pa[ei][k][mi] = 0; ph[ei][k][mi] = 0;
428
+ if (!m.active) continue;
429
+ int c = m.mc[mi]; const En& e = en[ei];
430
+ if (e.canAtk && !m.spawning) {
431
+ bool now = canAtk(e.c, c), reach = false;
432
+ for (int q = 0; q < e.nm && !reach; q++) if (canAtk(e.mc[q], c)) reach = true;
433
+ pa[ei][k][mi] = now ? PR.P_IN : (reach ? PR.P_REACH : 0.0);
434
+ }
435
+ if (!m.spawning && m.flag < 0) {
436
+ double p = 0; int others = max(1, e.nm - 1);
437
+ for (int q = 0; q < e.nm; q++) {
438
+ double w = (e.mc[q] == e.c) ? PR.STAYW : (1 - PR.STAYW) / others;
439
+ if (e.nm == 1) w = 1.0;
440
+ if (canAtk(c, e.mc[q])) p += w;
441
+ }
442
+ ph[ei][k][mi] = min(1.0, p);
443
+ }
444
+ }
445
+ }
446
+ // 单元静态得分
447
+ double base[3][5];
448
+ int pickAt[3][5]; // 该位置可拾取旗(1)
449
+ double pickB[3][5];
450
+ for (int k = 0; k < 3; k++) {
451
+ My& m = my[k];
452
+ for (int mi = 0; mi < m.nm; mi++) {
453
+ int c = m.mc[mi];
454
+ double s = 0;
455
+ s -= m.wg * (m.G.empty() ? 0 : m.G[c]);
456
+ pickAt[k][mi] = 0; pickB[k][mi] = 0;
457
+ if (m.flag >= 0) {
458
+ if (ISBASE[ME][c]) s += PR.CAPT;
459
+ } else {
460
+ for (auto& f : avail) if (f.c == c) {
461
+ pickAt[k][mi] = 1;
462
+ double coll = 0;
463
+ for (auto& e : en) if (e.flag < 0 && D2(e.c, c) <= 1) coll = max(coll, 0.6);
464
+ double pf = 1.0;
465
+ if (BASED[ME][c] > 3) {
466
+ int chasers = 0, guards = 0;
467
+ for (auto& e : en) if (e.canAtk && D2(e.c, c) <= 3) chasers++;
468
+ for (int j = 0; j < 3; j++) if (j != k && my[j].active && !my[j].spawning && D2(my[j].c, c) <= 2) guards++;
469
+ int eff = max(0, chasers - guards);
470
+ pf = eff == 0 ? 1.0 : eff == 1 ? PR.PF1 : PR.PF2;
471
+ }
472
+ pickB[k][mi] = PR.PICK * (1 - coll) * pf;
473
+ }
474
+ }
475
+ base[k][mi] = s;
476
+ }
477
+ }
478
+ // 枚举
479
+ double bestScore = -1e18; int bestSel[3] = {0, 0, 0}; int bestTgt[3] = {-1, -1, -1};
480
+ int sel[3];
481
+ int n0 = my[0].active ? my[0].nm : 1, n1 = my[1].active ? my[1].nm : 1, n2 = my[2].active ? my[2].nm : 1;
482
+ for (sel[0] = 0; sel[0] < n0; sel[0]++) for (sel[1] = 0; sel[1] < n1; sel[1]++) for (sel[2] = 0; sel[2] < n2; sel[2]++) {
483
+ int cell[3] = {-1, -1, -1}; bool ok = true;
484
+ for (int k = 0; k < 3; k++) if (my[k].active) cell[k] = my[k].mc[sel[k]];
485
+ for (int a = 0; a < 3 && ok; a++) for (int b = a + 1; b < 3; b++) if (cell[a] >= 0 && cell[a] == cell[b]) { ok = false; break; }
486
+ if (!ok) continue;
487
+ double score = 0;
488
+ for (int k = 0; k < 3; k++) if (my[k].active) score += base[k][sel[k]];
489
+ // 敌方火力分配
490
+ double inc[3][48]; int incn[3] = {0, 0, 0};
491
+ for (int ei = 0; ei < NE; ei++) {
492
+ if (!en[ei].canAtk) continue;
493
+ int bk = -1; double bp = -1;
494
+ for (int k = 0; k < 3; k++) if (my[k].active && pa[ei][k][sel[k]] > 0) {
495
+ double pr = (my[k].flag >= 0 ? 1000 : 0) + (200 - my[k].hp) + pa[ei][k][sel[k]] * 10;
496
+ if (pr > bp) { bp = pr; bk = k; }
497
+ }
498
+ if (bk >= 0) inc[bk][incn[bk]++] = pa[ei][bk][sel[bk]];
499
+ }
500
+ for (int k = 0; k < 3; k++) if (my[k].active && incn[k] > 0) {
501
+ int need = (my[k].hp + g.damage - 1) / g.damage;
502
+ double pd = atLeast(inc[k], incn[k], need);
503
+ double eh = 0; for (int i = 0; i < incn[k]; i++) eh += inc[k][i];
504
+ double endf = min(1.0, remaining / 12.0);
505
+ double vd = PR.VD * (0.35 + 0.65 * min(1.0, my[k].hp / 100.0)) * endf + (my[k].flag >= 0 ? PR.VDC : 0);
506
+ score -= pd * vd + min(eh, (double)(need - 1)) * PR.VHT;
507
+ }
508
+ // 我方攻击目标枚举
509
+ int opt[3][5]; int on[3];
510
+ for (int k = 0; k < 3; k++) {
511
+ on[k] = 0; opt[k][on[k]++] = -1;
512
+ if (!my[k].active || my[k].spawning || my[k].flag >= 0) continue;
513
+ vector<pair<double, int>> lst;
514
+ for (int ei = 0; ei < NE; ei++) {
515
+ double p = ph[ei][k][sel[k]];
516
+ if (p > 0.05) lst.push_back({p + (en[ei].flag >= 0 ? 2 : 0) + (200 - en[ei].hp) * 0.01, ei});
517
+ }
518
+ sort(lst.begin(), lst.end(), [](auto& a, auto& b) { return a.first > b.first; });
519
+ for (int i = 0; i < (int)lst.size() && on[k] < 4; i++) opt[k][on[k]++] = lst[i].second;
520
+ }
521
+ double bestAtk = -1e18; int bt[3] = {-1, -1, -1};
522
+ for (int a = 0; a < on[0]; a++) for (int b = 0; b < on[1]; b++) for (int c = 0; c < on[2]; c++) {
523
+ int tg[3] = {opt[0][a], opt[1][b], opt[2][c]};
524
+ double val = 0;
525
+ // 汇总每个目标
526
+ for (int ei = 0; ei < NE; ei++) {
527
+ double ps[3]; int n = 0;
528
+ for (int k = 0; k < 3; k++) if (tg[k] == ei) ps[n++] = ph[ei][k][sel[k]];
529
+ if (!n) continue;
530
+ int need = (en[ei].hp + g.damage - 1) / g.damage;
531
+ double pk = atLeast(ps, n, need), eh = 0;
532
+ for (int i = 0; i < n; i++) eh += ps[i];
533
+ val += pk * (PR.VK + (en[ei].flag >= 0 ? PR.VKC : 0)) + min(eh, (double)need) * PR.VHD;
534
+ }
535
+ // 拾旗替代攻击
536
+ for (int k = 0; k < 3; k++) if (tg[k] < 0 && my[k].active && pickAt[k][sel[k]]) val += pickB[k][sel[k]];
537
+ if (val > bestAtk) { bestAtk = val; bt[0] = tg[0]; bt[1] = tg[1]; bt[2] = tg[2]; }
538
+ }
539
+ score += bestAtk;
540
+ if (score > bestScore) { bestScore = score; for (int k = 0; k < 3; k++) { bestSel[k] = sel[k]; bestTgt[k] = bt[k]; } }
541
+ }
542
+
543
+ // ---- 输出 ----
544
+ string out = to_string(t);
545
+ string notes;
546
+ for (int k = 0; k < 3; k++) {
547
+ My& m = my[k];
548
+ if (!m.active) { out += " S -"; notes += (k ? ";" : "") + string("dead"); continue; }
549
+ int mv = m.mv[bestSel[k]];
550
+ string act = "-";
551
+ if (bestTgt[k] >= 0) act = to_string(en[bestTgt[k]].id);
552
+ else act = "P";
553
+ out += string(" ") + MVC[mv] + " " + act;
554
+ notes += (k ? ";" : "") + m.note;
555
+ }
556
+ out += " # " + notes;
557
+ return out;
558
+ }
559
+
560
+ int main() {
561
+ ios::sync_with_stdio(false);
562
+ Game g;
563
+ while (read_turn(g)) {
564
+ string out;
565
+ try { out = decide(g); }
566
+ catch (...) { out = to_string(g.turn) + " S - S - S -"; }
567
+ cout << out << endl;
568
+ }
569
+ }
@@ -0,0 +1,15 @@
1
+ # 复现正式赛
2
+
3
+ 正式赛分两段:2–8 人(`formal-2to8.json`,每位选手一份)、9–15 人(`formal-9to15.json`,每位选手两份同场),合并评分。配置里写着原来的赛程种子,所以赛程(地图、座位、对阵)可以一模一样地重建。
4
+
5
+ 在本目录运行(全程约 2 小时,12 并发;可以中断后用同一命令续跑):
6
+
7
+ ```bash
8
+ python ../../arena/tournament.py plan formal-2to8.json run-2to8
9
+ python ../../arena/tournament.py plan formal-9to15.json run-9to15
10
+ python ../../arena/tournament.py run run-2to8 --workers 8
11
+ python ../../arena/tournament.py run run-9to15 --workers 8
12
+ python ../../arena/tournament.py rate run-2to8 run-9to15
13
+ ```
14
+
15
+ 注意:旗子每次刷新在哪个旗点用的是单独的随机数(每局现取,为了防止从地图反推),所以逐局比分不会和原赛完全相同,但总排名应当一致。每回合限时 50 毫秒,对机器负载敏感:每局程序数 × 并发局数,最好不超过 CPU 线程数的约 3/4。
@@ -0,0 +1,31 @@
1
+ {
2
+ "game": "../workspace/engine.py",
3
+ "anchor": "基准",
4
+ "players": {
5
+ "基准": "../workspace/baseline.cpp",
6
+ "Fable 5.1": "../bots/fable-5.1.cpp",
7
+ "Opus 5.5": "../bots/opus-5.5.cpp",
8
+ "Sonnet 5.5": "../bots/sonnet-5.5.cpp",
9
+ "GPT-6 Astra": "../bots/gpt-6-astra.cpp",
10
+ "GPT-6.1 Sol": "../bots/gpt-6.1-sol.cpp",
11
+ "DeepSeek V4.1 Flash": "../bots/deepseek-v4.1-flash.cpp",
12
+ "Qwen 3.8 Max": "../bots/qwen-3.8-max.cpp",
13
+ "GLM 5.3": "../bots/glm-5.3.cpp",
14
+ "MiMo V2.6 Pro": "../bots/mimo-v2.6-pro.cpp",
15
+ "豆包 Seed 2.1 Turbo": "../bots/doubao-seed-2.1-turbo.cpp",
16
+ "Kimi K3": "../bots/kimi-k3.cpp"
17
+ },
18
+ "sizes": [
19
+ 2,
20
+ 3,
21
+ 4,
22
+ 5,
23
+ 6,
24
+ 7,
25
+ 8
26
+ ],
27
+ "maps_per_size": 110,
28
+ "copies": 1,
29
+ "seed": 27772916379806,
30
+ "replays": false
31
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "game": "../workspace/engine.py",
3
+ "anchor": "基准",
4
+ "players": {
5
+ "基准": "../workspace/baseline.cpp",
6
+ "Fable 5.1": "../bots/fable-5.1.cpp",
7
+ "Opus 5.5": "../bots/opus-5.5.cpp",
8
+ "Sonnet 5.5": "../bots/sonnet-5.5.cpp",
9
+ "GPT-6 Astra": "../bots/gpt-6-astra.cpp",
10
+ "GPT-6.1 Sol": "../bots/gpt-6.1-sol.cpp",
11
+ "DeepSeek V4.1 Flash": "../bots/deepseek-v4.1-flash.cpp",
12
+ "Qwen 3.8 Max": "../bots/qwen-3.8-max.cpp",
13
+ "GLM 5.3": "../bots/glm-5.3.cpp",
14
+ "MiMo V2.6 Pro": "../bots/mimo-v2.6-pro.cpp",
15
+ "豆包 Seed 2.1 Turbo": "../bots/doubao-seed-2.1-turbo.cpp",
16
+ "Kimi K3": "../bots/kimi-k3.cpp"
17
+ },
18
+ "sizes": [
19
+ 9,
20
+ 10,
21
+ 11,
22
+ 12,
23
+ 13,
24
+ 14,
25
+ 15
26
+ ],
27
+ "maps_per_size": 110,
28
+ "copies": 2,
29
+ "seed": 91187465621305,
30
+ "replays": false
31
+ }