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,836 @@
1
+ // Bomb Arena bot — survival-first exact simulation + escape-denial hunting.
2
+ // Strategy:
3
+ // * Exact deterministic forward simulation of the public rules engine
4
+ // (chains, flame-triggered early detonation, crate ray blocking, shrink,
5
+ // bomb cells blocking movement, flame expiry) over a 9-11 turn horizon.
6
+ // * Survival dominates scoring: time-expanded reachability with the first
7
+ // move forced; checked under three bomb scenarios (current bombs, nearest
8
+ // rival placing now, every rival placing now).
9
+ // * Offense = escape denial: after a hypothetical placement, each enemy's
10
+ // best-case reachable set is recomputed (my destination also blocks their
11
+ // escape via the engine's collision rule). Empty set = guaranteed kill.
12
+ // * Potential field + persistent goal for coherent positional play:
13
+ // early game opens crates and keeps distance; aggression rises as the
14
+ // circle shrinks / players drop, turning into corner-and-squeeze hunting.
15
+ // * Hard time guard: every phase checks a deadline and falls back to the
16
+ // best move found so far, so output is always valid and on time.
17
+ #include <cstdio>
18
+ #include <cstring>
19
+ #include <cstdlib>
20
+ #include <cmath>
21
+ #include <chrono>
22
+
23
+ typedef unsigned char u8;
24
+
25
+ static const int MAXN = 26, MAXC = 676, MAXH = 12, MAXB = 96, MAXP = 10;
26
+ static const int DX[5] = {0, 0, -1, 1, 0}, DY[5] = {-1, 1, 0, 0, 0};
27
+ static const char DS[6] = "UDLRS";
28
+
29
+ static int N, P, ME, LIMIT, FUSE, RANGE, CAP, FIRE, SHRINK, EVERY;
30
+ static int T, H, NN;
31
+ static char board[MAXN][MAXN];
32
+ static int pl_x[MAXP], pl_y[MAXP], pl_alive[MAXP];
33
+ struct Bomb { int owner, x, y, at; };
34
+ static Bomb bombs[MAXB];
35
+ static int nb;
36
+ static int flameIn[MAXC];
37
+
38
+ static inline int cellOf(int x, int y) { return y * N + x; }
39
+
40
+ // ---------------- fast input ----------------
41
+ // NOTE: fread() on a pipe blocks trying to fill the whole buffer; getchar()
42
+ // refills with a single read() call and returns as soon as data is available.
43
+ static inline int gc() { return getchar(); }
44
+ static inline bool tok(char* out) {
45
+ int c;
46
+ do { c = gc(); if (c == -1) return false; }
47
+ while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
48
+ int n = 0;
49
+ while (c != -1 && c != ' ' && c != '\n' && c != '\r' && c != '\t') {
50
+ if (n < 60) out[n++] = (char)c;
51
+ c = gc();
52
+ }
53
+ out[n] = 0;
54
+ return true;
55
+ }
56
+ static inline bool tokInt(int& v) {
57
+ char b[64];
58
+ if (!tok(b)) return false;
59
+ v = atoi(b);
60
+ return true;
61
+ }
62
+
63
+ // ---------------- timing ----------------
64
+ static long long deadlineNS = 0;
65
+ static inline long long nowNS() {
66
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
67
+ std::chrono::steady_clock::now().time_since_epoch())
68
+ .count();
69
+ }
70
+ static inline bool timeUp() { return nowNS() > deadlineNS; }
71
+
72
+ // ---------------- forward simulation ----------------
73
+ struct Scenario {
74
+ u8 moveOpen[MAXH][MAXC]; // '.' after this turn's shrink, before blast
75
+ u8 bombOcc[MAXH][MAXC]; // bomb present during this turn's move phase
76
+ u8 safeEnd[MAXH][MAXC]; // '.' after blast and not lethal at turn end
77
+ };
78
+ static Scenario SC[6];
79
+
80
+ static char simGrid[MAXC];
81
+ static int simExp[MAXC];
82
+ static Bomb simB[MAXB];
83
+ static int simAt[MAXC];
84
+ static u8 simGone[MAXB], simHit[MAXC];
85
+ static int qB[MAXB * 16];
86
+
87
+ static void simulate(Scenario& out, const Bomb* extras, int nextra) {
88
+ for (int y = 0; y < N; y++)
89
+ for (int x = 0; x < N; x++) simGrid[cellOf(x, y)] = board[y][x];
90
+ for (int c = 0; c < NN; c++) simExp[c] = flameIn[c];
91
+ int nb2 = 0;
92
+ for (int i = 0; i < nb && nb2 < MAXB; i++) simB[nb2++] = bombs[i];
93
+ for (int i = 0; i < nextra && nb2 < MAXB; i++) simB[nb2++] = extras[i];
94
+
95
+ for (int k = 0; k < H; k++) {
96
+ int tau = T + k;
97
+ int layer = (tau < SHRINK) ? 0 : 1 + (tau - SHRINK) / EVERY;
98
+ if (layer > 0) {
99
+ for (int y = 0; y < N; y++) {
100
+ int ry = (y < N - 1 - y) ? y : N - 1 - y;
101
+ if (ry > layer) continue;
102
+ for (int x = 0; x < N; x++) {
103
+ int rx = (x < N - 1 - x) ? x : N - 1 - x;
104
+ if ((rx < ry ? rx : ry) <= layer) {
105
+ int c = cellOf(x, y);
106
+ simGrid[c] = '#';
107
+ simExp[c] = -1;
108
+ }
109
+ }
110
+ }
111
+ int w = 0;
112
+ for (int i = 0; i < nb2; i++)
113
+ if (simGrid[cellOf(simB[i].x, simB[i].y)] != '#') simB[w++] = simB[i];
114
+ nb2 = w;
115
+ }
116
+ for (int c = 0; c < NN; c++)
117
+ if (simExp[c] >= 0 && simExp[c] < tau) simExp[c] = -1;
118
+
119
+ for (int c = 0; c < NN; c++) {
120
+ out.moveOpen[k][c] = (simGrid[c] == '.');
121
+ out.bombOcc[k][c] = 0;
122
+ simAt[c] = -1;
123
+ }
124
+ for (int i = 0; i < nb2; i++) {
125
+ int c = cellOf(simB[i].x, simB[i].y);
126
+ out.bombOcc[k][c] = 1;
127
+ simAt[c] = i;
128
+ }
129
+
130
+ memset(simGone, 0, nb2);
131
+ memset(simHit, 0, NN);
132
+ int qh = 0, qt = 0;
133
+ for (int i = 0; i < nb2; i++) {
134
+ int c = cellOf(simB[i].x, simB[i].y);
135
+ if (simB[i].at <= tau || simExp[c] >= tau) qB[qt++] = i;
136
+ }
137
+ while (qh < qt) {
138
+ int bi = qB[qh++];
139
+ if (simGone[bi]) continue;
140
+ simGone[bi] = 1;
141
+ Bomb b = simB[bi];
142
+ simHit[cellOf(b.x, b.y)] = 1;
143
+ for (int d = 0; d < 4; d++)
144
+ for (int r = 1; r <= RANGE; r++) {
145
+ int x = b.x + DX[d] * r, y = b.y + DY[d] * r;
146
+ if (x < 0 || y < 0 || x >= N || y >= N) break;
147
+ int c = cellOf(x, y);
148
+ if (simGrid[c] == '#') break;
149
+ simHit[c] = 1;
150
+ if (simGrid[c] == '+') break;
151
+ if (simAt[c] >= 0) {
152
+ if (!simGone[simAt[c]] && qt < MAXB * 16) qB[qt++] = simAt[c];
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ int w = 0;
158
+ for (int i = 0; i < nb2; i++)
159
+ if (!simGone[i]) simB[w++] = simB[i];
160
+ nb2 = w;
161
+ for (int c = 0; c < NN; c++)
162
+ if (simHit[c]) {
163
+ if (simGrid[c] == '+') simGrid[c] = '.';
164
+ int e = tau + FIRE - 1;
165
+ if (simExp[c] < e) simExp[c] = e;
166
+ }
167
+ for (int c = 0; c < NN; c++)
168
+ out.safeEnd[k][c] = (simGrid[c] == '.' && simExp[c] < tau);
169
+ }
170
+ }
171
+
172
+ // ---------------- reachability ----------------
173
+ static double potential[MAXC];
174
+ static u8 rCur[MAXC], rNxt[MAXC];
175
+ struct Reach { int life, count, count2; double util; };
176
+
177
+ static Reach reach(const Scenario& s, int start, int forced, int block) {
178
+ Reach R{0, 0, 0, -1e9};
179
+ memset(rCur, 0, NN);
180
+ if (start >= 0 && start < NN) rCur[start] = 1;
181
+ for (int k = 0; k < H; k++) {
182
+ for (int c = 0; c < NN; c++)
183
+ if (rCur[c] && !s.moveOpen[k][c]) rCur[c] = 0; // shrink death
184
+ memset(rNxt, 0, NN);
185
+ if (k == 0 && forced >= 0) {
186
+ if (rCur[start] && s.moveOpen[0][forced] &&
187
+ (forced == start || !s.bombOcc[0][forced]) && s.safeEnd[0][forced])
188
+ rNxt[forced] = 1;
189
+ } else {
190
+ for (int c = 0; c < NN; c++) {
191
+ if (!rCur[c]) continue;
192
+ int x = c % N, y = c / N;
193
+ for (int d = 0; d < 5; d++) {
194
+ int nx = x + DX[d], ny = y + DY[d], nc = c;
195
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N) {
196
+ int z = cellOf(nx, ny);
197
+ bool blockedByMe = (k == 0 && block >= 0 && z == block && z != c);
198
+ if (!blockedByMe && s.moveOpen[k][z] && (z == c || !s.bombOcc[k][z]))
199
+ nc = z;
200
+ }
201
+ if (s.safeEnd[k][nc]) rNxt[nc] = 1;
202
+ }
203
+ }
204
+ }
205
+ memcpy(rCur, rNxt, NN);
206
+ int cnt = 0;
207
+ double u = -1e9;
208
+ for (int c = 0; c < NN; c++)
209
+ if (rCur[c]) {
210
+ cnt++;
211
+ if (potential[c] > u) u = potential[c];
212
+ }
213
+ if (cnt == 0) break;
214
+ R.life = k + 1;
215
+ R.count = cnt;
216
+ R.util = u;
217
+ if (k == 1) R.count2 = cnt;
218
+ }
219
+ return R;
220
+ }
221
+
222
+ static u8 regCur[MAXC], regNxt[MAXC];
223
+ static void reachRegion2(const Scenario& s, int start, u8* out) {
224
+ memset(out, 0, NN);
225
+ memset(regCur, 0, NN);
226
+ if (start >= 0 && start < NN) regCur[start] = 1;
227
+ for (int k = 0; k < 2; k++) {
228
+ for (int c = 0; c < NN; c++)
229
+ if (regCur[c] && !s.moveOpen[k][c]) regCur[c] = 0;
230
+ memset(regNxt, 0, NN);
231
+ for (int c = 0; c < NN; c++) {
232
+ if (!regCur[c]) continue;
233
+ int x = c % N, y = c / N;
234
+ for (int d = 0; d < 5; d++) {
235
+ int nx = x + DX[d], ny = y + DY[d], nc = c;
236
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N) {
237
+ int z = cellOf(nx, ny);
238
+ if (s.moveOpen[k][z] && (z == c || !s.bombOcc[k][z])) nc = z;
239
+ }
240
+ if (s.safeEnd[k][nc]) regNxt[nc] = 1;
241
+ }
242
+ }
243
+ memcpy(regCur, regNxt, NN);
244
+ for (int c = 0; c < NN; c++)
245
+ if (regCur[c]) out[c] = 1;
246
+ }
247
+ }
248
+
249
+ // ---------------- potential field ----------------
250
+ static int baseCnt[MAXP], baseLife[MAXP];
251
+ static u8 nearReg[MAXP][MAXC];
252
+ static double aggr = 0;
253
+
254
+ static int crateRay(int x, int y) {
255
+ int v = 0;
256
+ for (int d = 0; d < 4; d++)
257
+ for (int r = 1; r <= RANGE; r++) {
258
+ int nx = x + DX[d] * r, ny = y + DY[d] * r;
259
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N) break;
260
+ char g = board[ny][nx];
261
+ if (g == '#') break;
262
+ if (g == '+') { v++; break; }
263
+ if (g == '.') {
264
+ bool bombThere = false;
265
+ for (int i = 0; i < nb; i++)
266
+ if (bombs[i].x == nx && bombs[i].y == ny) { bombThere = true; break; }
267
+ if (bombThere) break;
268
+ }
269
+ }
270
+ return v;
271
+ }
272
+
273
+ static void make_potential() {
274
+ static u8 done[MAXC];
275
+ for (int c = 0; c < NN; c++) { potential[c] = -1e6; done[c] = 0; }
276
+ for (int y = 0; y < N; y++)
277
+ for (int x = 0; x < N; x++) {
278
+ if (board[y][x] != '.') continue;
279
+ int c = cellOf(x, y);
280
+ int edge = x;
281
+ if (y < edge) edge = y;
282
+ if (N - 1 - x < edge) edge = N - 1 - x;
283
+ if (N - 1 - y < edge) edge = N - 1 - y;
284
+ double v = 1.3 * crateRay(x, y);
285
+ int openN = 0;
286
+ for (int d = 0; d < 4; d++) {
287
+ int nx = x + DX[d], ny = y + DY[d];
288
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N && board[ny][nx] == '.') openN++;
289
+ }
290
+ v += 0.4 * openN;
291
+ // hunting spots: blast cells overlapping a cornered enemy's region
292
+ for (int i = 0; i < P; i++) {
293
+ if (i == ME || !pl_alive[i] || baseCnt[i] < 1 || baseCnt[i] > 8) continue;
294
+ int overlap = 0;
295
+ if (nearReg[i][c]) overlap++;
296
+ for (int dd = 0; dd < 4; dd++)
297
+ for (int r = 1; r <= RANGE; r++) {
298
+ int nx = x + DX[dd] * r, ny = y + DY[dd] * r;
299
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N) break;
300
+ char g = board[ny][nx];
301
+ if (g == '#') break;
302
+ if (nearReg[i][cellOf(nx, ny)]) overlap++;
303
+ if (g == '+') break;
304
+ }
305
+ double add = aggr * 3.0 * overlap / baseCnt[i];
306
+ if (add > 5.0) add = 5.0;
307
+ v += add;
308
+ }
309
+ // enemy distance shaping
310
+ int dmin = 100;
311
+ for (int i = 0; i < P; i++)
312
+ if (i != ME && pl_alive[i]) {
313
+ int dd = abs(pl_x[i] - x) + abs(pl_y[i] - y);
314
+ if (dd < dmin) dmin = dd;
315
+ }
316
+ if (dmin < 100) {
317
+ v += (1.0 - aggr) * (dmin > 6 ? 3.0 : 0.5 * dmin);
318
+ if (dmin <= 5) v += aggr * 0.9 * (6 - dmin);
319
+ else v -= aggr * 0.3 * (dmin > 13 ? 8 : dmin - 5);
320
+ }
321
+ // shrink safety
322
+ int until = SHRINK + (edge - 1) * EVERY - T;
323
+ if (until < 8) v -= 40;
324
+ else if (until < 20) v -= 10;
325
+ else if (until < 45) v -= 2;
326
+ potential[c] = v;
327
+ }
328
+ // distance transform (max-propagation with 0.8 per step)
329
+ for (int iter = 0; iter < NN; iter++) {
330
+ int best = -1;
331
+ double bv = -1e9;
332
+ for (int c = 0; c < NN; c++)
333
+ if (!done[c] && potential[c] > bv) { bv = potential[c]; best = c; }
334
+ if (best < 0 || bv <= -1e5) break;
335
+ done[best] = 1;
336
+ int x = best % N, y = best / N;
337
+ for (int d = 0; d < 4; d++) {
338
+ int nx = x + DX[d], ny = y + DY[d];
339
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N || board[ny][nx] != '.') continue;
340
+ int nc = cellOf(nx, ny);
341
+ if (bv - 0.8 > potential[nc]) potential[nc] = bv - 0.8;
342
+ }
343
+ }
344
+ }
345
+
346
+ // ---------------- goal system ----------------
347
+ static int goal = -1, goalTurn = -1000;
348
+ static int distMe[MAXC], distGoal[MAXC];
349
+ static int qCells[MAXC];
350
+ static int recent[40];
351
+ static int recentN = 0;
352
+ static int regionSize = 0;
353
+
354
+ static void bfsDist(int start, int* dist) {
355
+ for (int c = 0; c < NN; c++) dist[c] = 1000000;
356
+ if (start < 0 || board[start / N][start % N] != '.') return;
357
+ int qh = 0, qt = 0;
358
+ dist[start] = 0;
359
+ qCells[qt++] = start;
360
+ while (qh < qt) {
361
+ int c = qCells[qh++];
362
+ int x = c % N, y = c / N;
363
+ for (int d = 0; d < 4; d++) {
364
+ int nx = x + DX[d], ny = y + DY[d];
365
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N || board[ny][nx] != '.') continue;
366
+ int z = cellOf(nx, ny);
367
+ if (dist[z] > dist[c] + 1) { dist[z] = dist[c] + 1; qCells[qt++] = z; }
368
+ }
369
+ }
370
+ }
371
+
372
+ static double visits(int c) {
373
+ double s = 0;
374
+ for (int k = 0; k < recentN; k++)
375
+ if (recent[k] == c) s += 1.0 / (1.0 + 0.15 * (recentN - 1 - k));
376
+ return s;
377
+ }
378
+
379
+ static void update_goal() {
380
+ int me = cellOf(pl_x[ME], pl_y[ME]);
381
+ bfsDist(me, distMe);
382
+ regionSize = 0;
383
+ for (int c = 0; c < NN; c++)
384
+ if (distMe[c] < 1000000) regionSize++;
385
+ int layer = (T < SHRINK) ? 0 : 1 + (T - SHRINK) / EVERY;
386
+ bool bad = goal < 0 || board[goal / N][goal % N] != '.' || distMe[goal] >= 1000000 ||
387
+ T - goalTurn >= 12 || goal == me;
388
+ if (!bad) {
389
+ int gx = goal % N, gy = goal / N;
390
+ int e = gx;
391
+ if (gy < e) e = gy;
392
+ if (N - 1 - gx < e) e = N - 1 - gx;
393
+ if (N - 1 - gy < e) e = N - 1 - gy;
394
+ if (e <= layer + 1) bad = true;
395
+ }
396
+ if (bad) {
397
+ goal = -1;
398
+ double best = -1e18;
399
+ for (int c = 0; c < NN; c++) {
400
+ if (board[c / N][c % N] != '.' || distMe[c] >= 1000000) continue;
401
+ double v = potential[c] - 0.65 * distMe[c] - 0.9 * visits(c);
402
+ if (v > best) { best = v; goal = c; }
403
+ }
404
+ goalTurn = T;
405
+ }
406
+ bfsDist(goal < 0 ? me : goal, distGoal);
407
+ }
408
+
409
+ // ---------------- enemy move model & destination prediction ----------------
410
+ static int assumeDir[MAXP];
411
+ static int stayLifeE[MAXP];
412
+ static int threatDist[MAXC];
413
+
414
+ static void modelEnemies(const Scenario& s0) {
415
+ // threat cells: bombs about to explode, active flames
416
+ int thr[MAXC], nt = 0;
417
+ for (int i = 0; i < nb; i++)
418
+ if (bombs[i].at <= T + 2 && nt < MAXC) thr[nt++] = cellOf(bombs[i].x, bombs[i].y);
419
+ for (int c = 0; c < NN; c++)
420
+ if (flameIn[c] >= T && nt < MAXC) thr[nt++] = c;
421
+ for (int c = 0; c < NN; c++) {
422
+ threatDist[c] = 1000;
423
+ for (int i = 0; i < nt; i++) {
424
+ int d = abs(c % N - thr[i] % N) + abs(c / N - thr[i] / N);
425
+ if (d < threatDist[c]) threatDist[c] = d;
426
+ }
427
+ }
428
+ for (int i = 0; i < P; i++) {
429
+ assumeDir[i] = 4;
430
+ if (i == ME || !pl_alive[i]) continue;
431
+ int c = cellOf(pl_x[i], pl_y[i]);
432
+ // An enemy whose cell becomes unsafe within a few turns will move NOW
433
+ // (strong bots relocate early); assuming "stay" there wrongly blocks
434
+ // our own escape through their cell.
435
+ int stayLife = 0;
436
+ while (stayLife < H && s0.safeEnd[stayLife][c]) stayLife++;
437
+ stayLifeE[i] = stayLife;
438
+ bool danger = stayLife <= 3;
439
+ if (!danger) { assumeDir[i] = 4; continue; }
440
+ int bestD = 4, bestV = -1 << 30;
441
+ for (int d = 0; d < 5; d++) {
442
+ int nx = pl_x[i] + DX[d], ny = pl_y[i] + DY[d], nc = c;
443
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N) {
444
+ int z = cellOf(nx, ny);
445
+ if (s0.moveOpen[0][z] && (z == c || !s0.bombOcc[0][z])) nc = z;
446
+ }
447
+ if (!s0.safeEnd[0][nc]) continue;
448
+ int v = threatDist[nc] * 2 + (nc != c ? 3 : 0);
449
+ if (v > bestV) { bestV = v; bestD = d; }
450
+ }
451
+ assumeDir[i] = bestD; // 4 if no safe option (doomed: assume stay)
452
+ }
453
+ }
454
+
455
+ static int predictDest(int myDir, const Scenario& s) {
456
+ int orig[MAXP], targ[MAXP], res[MAXP], n = 0, myIdx = 0;
457
+ for (int i = 0; i < P; i++) {
458
+ if (!pl_alive[i]) continue;
459
+ int o = cellOf(pl_x[i], pl_y[i]);
460
+ int d = (i == ME) ? myDir : assumeDir[i];
461
+ int nx = pl_x[i] + DX[d], ny = pl_y[i] + DY[d], t = o;
462
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N) {
463
+ int z = cellOf(nx, ny);
464
+ if (s.moveOpen[0][z] && (z == o || !s.bombOcc[0][z])) t = z;
465
+ }
466
+ orig[n] = o;
467
+ targ[n] = t;
468
+ if (i == ME) myIdx = n;
469
+ n++;
470
+ }
471
+ for (int i = 0; i < n; i++) res[i] = targ[i];
472
+ for (int i = 0; i < n; i++) {
473
+ int cnt = 0;
474
+ for (int j = 0; j < n; j++)
475
+ if (targ[j] == targ[i]) cnt++;
476
+ if (cnt > 1) res[i] = orig[i];
477
+ }
478
+ bool changed = true;
479
+ while (changed) {
480
+ changed = false;
481
+ for (int i = 0; i < n; i++) {
482
+ if (res[i] == orig[i]) continue;
483
+ for (int j = 0; j < n; j++)
484
+ if (res[j] == orig[j] && orig[j] == res[i]) {
485
+ res[i] = orig[i];
486
+ changed = true;
487
+ break;
488
+ }
489
+ }
490
+ }
491
+ return res[myIdx];
492
+ }
493
+
494
+ // ---------------- decision ----------------
495
+ static int blast_value(int x, int y) {
496
+ int v = 0;
497
+ for (int d = 0; d < 4; d++)
498
+ for (int r = 1; r <= RANGE; r++) {
499
+ int nx = x + DX[d] * r, ny = y + DY[d] * r;
500
+ if (nx < 0 || ny < 0 || nx >= N || ny >= N || board[ny][nx] == '#') break;
501
+ if (board[ny][nx] == '+') { v += 3; break; }
502
+ bool bombThere = false;
503
+ for (int i = 0; i < nb; i++)
504
+ if (bombs[i].x == nx && bombs[i].y == ny) { bombThere = true; break; }
505
+ if (bombThere) break;
506
+ }
507
+ return v;
508
+ }
509
+
510
+ static int decide() {
511
+ int meCell = cellOf(pl_x[ME], pl_y[ME]);
512
+ int aliveCnt = 0;
513
+ for (int i = 0; i < P; i++)
514
+ if (pl_alive[i]) aliveCnt++;
515
+ H = (aliveCnt <= 4) ? 11 : 9;
516
+ if (H > LIMIT - T) H = LIMIT - T;
517
+ if (H > MAXH) H = MAXH;
518
+ if (H < 1) H = 1;
519
+
520
+ simulate(SC[0], nullptr, 0);
521
+ if (timeUp()) return 4;
522
+
523
+ // enemy baseline reach & near regions
524
+ aggr = 1.15 - 0.13 * (aliveCnt - 1) + (T >= SHRINK - 50 ? 0.3 : 0.0);
525
+ for (int i = 0; i < P; i++) {
526
+ baseCnt[i] = 0;
527
+ baseLife[i] = 0;
528
+ memset(nearReg[i], 0, NN);
529
+ if (i == ME || !pl_alive[i]) continue;
530
+ Reach r = reach(SC[0], cellOf(pl_x[i], pl_y[i]), -1, -1);
531
+ baseCnt[i] = r.count;
532
+ baseLife[i] = r.life;
533
+ if (r.count > 0 && r.count <= 8) aggr += 0.1;
534
+ reachRegion2(SC[0], cellOf(pl_x[i], pl_y[i]), nearReg[i]);
535
+ }
536
+ if (aggr > 1.0) aggr = 1.0;
537
+ if (aggr < 0.0) aggr = 0.0;
538
+
539
+ make_potential();
540
+ update_goal();
541
+ modelEnemies(SC[0]);
542
+ if (timeUp()) return 4;
543
+
544
+ // placement eligibility
545
+ int myBombs = 0;
546
+ bool cellFree = true;
547
+ for (int i = 0; i < nb; i++) {
548
+ if (bombs[i].owner == ME) myBombs++;
549
+ if (cellOf(bombs[i].x, bombs[i].y) == meCell) cellFree = false;
550
+ }
551
+ bool placeOK = myBombs < CAP && cellFree;
552
+ bool myBombHere = false;
553
+ for (int i = 0; i < nb; i++)
554
+ if (bombs[i].owner == ME && cellOf(bombs[i].x, bombs[i].y) == meCell) myBombHere = true;
555
+ Bomb mine{ME, pl_x[ME], pl_y[ME], T + FUSE};
556
+
557
+ // threat: nearest eligible rival; all-place paranoia scenario
558
+ int threat = -1, threatD = 1000, nAll = 0;
559
+ Bomb allB[MAXP];
560
+ for (int i = 0; i < P; i++) {
561
+ if (i == ME || !pl_alive[i]) continue;
562
+ int cnt = 0;
563
+ bool onBomb = false;
564
+ for (int j = 0; j < nb; j++) {
565
+ if (bombs[j].owner == i) cnt++;
566
+ if (cellOf(bombs[j].x, bombs[j].y) == cellOf(pl_x[i], pl_y[i])) onBomb = true;
567
+ }
568
+ if (cnt >= CAP || onBomb) continue;
569
+ Bomb b{i, pl_x[i], pl_y[i], T + FUSE};
570
+ allB[nAll++] = b;
571
+ int d = abs(pl_x[i] - pl_x[ME]) + abs(pl_y[i] - pl_y[ME]);
572
+ if (d <= 8 && d < threatD) { threatD = d; threat = i; }
573
+ }
574
+
575
+ Scenario *Sb = &SC[0], *Sm = &SC[1], *St = &SC[2], *Smt = &SC[3], *Sa = &SC[4], *Smat = &SC[5];
576
+ if (placeOK) {
577
+ simulate(SC[1], &mine, 1);
578
+ } else {
579
+ Sm = Sb;
580
+ }
581
+ if (threat >= 0) {
582
+ Bomb tb{threat, pl_x[threat], pl_y[threat], T + FUSE};
583
+ simulate(SC[2], &tb, 1);
584
+ if (placeOK) {
585
+ Bomb both[2] = {mine, tb};
586
+ simulate(SC[3], both, 2);
587
+ } else {
588
+ Smt = St;
589
+ }
590
+ } else {
591
+ St = Sb;
592
+ Smt = Sm;
593
+ }
594
+ if (nAll > 0) {
595
+ simulate(SC[4], allB, nAll);
596
+ if (placeOK) {
597
+ Bomb allMine[MAXP + 1];
598
+ allMine[0] = mine;
599
+ for (int i = 0; i < nAll; i++) allMine[i + 1] = allB[i];
600
+ simulate(SC[5], allMine, nAll + 1);
601
+ } else {
602
+ Smat = Sa;
603
+ }
604
+ } else {
605
+ Sa = Sb;
606
+ Smat = Sm;
607
+ }
608
+ if (timeUp()) return 4;
609
+
610
+ // per-enemy denial baseline under my placement (no body block)
611
+ int scenCnt[MAXP];
612
+ for (int i = 0; i < P; i++) {
613
+ scenCnt[i] = baseCnt[i];
614
+ if (i == ME || !pl_alive[i] || !placeOK) continue;
615
+ int d = abs(pl_x[i] - pl_x[ME]) + abs(pl_y[i] - pl_y[ME]);
616
+ if (d <= 10) scenCnt[i] = reach(*Sm, cellOf(pl_x[i], pl_y[i]), -1, -1).count;
617
+ }
618
+
619
+ // quick fallback: safest immediate move by potential
620
+ int fbD = 4;
621
+ double fbV = -1e30;
622
+ for (int d = 0; d < 5; d++) {
623
+ int nx = pl_x[ME] + DX[d], ny = pl_y[ME] + DY[d], nc = meCell;
624
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N) {
625
+ int z = cellOf(nx, ny);
626
+ if (SC[0].moveOpen[0][z] && (z == meCell || !SC[0].bombOcc[0][z])) nc = z;
627
+ }
628
+ if (!SC[0].safeEnd[0][nc]) continue;
629
+ double v = potential[nc] - (nc == meCell ? 0.5 : 0);
630
+ if (v > fbV) { fbV = v; fbD = d; }
631
+ }
632
+
633
+ int bestAct = fbD, bestPlace = 0, evaluated = 0;
634
+ double bestScore = -1e30;
635
+ for (int place = 0; place <= 1; place++) {
636
+ if (place && !placeOK) continue;
637
+ const Scenario& scen = place ? *Sm : *Sb;
638
+ const Scenario& cautS = place ? *Smt : *St;
639
+ const Scenario& parS = place ? *Smat : *Sa;
640
+ for (int d = 0; d < 5; d++) {
641
+ if (timeUp()) goto done;
642
+ int destPred = predictDest(d, scen);
643
+ // raw terrain target ignoring player collisions
644
+ int terrT = meCell;
645
+ {
646
+ int nx = pl_x[ME] + DX[d], ny = pl_y[ME] + DY[d];
647
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N) {
648
+ int z = cellOf(nx, ny);
649
+ if (scen.moveOpen[0][z] && (z == meCell || !scen.bombOcc[0][z])) terrT = z;
650
+ }
651
+ }
652
+ Reach own = reach(scen, meCell, destPred, -1);
653
+ bool hedged = false;
654
+ double hedgePen = 0;
655
+ // Free-option hedge: if an enemy assumed to stay blocks terrT, the
656
+ // blocked outcome equals standing still, while the swap outcome can
657
+ // save us. Enemies whose cell turns unsafe soon will relocate, so
658
+ // take the better branch with a small uncertainty penalty.
659
+ if (destPred != terrT && terrT != meCell && d != 4) {
660
+ for (int i = 0; i < P; i++)
661
+ if (i != ME && pl_alive[i] && cellOf(pl_x[i], pl_y[i]) == terrT) {
662
+ if (stayLifeE[i] <= 6) {
663
+ Reach sw = reach(scen, meCell, terrT, -1);
664
+ if (sw.life > own.life) {
665
+ own = sw;
666
+ destPred = terrT;
667
+ hedged = true;
668
+ hedgePen = 4.0;
669
+ }
670
+ }
671
+ break;
672
+ }
673
+ }
674
+ double score = own.life * 10000.0 - hedgePen;
675
+ if (own.count > 0) score += 0.25 * own.util + 1.1 * log(1.0 + own.count);
676
+ // anti-pocket: few reachable cells next turn = trap-prone
677
+ if (own.life >= 2) {
678
+ if (own.count2 <= 1) score -= 6.0;
679
+ else if (own.count2 == 2) score -= 2.0;
680
+ else if (own.count2 == 3) score -= 0.8;
681
+ }
682
+ // never stand on a burning fuse: leaving now buys a turn of slack;
683
+ // "stay and flee later" dies when a rival plugs the corridor.
684
+ if (destPred == meCell && (place == 1 || myBombHere)) score -= 15.0;
685
+
686
+ int destC = predictDest(d, cautS);
687
+ Reach caut = reach(cautS, meCell, destC, -1);
688
+ if (caut.life == 0 && own.life > 0) score -= 35 + 5 * own.life;
689
+ else if (caut.life < own.life) score -= 3.0 * (own.life - caut.life);
690
+
691
+ int destP = predictDest(d, parS);
692
+ Reach par = reach(parS, meCell, destP, -1);
693
+ if (par.life == 0 && own.life > 0) score -= 18 + 3 * own.life;
694
+ else if (par.life < own.life) score -= 1.5 * (own.life - par.life);
695
+
696
+ // swap risk: destination occupied by an enemy assumed to move away
697
+ if (!hedged) {
698
+ int nx = pl_x[ME] + DX[d], ny = pl_y[ME] + DY[d];
699
+ if (nx >= 0 && ny >= 0 && nx < N && ny < N) {
700
+ int z = cellOf(nx, ny);
701
+ if (destPred == z && z != meCell) {
702
+ for (int i = 0; i < P; i++)
703
+ if (i != ME && pl_alive[i] && cellOf(pl_x[i], pl_y[i]) == z) {
704
+ Reach stayR = reach(scen, meCell, meCell, -1);
705
+ if (stayR.life < own.life) score -= 12.0 * (own.life - stayR.life);
706
+ break;
707
+ }
708
+ }
709
+ }
710
+ }
711
+
712
+ // denial / body block
713
+ double den = 0;
714
+ if (place) {
715
+ den += 0.7 * blast_value(pl_x[ME], pl_y[ME]) - 2.2;
716
+ if (regionSize < 10) den += 0.8 * (10 - regionSize);
717
+ }
718
+ for (int i = 0; i < P; i++) {
719
+ if (i == ME || !pl_alive[i]) continue;
720
+ int base = baseCnt[i];
721
+ if (base <= 0) continue;
722
+ int ec = cellOf(pl_x[i], pl_y[i]);
723
+ int dd = abs(pl_x[i] - pl_x[ME]) + abs(pl_y[i] - pl_y[ME]);
724
+ if (dd > 10 && abs(ec % N - destPred % N) + abs(ec / N - destPred / N) > 2)
725
+ continue;
726
+ int sc = place ? scenCnt[i] : baseCnt[i];
727
+ if (abs(ec % N - destPred % N) + abs(ec / N - destPred / N) <= 2)
728
+ sc = reach(scen, ec, -1, destPred).count;
729
+ if (sc == 0) den += 130;
730
+ else {
731
+ double ratio = 1.0 - (double)sc / base;
732
+ if (ratio > 0) den += 5.0 * ratio;
733
+ if (sc <= 3) den += 6.0 * (4 - sc);
734
+ }
735
+ }
736
+ score += den;
737
+
738
+ int gd = distGoal[destPred];
739
+ if (gd > 1000000) gd = 60;
740
+ if (gd > 20) gd = 20;
741
+ score -= 1.3 * gd + 1.8 * visits(destPred);
742
+ if (destPred == meCell) score -= 0.6;
743
+ score -= 0.002 * ((d + T) % 5);
744
+
745
+ if (score > bestScore) {
746
+ bestScore = score;
747
+ bestAct = d;
748
+ bestPlace = place;
749
+ evaluated = 1;
750
+ }
751
+ }
752
+ }
753
+ done:
754
+ if (!evaluated) return fbD; // place stays 0
755
+ if (bestPlace) goal = -1;
756
+ return bestAct + 10 * bestPlace;
757
+ }
758
+
759
+ // ---------------- main ----------------
760
+ int main() {
761
+ char w[64];
762
+ if (!tok(w) || strcmp(w, "INIT") != 0) return 0;
763
+ if (!tokInt(N) || !tokInt(P) || !tokInt(ME) || !tokInt(LIMIT) || !tokInt(FUSE) ||
764
+ !tokInt(RANGE) || !tokInt(CAP) || !tokInt(FIRE) || !tokInt(SHRINK) || !tokInt(EVERY))
765
+ return 0;
766
+ if (N > MAXN - 1) N = MAXN - 1;
767
+ if (P > MAXP) P = MAXP;
768
+ NN = N * N;
769
+ goal = -1;
770
+ goalTurn = -1000;
771
+ recentN = 0;
772
+
773
+ while (true) {
774
+ if (!tok(w)) break;
775
+ if (strcmp(w, "TURN") != 0) break;
776
+ if (!tokInt(T)) break;
777
+ deadlineNS = nowNS() + (T == 0 ? 900LL : 34LL) * 1000000LL;
778
+ bool ok = true;
779
+ if (!tok(w) || strcmp(w, "BOARD") != 0) break;
780
+ for (int y = 0; y < N; y++) {
781
+ if (!tok(w)) { ok = false; break; }
782
+ strncpy(board[y], w, MAXN - 1);
783
+ board[y][N] = 0;
784
+ }
785
+ for (int i = 0; i < P && ok; i++) {
786
+ int id;
787
+ ok = tok(w) && tokInt(id) && tokInt(pl_x[id]) && tokInt(pl_y[id]) && tokInt(pl_alive[id]);
788
+ }
789
+ int k;
790
+ if (ok) ok = tok(w) && tokInt(k);
791
+ nb = 0;
792
+ for (int i = 0; i < k && ok; i++) {
793
+ Bomb b;
794
+ ok = tok(w) && tokInt(b.owner) && tokInt(b.x) && tokInt(b.y) && tokInt(b.at);
795
+ if (nb < MAXB) bombs[nb++] = b;
796
+ }
797
+ for (int c = 0; c < NN; c++) flameIn[c] = -1;
798
+ if (ok) ok = tok(w) && tokInt(k);
799
+ for (int i = 0; i < k && ok; i++) {
800
+ int x, y, e;
801
+ ok = tok(w) && tokInt(x) && tokInt(y) && tokInt(e);
802
+ if (x >= 0 && y >= 0 && x < N && y < N) flameIn[cellOf(x, y)] = e;
803
+ }
804
+ if (ok) ok = tok(w) && tokInt(k); // STATUS
805
+ for (int i = 0; i < k && ok; i++) {
806
+ int a, b2, c2, d2;
807
+ ok = tok(w) && tokInt(a) && tokInt(b2) && tokInt(c2) && tokInt(d2);
808
+ }
809
+ if (ok) ok = tok(w) && tokInt(k); // SOURCES
810
+ for (int i = 0; i < k && ok; i++) {
811
+ int a, b2, c2, d2;
812
+ ok = tok(w) && tokInt(a) && tokInt(b2) && tokInt(c2) && tokInt(d2);
813
+ }
814
+ if (ok) ok = tok(w) && strcmp(w, "END") == 0;
815
+ if (!ok) break;
816
+
817
+ int act = 4, place = 0;
818
+ if (pl_alive[ME]) {
819
+ int r = decide();
820
+ if (r >= 10) { act = r - 10; place = 1; }
821
+ else act = r;
822
+ }
823
+ // remember position for anti-oscillation
824
+ if (recentN >= 32) {
825
+ memmove(recent, recent + 1, (recentN - 1) * sizeof(int));
826
+ recentN--;
827
+ }
828
+ recent[recentN++] = cellOf(pl_x[ME], pl_y[ME]);
829
+
830
+ char out[64];
831
+ int len = snprintf(out, sizeof(out), "%d %c %d\n", T, DS[act], place);
832
+ fwrite(out, 1, len, stdout);
833
+ fflush(stdout);
834
+ }
835
+ return 0;
836
+ }