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,447 @@
1
+ // Bomberman bot for 2-10 players (bomb-arena-0.5-public-state).
2
+ //
3
+ // Strategy, in one paragraph per layer:
4
+ //
5
+ // 1. Danger timeline. For every future turn k the bot rebuilds the exact blast
6
+ // geometry of the rules: shrink layers turning cells into walls (bombs, crates
7
+ // and flames on them removed), flame expiry, the full explosion phase over one
8
+ // pre-explosion snapshot (fuse expiry or a bomb already sitting in flame, rays
9
+ // of three cells, crates burned and blocking, a hit bomb chaining immediately and
10
+ // blocking that ray), and crate removal. That yields, per turn, which cells block
11
+ // movement, which hold bombs, and which kill anyone standing on them. This
12
+ // timeline was validated cell-for-cell against the reference engine.
13
+ // 2. Survival horizon. A time-expanded search over the timeline gives the number of
14
+ // turns the bot can keep itself alive, the smallest number of distinct escape
15
+ // cells available along the way, and the size of the reachable set at the end.
16
+ // The pessimistic pass assumes every living rival drops a bomb next turn on the
17
+ // cell it occupies and on the passable neighbour that closes the distance to us,
18
+ // and that rival cells cannot be entered; the optimistic pass uses only the bombs
19
+ // already on the board with a long horizon so that wanderers still walk towards
20
+ // the shrinking centre.
21
+ // 3. Choice. Each of the ten (move, place?) pairs is scored on both horizons plus a
22
+ // positional term: depth band a couple of layers inside the current wall,
23
+ // local openness, crowding penalty near rivals, revisit penalty. Because scoring
24
+ // is joint, a bomb that would trap the bot - including one that chains an adjacent
25
+ // bomb straight back onto its own cell - is simply never selected.
26
+ // 4. Offense. A placement is credited by how far it cuts each rival's own survival
27
+ // horizon and escape set (recomputed with the bomb added), with a large bonus when
28
+ // a rival is trapped outright and when the bomb sits next to a rival bomb, where a
29
+ // chain detonation does the work. Crates come for free: the timeline burns them,
30
+ // so bombing is also how the bot opens its own escape routes when boxed in.
31
+ //
32
+ // Public state only, no randomness, no file or network access.
33
+ #include <bits/stdc++.h>
34
+ #include <chrono>
35
+ using namespace std;
36
+
37
+ static int N = 13, P = 2, ME = 0, T = 0, LIMIT = 300, FUSE = 4, RANGE = 3, CAP = 2, FIRE = 2,
38
+ SHRINK = 150, EVERY = 20;
39
+ static const int DX[5] = {0, 0, -1, 1, 0};
40
+ static const int DY[5] = {-1, 1, 0, 0, 0};
41
+ static const char DC[5] = {'U', 'D', 'L', 'R', 'S'};
42
+
43
+ struct Pl { int x = 0, y = 0, alive = 1; };
44
+ struct Bm { int owner = 0, x = 0, y = 0, at = 0; };
45
+
46
+ static vector<string> board;
47
+ static vector<Pl> players;
48
+ static vector<Bm> bombs;
49
+ static vector<array<int, 3>> flames; // x,y,last lethal turn
50
+
51
+ static inline int cell(int x, int y) { return y * N + x; }
52
+ static inline int CX(int c) { return c % N; }
53
+ static inline int CY(int c) { return c / N; }
54
+ static inline int edgeOf(int c) { int x = CX(c), y = CY(c); return min(min(x, y), min(N - 1 - x, N - 1 - y)); }
55
+
56
+ // ---------------------------------------------------------------- timeline
57
+ // For each future turn T+k we record, at movement phase and at end of turn:
58
+ // blk : cell blocks movement (permanent wall or standing crate)
59
+ // occ : bomb occupies the cell during that turn's movement phase
60
+ // leak : standing on the cell at the end of the turn kills you (wall or flame)
61
+ struct TL {
62
+ int H = 0, NN = 0;
63
+ vector<unsigned char> blk, occ, leak;
64
+ void init(int h, int nn) {
65
+ H = h; NN = nn;
66
+ blk.assign((size_t)h * nn, 0);
67
+ occ.assign((size_t)h * nn, 0);
68
+ leak.assign((size_t)h * nn, 0);
69
+ }
70
+ };
71
+
72
+ static void buildTL(const vector<Bm>& bin, int H, TL& out) {
73
+ int NN = N * N;
74
+ out.init(H, NN);
75
+ vector<char> g(NN);
76
+ for (int y = 0; y < N; y++)
77
+ for (int x = 0; x < N; x++) g[cell(x, y)] = board[y][x];
78
+ vector<int> fexp(NN, -1);
79
+ for (auto& f : flames) {
80
+ int c = cell(f[0], f[1]);
81
+ fexp[c] = max(fexp[c], f[2]);
82
+ }
83
+ vector<Bm> bs = bin;
84
+ vector<int> at(NN, -1);
85
+ vector<char> gone, hit;
86
+ vector<int> pending;
87
+ for (int k = 0; k < H; k++) {
88
+ int now = T + k;
89
+ if (now >= SHRINK && (now - SHRINK) % EVERY == 0) {
90
+ int layer = 1 + (now - SHRINK) / EVERY;
91
+ for (int y = 0; y < N; y++)
92
+ for (int x = 0; x < N; x++) {
93
+ if (min(min(x, y), min(N - 1 - x, N - 1 - y)) <= layer) {
94
+ int c = cell(x, y);
95
+ g[c] = '#';
96
+ fexp[c] = -1;
97
+ }
98
+ }
99
+ size_t w = 0;
100
+ for (size_t i = 0; i < bs.size(); i++)
101
+ if (g[cell(bs[i].x, bs[i].y)] != '#') bs[w++] = bs[i];
102
+ bs.resize(w);
103
+ }
104
+ for (int c = 0; c < NN; c++)
105
+ if (fexp[c] < now) fexp[c] = -1;
106
+ unsigned char* pb = &out.blk[(size_t)k * NN];
107
+ unsigned char* po = &out.occ[(size_t)k * NN];
108
+ unsigned char* pl = &out.leak[(size_t)k * NN];
109
+ fill(po, po + NN, 0);
110
+ for (int c = 0; c < NN; c++) {
111
+ char ch = g[c];
112
+ pb[c] = (ch == '.') ? 0 : 1;
113
+ pl[c] = (ch == '#') ? 1 : 0;
114
+ }
115
+ fill(at.begin(), at.end(), -1);
116
+ for (size_t i = 0; i < bs.size(); i++) {
117
+ int c = cell(bs[i].x, bs[i].y);
118
+ at[c] = (int)i;
119
+ po[c] = 1;
120
+ }
121
+ // explosion phase (single pre-explosion snapshot for crates and bombs)
122
+ pending.clear();
123
+ for (size_t i = 0; i < bs.size(); i++)
124
+ if (bs[i].at <= now || fexp[cell(bs[i].x, bs[i].y)] >= now) pending.push_back((int)i);
125
+ gone.assign(bs.size(), 0);
126
+ hit.assign(NN, 0);
127
+ vector<int> destroyed;
128
+ while (!pending.empty()) {
129
+ int i = pending.back();
130
+ pending.pop_back();
131
+ if (gone[i]) continue;
132
+ gone[i] = 1;
133
+ const Bm b = bs[i];
134
+ hit[cell(b.x, b.y)] = 1;
135
+ for (int d = 0; d < 4; d++) {
136
+ int x = b.x, y = b.y;
137
+ for (int r = 1; r <= RANGE; r++) {
138
+ x += DX[d]; y += DY[d];
139
+ if (x < 0 || y < 0 || x >= N || y >= N) break;
140
+ int c = cell(x, y);
141
+ if (g[c] == '#') break;
142
+ hit[c] = 1;
143
+ if (g[c] == '+') { destroyed.push_back(c); break; }
144
+ if (at[c] >= 0) { pending.push_back(at[c]); break; }
145
+ }
146
+ }
147
+ }
148
+ size_t w = 0;
149
+ for (size_t i = 0; i < bs.size(); i++)
150
+ if (!gone[i]) bs[w++] = bs[i];
151
+ bs.resize(w);
152
+ for (int c : destroyed) g[c] = '.';
153
+ for (int c = 0; c < NN; c++)
154
+ if (hit[c]) fexp[c] = max(fexp[c], now + FIRE - 1);
155
+ for (int c = 0; c < NN; c++)
156
+ if (fexp[c] >= now) pl[c] = 1;
157
+ }
158
+ }
159
+
160
+ // ------------------------------------------------------------- reachability
161
+ struct Reach {
162
+ int life = 0; // number of turns (T..T+life-1) that can be survived
163
+ int endCount = 0; // distinct cells reachable alive at the horizon end
164
+ int minCount = 0; // smallest reachable-set size along the way
165
+ };
166
+
167
+ static Reach survive(const TL& tl, int start, const vector<char>* eblk, int blockUntil) {
168
+ int NN = N * N;
169
+ Reach r;
170
+ vector<char> cur(NN, 0), nxt(NN, 0);
171
+ if (start < 0 || start >= NN || tl.leak[start]) return r;
172
+ cur[start] = 1;
173
+ r.life = 1;
174
+ r.minCount = 1;
175
+ for (int k = 1; k < tl.H; k++) {
176
+ fill(nxt.begin(), nxt.end(), 0);
177
+ const unsigned char* pb = &tl.blk[(size_t)k * NN];
178
+ const unsigned char* po = &tl.occ[(size_t)k * NN];
179
+ const unsigned char* pl = &tl.leak[(size_t)k * NN];
180
+ int cnt = 0;
181
+ for (int c = 0; c < NN; c++) {
182
+ if (!cur[c]) continue;
183
+ int x = CX(c), y = CY(c);
184
+ for (int d = 0; d < 5; d++) {
185
+ int nx = x + DX[d], ny = y + DY[d];
186
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
187
+ int b = cell(nx, ny);
188
+ if (b != c) {
189
+ if (pb[b] || po[b]) continue;
190
+ if (eblk && (k <= blockUntil) && (*eblk)[b]) continue;
191
+ }
192
+ if (pl[b]) continue;
193
+ if (!nxt[b]) { nxt[b] = 1; cnt++; }
194
+ }
195
+ }
196
+ if (!cnt) break;
197
+ cur.swap(nxt);
198
+ r.life = k + 1;
199
+ r.minCount = min(r.minCount, cnt);
200
+ r.endCount = cnt;
201
+ }
202
+ return r;
203
+ }
204
+
205
+ // ----------------------------------------------------------------- helpers
206
+ static int aliveCount() {
207
+ int c = 0;
208
+ for (auto& p : players) c += p.alive;
209
+ return c;
210
+ }
211
+
212
+ static double openness(int c, int rad) {
213
+ int x0 = CX(c), y0 = CY(c), cnt = 0;
214
+ for (int y = max(0, y0 - rad); y <= min(N - 1, y0 + rad); y++)
215
+ for (int x = max(0, x0 - rad); x <= min(N - 1, x0 + rad); x++)
216
+ if (board[y][x] == '.') cnt++;
217
+ return cnt;
218
+ }
219
+
220
+ // ---------------------------------------------------------------- decision
221
+ static bool DBG = false;
222
+ static vector<int> visitHist;
223
+
224
+ static pair<int, int> decide() {
225
+ auto t0 = chrono::steady_clock::now();
226
+ int NN = N * N;
227
+ int mx = players[ME].x, my = players[ME].y;
228
+ int myCell = cell(mx, my);
229
+ visitHist.push_back(myCell);
230
+ if (visitHist.size() > 40) visitHist.erase(visitHist.begin());
231
+
232
+ vector<char> eblk(NN, 0);
233
+ vector<int> enemies;
234
+ for (int i = 0; i < P; i++) {
235
+ if (i == ME || !players[i].alive) continue;
236
+ eblk[cell(players[i].x, players[i].y)] = 1;
237
+ enemies.push_back(i);
238
+ }
239
+
240
+ // ------- placement legality
241
+ int myBombs = 0;
242
+ bool bombUnderMe = false, shared = false;
243
+ for (auto& b : bombs) {
244
+ if (b.owner == ME) myBombs++;
245
+ if (b.x == mx && b.y == my) bombUnderMe = true;
246
+ }
247
+ for (int i = 0; i < P; i++)
248
+ if (i != ME && players[i].alive && players[i].x == mx && players[i].y == my) shared = true;
249
+ bool canPlace = (myBombs < CAP) && !bombUnderMe && !shared;
250
+
251
+ // Terrain-obeying target for the current turn. Enemy cells are not treated as
252
+ // hard blockers: standing still is scored separately, so a move into a cell a
253
+ // rival is vacating stays available when standing still means dying.
254
+ vector<char> occNow(NN, 0);
255
+ for (auto& b : bombs) occNow[cell(b.x, b.y)] = 1;
256
+ auto myTarget = [&](int d) {
257
+ int nx = mx + DX[d], ny = my + DY[d];
258
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N) return myCell;
259
+ if (board[ny][nx] != '.') return myCell;
260
+ int c = cell(nx, ny);
261
+ if (c != myCell && occNow[c]) return myCell;
262
+ return c;
263
+ };
264
+ // my own cell is always legal to hold (unless shrink, handled by timeline)
265
+
266
+ // ------- timelines per placement option
267
+ const int HP = 22; // pessimistic horizon
268
+ const int HO = 46; // optimistic horizon (shrink planning)
269
+ TL tlNoP, tlYesP, tlNoO, tlYesO;
270
+ vector<Bm> basePred = bombs;
271
+ for (int i : enemies) {
272
+ // Rivals bomb while closing in, so model the two most likely bomb sites:
273
+ // where they stand now, and the passable neighbour that gets closest to us.
274
+ int cnt = 0;
275
+ bool under = false;
276
+ for (auto& b : bombs) {
277
+ if (b.owner == i) cnt++;
278
+ if (b.x == players[i].x && b.y == players[i].y) under = true;
279
+ }
280
+ if (cnt < CAP && !under) basePred.push_back(Bm{i, players[i].x, players[i].y, T + 1 + FUSE});
281
+ int bx = players[i].x, by = players[i].y;
282
+ int bestd = abs(bx - mx) + abs(by - my), bestc = -1;
283
+ for (int d = 0; d < 4; d++) {
284
+ int nx = bx + DX[d], ny = by + DY[d];
285
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
286
+ if (board[ny][nx] != '.') continue;
287
+ int c = cell(nx, ny);
288
+ bool occ = false;
289
+ for (auto& b : bombs)
290
+ if (b.x == nx && b.y == ny) occ = true;
291
+ if (occ) continue;
292
+ int dist = abs(nx - mx) + abs(ny - my);
293
+ if (dist < bestd) { bestd = dist; bestc = c; }
294
+ }
295
+ if (bestc >= 0) basePred.push_back(Bm{i, CX(bestc), CY(bestc), T + 2 + FUSE});
296
+ }
297
+ buildTL(basePred, HP, tlNoP); // pessimistic: everyone may bomb immediately
298
+ buildTL(bombs, HO, tlNoO); // optimistic: current bombs only, long horizon
299
+ if (canPlace) {
300
+ vector<Bm> yes = bombs;
301
+ yes.push_back(Bm{ME, mx, my, T + FUSE});
302
+ vector<Bm> yesPred = basePred;
303
+ yesPred.push_back(Bm{ME, mx, my, T + FUSE});
304
+ buildTL(yesPred, HP, tlYesP);
305
+ buildTL(yes, HO, tlYesO);
306
+ }
307
+
308
+ // enemy baseline horizons (neutral timeline: current bombs only)
309
+ struct EnInfo { int baseLife, baseCnt, baseMin; };
310
+ vector<EnInfo> enBase(enemies.size());
311
+ for (size_t j = 0; j < enemies.size(); j++) {
312
+ int e = enemies[j];
313
+ Reach rr = survive(tlNoO, cell(players[e].x, players[e].y), &eblk, 0);
314
+ enBase[j] = {rr.life, rr.endCount, rr.minCount};
315
+ }
316
+
317
+ // ------- evaluate (placement, direction) pairs jointly
318
+ int curLayer = (T < SHRINK) ? 0 : 1 + (T - SHRINK) / EVERY;
319
+ int aliveNow = aliveCount();
320
+ // depth band: stay a couple of layers inside the current wall, deeper as it closes
321
+ int want = curLayer + (aliveNow > 4 ? 2 : 3);
322
+
323
+ double bestScore = -1e18;
324
+ int bestPlace = 0, bestD = 4;
325
+ for (int place = 0; place <= 1; place++) {
326
+ if (place && !canPlace) continue;
327
+ const TL& tp = place ? tlYesP : tlNoP;
328
+ const TL& to = place ? tlYesO : tlNoO;
329
+ // offensive value of this bomb (independent of my own destination)
330
+ double off = 0;
331
+ if (place) {
332
+ for (size_t j = 0; j < enemies.size(); j++) {
333
+ int ec = cell(players[enemies[j]].x, players[enemies[j]].y);
334
+ Reach rb = survive(to, ec, &eblk, 0);
335
+ if (rb.life == 0) continue; // already doomed by other bombs
336
+ int dLife = enBase[j].baseLife - rb.life;
337
+ int dMin = enBase[j].baseMin - rb.minCount;
338
+ int dCnt = enBase[j].baseCnt - rb.endCount;
339
+ if (rb.life <= 1) off += 700; // trapped outright by this bomb
340
+ off += 110.0 * max(0, dLife);
341
+ off += 26.0 * max(0, dMin);
342
+ off += 7.0 * max(0, dCnt);
343
+ // chain bonus: my bomb detonating an enemy bomb is a strong trap
344
+ for (auto& b : bombs)
345
+ if (b.owner != ME && (int)abs(b.x - mx) + (int)abs(b.y - my) <= RANGE + 1) off += 60;
346
+ }
347
+ off -= 2.0; // placement inertia
348
+ }
349
+ for (int d = 0; d < 5; d++) {
350
+ int dest = myTarget(d);
351
+ Reach rp = survive(tp, dest, &eblk, HP);
352
+ Reach ro = survive(to, dest, &eblk, 0);
353
+ double sc = 900.0 * rp.life + 25.0 * ro.life + 44.0 * min(6, rp.minCount) +
354
+ 3.0 * min(14, ro.endCount);
355
+ int e = edgeOf(dest);
356
+ sc -= 26.0 * abs(e - want);
357
+ sc += 1.6 * openness(dest, 2);
358
+ for (int i : enemies) {
359
+ int dist = abs(players[i].x - CX(dest)) + abs(players[i].y - CY(dest));
360
+ if (dist == 0) sc -= 500;
361
+ else if (dist == 1) sc -= 30;
362
+ else if (dist == 2) sc -= 13;
363
+ else if (dist == 3) sc -= 5;
364
+ }
365
+ int seen = 0;
366
+ for (int v : visitHist)
367
+ if (v == dest) seen++;
368
+ sc -= 1.5 * seen;
369
+ if (d == 4) sc -= 0.4;
370
+ if (dest == myCell && d != 4) sc -= 4; // requested a blocked move
371
+ sc += off;
372
+ if (DBG)
373
+ fprintf(stderr, "place=%d d=%c dest=(%d,%d) rp.life=%d rp.min=%d ro.life=%d edge=%d sc=%.1f off=%.1f\n",
374
+ place, DC[d], CX(dest), CY(dest), rp.life, rp.minCount, ro.life, e, sc, off);
375
+ if (sc > bestScore) { bestScore = sc; bestPlace = place; bestD = d; }
376
+ }
377
+ }
378
+ if (DBG) fprintf(stderr, " select d=%c place=%d compute=%.2fms\n", DC[bestD], bestPlace,
379
+ chrono::duration<double, milli>(chrono::steady_clock::now() - t0).count());
380
+ return {bestD, bestPlace};
381
+ }
382
+
383
+ // ------------------------------------------------------------------- input
384
+ static bool readState() {
385
+ string w;
386
+ if (!(cin >> w)) return false;
387
+ if (w != "TURN") return false;
388
+ cin >> T;
389
+ cin >> w; // BOARD
390
+ if (w != "BOARD") return false;
391
+ for (int y = 0; y < N; y++) cin >> board[y];
392
+ players.assign(P, Pl{});
393
+ for (int i = 0; i < P; i++) {
394
+ int id, x, y, a;
395
+ cin >> w >> id >> x >> y >> a;
396
+ players[id].x = x; players[id].y = y; players[id].alive = a;
397
+ }
398
+ int k;
399
+ cin >> w >> k; // BOMBS
400
+ bombs.clear();
401
+ for (int i = 0; i < k; i++) {
402
+ Bm b;
403
+ cin >> w >> b.owner >> b.x >> b.y >> b.at;
404
+ bombs.push_back(b);
405
+ }
406
+ cin >> w >> k; // FLAMES
407
+ flames.clear();
408
+ for (int i = 0; i < k; i++) {
409
+ array<int, 3> f;
410
+ cin >> w >> f[0] >> f[1] >> f[2];
411
+ flames.push_back(f);
412
+ }
413
+ // STATUS / SOURCES carry score bookkeeping this bot does not need; drain
414
+ // whatever follows so an added section cannot desynchronise the stream.
415
+ while (cin >> w)
416
+ if (w == "END") return true;
417
+ return false;
418
+ }
419
+
420
+ int main(int argc, char** argv) {
421
+ ios::sync_with_stdio(false);
422
+ cin.tie(nullptr);
423
+ string w;
424
+ if (!(cin >> w >> N >> P >> ME >> LIMIT >> FUSE >> RANGE >> CAP >> FIRE >> SHRINK >> EVERY)) return 0;
425
+ DBG = (argc > 1 && string(argv[1]) == "--dbg");
426
+ bool DUMP = (argc > 1 && string(argv[1]) == "--dump");
427
+ board.assign(N, string(N, '.'));
428
+ players.assign(P, Pl{});
429
+ while (readState()) {
430
+ if (DUMP) {
431
+ TL tl;
432
+ buildTL(bombs, 12, tl);
433
+ for (int k = 0; k < tl.H; k++) {
434
+ string a, b;
435
+ for (int c = 0; c < N * N; c++) {
436
+ a += ('0' + tl.leak[(size_t)k * N * N + c]);
437
+ b += ('0' + tl.occ[(size_t)k * N * N + c]);
438
+ }
439
+ fprintf(stderr, "TL %d %s %s\n", T + k, a.c_str(), b.c_str());
440
+ }
441
+ fflush(stderr);
442
+ }
443
+ auto ans = decide();
444
+ cout << T << ' ' << DC[ans.first] << ' ' << ans.second << '\n' << flush;
445
+ }
446
+ return 0;
447
+ }