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,241 @@
1
+ // Final entry: coordinated opening supply routes, marginal terrain-clearing
2
+ // value, selective projectile pressure, and joint attack/defense allocation.
3
+ // Exact simultaneous-action matrices with three-turn tactical rollouts;
4
+ // CPU-budget guard retains a legal one-turn fallback.
5
+ #include "tank.hpp"
6
+ #include <algorithm>
7
+ #include <array>
8
+ #include <cmath>
9
+ #include <queue>
10
+ #include <vector>
11
+ #include <cstdio>
12
+ using namespace tank;
13
+ namespace ai {
14
+ constexpr float INF=10000;
15
+ struct Context { float field[6][CELLS]; float grad[6]; float attack[2][2][CELLS]; float sd[2][MAX_SUPPLY][CELLS]; float ed[6][CELLS]; int occ[CELLS]; float wallval[CELLS]; int walls[CELLS],nw; uint64_t wh; int me; } ctx;
16
+ int hist[6][CELLS];int opening[6];
17
+ unsigned rng=7123671;
18
+ unsigned rnd(){rng^=rng<<13;rng^=rng>>17;rng^=rng<<5;return rng;}
19
+ int md(int a,int b){return std::abs(cell_x(a)-cell_x(b))+std::abs(cell_y(a)-cell_y(b));}
20
+ void dijkstra(const State&s,float* d,bool steel,float speed){
21
+ using P=std::pair<float,int>;std::priority_queue<P,std::vector<P>,std::greater<P>>q;
22
+ for(int y=0;y<s.P.size;y++)for(int x=0;x<s.P.size;x++){int c=cell_of(x,y);if(d[c]<INF)q.push({d[c],c});}
23
+ while(!q.empty()){auto [v,c]=q.top();q.pop();if(v>d[c]+.001)continue;
24
+ int gc=s.grid[c];float cost=1/speed+(gc==BRICK?1.8f:gc==STEEL?2.0f:0);
25
+ for(int k=0;k<4;k++){int n=c+DIR_DELTA[k],g=s.grid[n];if(g!=EMPTY&&g!=BRICK&&!(g==STEEL&&steel))continue;
26
+ float nv=v+cost;if(nv<d[n]){d[n]=nv;q.push({nv,n});}}
27
+ }
28
+ }
29
+ void setup(const State&s,int me){
30
+ ctx.me=me;ctx.nw=0;ctx.wh=s.wall_hash;std::fill(ctx.occ,ctx.occ+CELLS,-1);for(int i=0;i<6;i++)if(s.tank[i].alive)ctx.occ[s.tank[i].pos]=i;
31
+ for(int seat=0;seat<2;seat++)for(int st=0;st<2;st++){
32
+ float* d=ctx.attack[seat][st];std::fill(d,d+CELLS,INF);
33
+ int base=s.base_pos[1-seat];
34
+ for(int dir=0;dir<4;dir++){float cost=0;int len=0;for(int c=base+DIR_DELTA[dir];s.grid[c]!=OUTSIDE;c+=DIR_DELTA[dir]){
35
+ int g=s.grid[c];if(g==BASE0||g==BASE1||(g==STEEL&&!st))break;len++;cost+=(g==BRICK||g==STEEL)?1.9f:0;
36
+ if(g!=WATER)d[c]=cost+len*.75f;
37
+ int blocker=ctx.occ[c];if(blocker>=0)cost+=(blocker/3==seat?2.0f:6.0f);}}
38
+ dijkstra(s,d,st,1);
39
+ }
40
+ for(int st=0;st<2;st++)for(int k=0;k<s.n_supply;k++){float*d=ctx.sd[st][k];std::fill(d,d+CELLS,INF);d[s.supply[k]]=0;dijkstra(s,d,st,1);}
41
+
42
+ if(s.turn==0){for(int seat=0;seat<2;seat++){
43
+ float best=1e9;for(int a=0;a<3;a++)for(int b=0;b<3;b++)for(int c=0;c<3;c++)if(a!=b&&a!=c&&b!=c){
44
+ int z[3]={a,b,c};float sum=0,mx=0;
45
+ for(int t=0;t<3;t++){float d=ctx.sd[0][z[t]][s.spawn[seat*3+t]]/(t==0?1.65f:1.f);sum+=d;mx=std::max(mx,d);}
46
+ if(sum+.5f*mx<best){best=sum+.5f*mx;for(int t=0;t<3;t++)opening[seat*3+t]=z[t]+1;}
47
+ }
48
+ }}
49
+ for(int j=0;j<6;j++){
50
+ float*d=ctx.ed[j];std::fill(d,d+CELLS,INF);if(!s.tank[j].alive)continue;
51
+ int p=s.tank[j].pos;d[p]=1;
52
+ for(int k=0;k<4;k++)for(int n=1,c=p+DIR_DELTA[k];n<=5;n++,c+=DIR_DELTA[k]){
53
+ if(s.grid[c]!=EMPTY&&s.grid[c]!=WATER)break;
54
+ if(s.grid[c]==EMPTY)d[c]=n*.65f;
55
+ }
56
+ dijkstra(s,d,false,1);
57
+ }
58
+ for(int seat=0;seat<2;seat++){
59
+ float util[3][8];
60
+ for(int t=0;t<3;t++){int i=3*seat+t;const Tank&a=s.tank[i];int p=a.alive?a.pos:s.spawn[i];float speed=t==0?1.65f:1;
61
+ util[t][0]=34-1.6f*ctx.attack[seat][a.level>=2][p]/speed;
62
+ for(int k=0;k<s.n_supply;k++){
63
+ float dis=ctx.sd[a.level>=2][k][p]/speed;
64
+ int wait=(s.star_mask>>k&1)?0:(s.turn<10?11-s.turn:21-(s.turn-10)%20);
65
+ float val=33-2.25f*dis-3.6f*std::max(0.0f,wait-dis);
66
+ if(a.level>=2)val=-1000;
67
+ if(a.level==0)val+=7;else val-=12;
68
+ if(t==0)val+=3;
69
+ util[t][k+1]=val;
70
+ }
71
+ for(int e=0;e<3;e++){
72
+ int j=(1-seat)*3+e;float bd=ctx.attack[1-seat][s.tank[j].level>=2][s.tank[j].pos];
73
+ int home=md(s.tank[j].pos,s.base_pos[seat]);float threat=std::max(0,8-home)*4.5f;
74
+ float dis=ctx.ed[j][p]/speed;
75
+ util[t][s.n_supply+1+e]=s.tank[j].alive&&home<=7?40+threat-2.5f*dis:-1000;
76
+ }
77
+ }
78
+ int goals[3]={};float best=-1e9;
79
+ for(int a=0;a<=s.n_supply+3;a++)for(int b=0;b<=s.n_supply+3;b++)for(int c=0;c<=s.n_supply+3;c++){
80
+ if((a&&a==b)||(a&&a==c)||(b&&b==c))continue;
81
+ int nd=(a>s.n_supply)+(b>s.n_supply)+(c>s.n_supply);
82
+ float v=util[0][a]+util[1][b]+util[2][c]-std::max(0,nd-1)*24;if(v>best){best=v;goals[0]=a;goals[1]=b;goals[2]=c;}}
83
+ for(int t=0;t<3;t++){int i=seat*3+t;const Tank&a=s.tank[i];float speed=t==0?1.65f:1;int goal=goals[t];if(s.turn<11||(s.turn<17&&a.level==0&&(s.star_mask>>(opening[i]-1)&1)))goal=opening[i];ctx.grad[i]=(goal==0?1.6f:goal<=s.n_supply?2.25f:2.5f)/speed;
84
+ for(int c=0;c<CELLS;c++){
85
+ float atk=34-1.6f*std::min(40.f,ctx.attack[seat][a.level>=2][c]/speed);
86
+ float v=atk;
87
+ if(goal&&goal<=s.n_supply){int k=goal-1;float dis=ctx.sd[a.level>=2][k][c]/speed;v=47-2.25f*std::min(40.f,dis);}
88
+ if(goal>s.n_supply){int j=(1-seat)*3+goal-s.n_supply-1;v=50-2.5f*std::min(40.f,ctx.ed[j][c]/speed);}
89
+ ctx.field[i][c]=v;
90
+ }
91
+ }
92
+ }
93
+ // Credit terrain changes immediately, including bullets consumed this turn.
94
+ for(int c=0;c<CELLS;c++)if(s.grid[c]==BRICK||s.grid[c]==STEEL){
95
+ ctx.walls[ctx.nw++]=c;float vv[2]={};
96
+ for(int i=0;i<6;i++)if(s.tank[i].alive){int p=s.tank[i].pos;int d=md(p,c);float gain=ctx.field[i][c]-ctx.field[i][p];
97
+ if(d<=6&&gain>0)vv[i/3]=std::max(vv[i/3],std::max(0.f,(gain-ctx.grad[i]*d)*1.2f+.3f));
98
+ }
99
+ if(md(c,s.base_pos[0])<=2)vv[1]+=7;
100
+ if(md(c,s.base_pos[1])<=2)vv[0]+=7;
101
+ ctx.wallval[c]=vv[0]-vv[1];
102
+ }
103
+ }
104
+ float bulletval(const State&s,const Bullet&b){
105
+ int seat=seat_of(b.owner),pos=b.pos;
106
+ float val=0;
107
+ for(int n=1;n<=s.P.size+1;n++){
108
+ pos+=DIR_DELTA[b.dir];int g=s.grid[pos];if(g==OUTSIDE)break;
109
+ if(g==BRICK||(g==STEEL&&b.steel)){
110
+ float gain=ctx.wallval[pos]*(seat==0?1:-1);
111
+ val=gain;break;
112
+ }
113
+ if(g==STEEL)break;
114
+ if(g==BASE0||g==BASE1){int side=g-BASE0;val=(side!=seat?1.f:-1.f)*135.f/(1+.035f*n);break;}
115
+ int hit=tank_at(s,pos);
116
+ if(hit>=0){
117
+ int free=0;for(int k=0;k<4;k++)if((k/2)!=(b.dir/2)&&s.grid[pos+DIR_DELTA[k]]==EMPTY&&tank_at(s,pos+DIR_DELTA[k])<0)free++;
118
+ float p=(n<=2?.22f:.025f);if(free==0)p=(n<=2?.7f:.12f);
119
+ if(can_fire(s,hit))p*=.55f;
120
+ float damage=16+(s.tank[hit].hp==1?45.f:0);
121
+ val=damage*p*(seat_of(hit)==seat?-1.f:1.f);break;
122
+ }
123
+ }
124
+ return seat==0?val:-val;
125
+ }
126
+ float eval(const State&s){
127
+ if(s.done)return s.winner==0?1e6f:s.winner==1?-1e6f:0;
128
+ float z=(s.base_hp[0]-s.base_hp[1])*180.f+(s.kills[0]-s.kills[1])*28.f+(s.stars_eaten[0]-s.stars_eaten[1])*2;
129
+ for(int i=0;i<6;i++){
130
+ const Tank&t=s.tank[i];float v;
131
+ if(!t.alive)v=-3*respawn_in(s,i);
132
+ else {
133
+ v=40+t.hp*15+t.level*8+ctx.field[i][t.pos];
134
+ if(can_fire(s,i))v+=1.4f;
135
+ int base=s.base_pos[1-i/3];int dir=-1;
136
+ if(cell_x(base)==cell_x(t.pos))dir=base>t.pos?DOWN:UP;
137
+ if(cell_y(base)==cell_y(t.pos))dir=base>t.pos?RIGHT:LEFT;
138
+ if(dir>=0){
139
+ bool clear=true;int dis=md(base,t.pos);
140
+ for(int c=t.pos+DIR_DELTA[dir];c!=base;c+=DIR_DELTA[dir])if(s.grid[c]==BRICK||s.grid[c]==STEEL||tank_at(s,c)>=0){clear=false;break;}
141
+ if(clear)v+=100.f/(1+dis*.35f)*(t.level==0&&i%3!=FIRE?.8f:1.f);
142
+ }
143
+ for(int j=0;j<6;j++)if(seat_of(j)!=seat_of(i)&&!s.tank[j].alive&&s.spawn[j]==t.pos)v-=respawn_in(s,j)<=1?100:15;
144
+ // Only a modest exploration penalty; do not abandon productive siege squares.
145
+ v-=std::min(8,hist[i][t.pos])*.11f;
146
+ }
147
+ z+=(i<3?v:-v);
148
+ }
149
+ if(s.wall_hash!=ctx.wh)for(int k=0;k<ctx.nw;k++){int c=ctx.walls[k];if(s.grid[c]==EMPTY)z+=ctx.wallval[c];}
150
+ for(int k=0;k<s.n_bullets;k++)z+=bulletval(s,s.bullet[k]);
151
+ return z;
152
+ }
153
+ float value(const State&s,int seat,const Orders&a,const Orders&b){State n=s;step_as(n,seat,a,b);float v=eval(n);return seat==0?v:-v;}
154
+ struct Choice {Cmd c;float v;};
155
+ struct Pool{std::vector<Orders> a;void add(Orders x){for(auto y:a)if(x==y)return;a.push_back(x);}};
156
+ Orders improve(const State&s,int seat,Orders own,const Orders&enemy, std::array<std::vector<Choice>,3>*rank=nullptr){
157
+ for(int t=0;t<3;t++){
158
+ Cmd cmds[N_CMDS];int n=legal_commands(s,seat*3+t,cmds);float best=-1e20;Cmd bc=0;std::vector<Choice>ls;
159
+ for(int k=0;k<n;k++){Orders a=own;a.cmd[t]=cmds[k];float v=value(s,seat,a,enemy);ls.push_back({cmds[k],v});if(v>best+1e-4){best=v;bc=cmds[k];}}
160
+ own.cmd[t]=bc;
161
+ if(rank){std::sort(ls.begin(),ls.end(),[](Choice a,Choice b){return a.v>b.v;});(*rank)[t]=ls;}
162
+ }
163
+ return own;
164
+ }
165
+ }
166
+ void init(const State&s,int me){using namespace ai;for(auto &row:hist)std::fill(row,row+CELLS,0);rng=7123671+me;}
167
+ Orders decide(const State&s,int me){
168
+ using namespace ai;setup(s,me);
169
+ for(int i=0;i<6;i++)if(s.tank[i].alive)hist[i][s.tank[i].pos]++;
170
+ Orders a,b;
171
+ a=improve(s,me,a,b);b=improve(s,1-me,b,a);
172
+ Pool pa,pb;pa.add(a);pb.add(b);pb.add(Orders{});
173
+ std::array<std::vector<Choice>,3> ra,rb;
174
+ for(int it=0;it<3;it++){
175
+ a=improve(s,me,a,b,&ra);pa.add(a);
176
+ b=improve(s,1-me,b,a,&rb);pb.add(b);
177
+ }
178
+ for(int t=0;t<3;t++){
179
+ for(int k=0;k<std::min(4,(int)ra[t].size());k++){Orders x=a;x.cmd[t]=ra[t][k].c;pa.add(x);}
180
+ for(int k=0;k<std::min(4,(int)rb[t].size());k++){Orders x=b;x.cmd[t]=rb[t][k].c;pb.add(x);}
181
+ }
182
+ // Include coordinated variants; a single best reply cannot express simultaneous dodges.
183
+ for(int k=0;k<9;k++){
184
+ Orders x=a,y=b;for(int t=0;t<3;t++){int r=(k/(t==0?1:t==1?3:1)+t)%3;if(r<(int)ra[t].size())x.cmd[t]=ra[t][r].c;if(r<(int)rb[t].size())y.cmd[t]=rb[t][r].c;}pa.add(x);pb.add(y);
185
+ }
186
+ int na=pa.a.size(),nb=pb.a.size();float mat[32][32];
187
+ for(int i=0;i<na;i++)for(int j=0;j<nb;j++)mat[i][j]=value(s,me,pa.a[i],pb.a[j]);
188
+ // Fictitious play gives a robust mixed policy for the simultaneous-action game.
189
+ float sa[32]={},sb[32]={};int ca[32]={},cb[32]={};int bi=0,bj=0;
190
+ for(int it=0;it<160;it++){
191
+ ca[bi]++;cb[bj]++;
192
+ for(int i=0;i<na;i++)sa[i]+=mat[i][bj];
193
+ for(int j=0;j<nb;j++)sb[j]+=mat[bi][j];
194
+ bi=0;bj=0;for(int i=1;i<na;i++)if(sa[i]>sa[bi])bi=i;for(int j=1;j<nb;j++)if(sb[j]<sb[bj])bj=j;
195
+ }
196
+ int sel=0;float bv=-1e20;
197
+ for(int i=0;i<na;i++){
198
+ float v=0,w=1e20;for(int j=0;j<nb;j++){v+=mat[i][j]*cb[j]/160.f;w=std::min(w,mat[i][j]);}
199
+ v=.85f*v+.15f*w;
200
+ if(v>bv){bv=v;sel=i;}
201
+ }
202
+
203
+ // Extend the most relevant simultaneous choices through three full turns.
204
+ std::vector<int> ia,ib;
205
+ for(int i=0;i<na;i++)ia.push_back(i);
206
+ for(int j=0;j<nb;j++)ib.push_back(j);
207
+ float ar[64]={},br[64]={};
208
+ for(int i=0;i<na;i++){float w=1e20;for(int j=0;j<nb;j++){ar[i]+=mat[i][j]*cb[j]/160.f;w=std::min(w,mat[i][j]);}ar[i]=ar[i]*.85f+.15f*w;}
209
+ for(int j=0;j<nb;j++){float w=-1e20;for(int i=0;i<na;i++){br[j]+=mat[i][j]*ca[i]/160.f;w=std::max(w,mat[i][j]);}br[j]=br[j]*.85f+.15f*w;}
210
+ std::sort(ia.begin(),ia.end(),[&](int x,int y){return ar[x]>ar[y];});
211
+ std::sort(ib.begin(),ib.end(),[&](int x,int y){return br[x]<br[y];});
212
+ ia.erase(std::remove(ia.begin(),ia.end(),sel),ia.end());ia.insert(ia.begin(),sel);
213
+ ia.resize(std::min(12,(int)ia.size()));ib.resize(std::min(10,(int)ib.size()));
214
+ float deep[12][12];int nr=ia.size(),nc=ib.size();
215
+ for(int x=0;x<nr;x++)for(int y=0;y<nc;y++){
216
+ if(budget_left()<6)return pa.a[sel];
217
+ State n=s;step_as(n,me,pa.a[ia[x]],pb.a[ib[y]]);
218
+ float v=eval(n)*(me==0?1:-1)*.25f;
219
+ for(int depth=0;depth<2&&!n.done;depth++){
220
+ Orders aa,bb;
221
+ aa=improve(n,me,aa,bb);bb=improve(n,1-me,bb,aa);
222
+ Orders aa2=improve(n,me,aa,bb);
223
+ step_as(n,me,aa2,bb);
224
+ v+=eval(n)*(me==0?1:-1)*(depth==0?.30f:.45f);
225
+ }
226
+ deep[x][y]=n.done?eval(n)*(me==0?1:-1):v;
227
+ }
228
+ std::fill(sa,sa+32,0);std::fill(sb,sb+32,0);std::fill(ca,ca+32,0);std::fill(cb,cb+32,0);bi=bj=0;
229
+ for(int it=0;it<200;it++){
230
+ ca[bi]++;cb[bj]++;
231
+ for(int i=0;i<nr;i++)sa[i]+=deep[i][bj];
232
+ for(int j=0;j<nc;j++)sb[j]+=deep[bi][j];
233
+ bi=bj=0;for(int i=1;i<nr;i++)if(sa[i]>sa[bi])bi=i;for(int j=1;j<nc;j++)if(sb[j]<sb[bj])bj=j;
234
+ }
235
+ bv=-1e20;
236
+ for(int i=0;i<nr;i++){
237
+ float v=0,w=1e20;for(int j=0;j<nc;j++){v+=deep[i][j]*cb[j]/200.f;w=std::min(w,deep[i][j]);}
238
+ v=.85f*v+.15f*w;if(v>bv){bv=v;sel=ia[i];}
239
+ }
240
+ return pa.a[sel];
241
+ }
@@ -0,0 +1,356 @@
1
+ // Coordinated tank bot: supply control, a committed fast flanker, and adaptive support.
2
+ // Supply assignments account for opposing arrival times and chassis-specific contest risk.
3
+ // Fire tanks discount incidental chases while retaining critical defensive interceptions.
4
+ // Exact joint-action simulation combines strategic rollouts with nested simultaneous games.
5
+ // Shared action rankings avoid repeated work; every search retains a legal budget fallback.
6
+ #include "tank.hpp"
7
+ #include <algorithm>
8
+ #include <array>
9
+ #include <cmath>
10
+ #include <queue>
11
+ #include <utility>
12
+ #include <vector>
13
+ #include <cstdio>
14
+ #include <unordered_map>
15
+ using namespace tank;
16
+ namespace bot {
17
+ constexpr float INF=10000;
18
+ float bd[6][CELLS], sd[6][MAX_SUPPLY][CELLS], hd[6][3][CELLS], field[6][CELLS];
19
+ int goal[6], previous[6];float anchor[6];
20
+ uint64_t rng=123456789;
21
+ uint64_t random64(){rng^=rng<<13;rng^=rng>>7;rng^=rng<<17;return rng;}
22
+ float rand01(){return (random64()>>40)*(1.0f/16777216);}
23
+ int md(int a,int b){return std::abs(cell_x(a)-cell_x(b))+std::abs(cell_y(a)-cell_y(b));}
24
+ int direction(int a,int b){if(a==b)return -1;if(cell_x(a)==cell_x(b))return a>b?0:1;if(cell_y(a)==cell_y(b))return a>b?2:3;return -1;}
25
+ bool clear(const State&s,int a,int b){int d=direction(a,b);if(d<0)return false;for(int p=a+DIR_DELTA[d];p!=b;p+=DIR_DELTA[d])if(s.grid[p]!=EMPTY&&s.grid[p]!=WATER)return false;return true;}
26
+ void dijkstra(const State&s,int i,float *dist,const std::vector<std::pair<int,float>>& seeds){
27
+ for(int p=0;p<CELLS;p++)dist[p]=INF;
28
+ using Node=std::pair<float,int>;
29
+ std::priority_queue<Node,std::vector<Node>,std::greater<Node>>q;
30
+ for(auto [p,v]:seeds)if(v<dist[p]){dist[p]=v;q.emplace(v,p);}
31
+ float walk=type_of(i)==FAST?.58f:1.f;
32
+ while(!q.empty()){
33
+ auto [v,p]=q.top();q.pop();if(v>dist[p]+.001f)continue;
34
+ int g=s.grid[p];float extra=g==BRICK?2.f:g==STEEL?3.f:0.f;
35
+ for(int d=0;d<4;d++){
36
+ int n=p+DIR_DELTA[d];if(n<0||n>=CELLS)continue;
37
+ int ng=s.grid[n];if(ng==OUTSIDE||ng==WATER||ng==BASE0||ng==BASE1||(ng==STEEL&&s.tank[i].level<2))continue;
38
+ float nv=v+walk+extra;
39
+ if(nv<dist[n]){dist[n]=nv;q.emplace(nv,n);}
40
+ }
41
+ }
42
+ }
43
+ void prepare(const State&s){
44
+ for(int i=0;i<6;i++){
45
+ int side=seat_of(i),base=s.base_pos[1-side];std::vector<std::pair<int,float>> seeds;
46
+ for(int d=0;d<4;d++){
47
+ int walls=0,range=0;
48
+ for(int p=base+DIR_DELTA[d];p>=0&&p<CELLS;p+=DIR_DELTA[d]){
49
+ int g=s.grid[p];if(g==OUTSIDE||g==BASE0||g==BASE1||(g==STEEL&&s.tank[i].level<2))break;
50
+ range++;if(g==BRICK||g==STEEL)walls++;
51
+ if(g!=WATER)seeds.emplace_back(p,range*(type_of(i)==FAST?1.45f:.85f)+walls*2.0f+((type_of(i)==FAST&&d<2)?5.f:0.f));
52
+ }
53
+ }
54
+ dijkstra(s,i,bd[i],seeds);
55
+ for(int k=0;k<s.n_supply;k++)dijkstra(s,i,sd[i][k],{{s.supply[k],0}});
56
+ }
57
+ for(int i=0;i<6;i++)for(int t=0;t<3;t++){
58
+ int j=(1-seat_of(i))*3+t,p=s.tank[j].pos;
59
+ std::vector<std::pair<int,float>> seeds;
60
+ if(s.tank[j].alive)for(int d=0;d<4;d++)for(int range=1;range<=5;range++){
61
+ int q=p+DIR_DELTA[d]*range;if(q<0||q>=CELLS||s.grid[q]==OUTSIDE)break;
62
+ int g=s.grid[q];if(g==BASE0||g==BASE1)break;if(g==STEEL&&s.tank[i].level<2)break;
63
+ if(g==EMPTY||g==BRICK||g==STEEL)seeds.emplace_back(q,1.0f*range+(g==EMPTY?0.f:2.f));
64
+ if(g==BRICK||g==STEEL)break;
65
+ }
66
+ dijkstra(s,i,hd[i][t],seeds);
67
+ }
68
+ for(int side=0;side<2;side++){
69
+ float options[3][7];int next=s.turn<10?10-s.turn:20-(s.turn-10)%20;
70
+ for(int t=0;t<3;t++){
71
+ int i=side*3+t;int p=s.tank[i].alive?s.tank[i].pos:s.spawn[i];
72
+ options[t][0]=-bd[i][p]*.65f;
73
+ for(int k=0;k<s.n_supply;k++){
74
+ float wait=(s.star_mask&(1<<k))?0.f:float(next+1);
75
+ float eta=sd[i][k][p],enemy=INF;
76
+ for(int j=(1-side)*3;j<(1-side)*3+3;j++)if(s.tank[j].alive&&s.tank[j].level<2)enemy=std::min(enemy,sd[j][k][s.tank[j].pos]);
77
+ float value=(s.tank[i].level==0?17.f:0.f)-1.5f*std::max(eta,wait);
78
+ if(enemy+.5f<eta)value-=std::min(18.f,(eta-enemy)*(t==0?4.f:t==2?1.f:2.f));
79
+ if(!s.tank[i].alive)value=-INF;
80
+ if(s.tank[i].level>=2)value=-INF;
81
+ options[t][k+1]=value;
82
+ }
83
+ for(int e=0;e<3;e++){
84
+ int j=(1-side)*3+e;
85
+ float threat=-INF;
86
+ if(s.tank[j].alive){
87
+ int dist=md(s.tank[j].pos,s.base_pos[side]);
88
+ if(dist<=7){threat=27.f-2.f*dist+3.f*s.tank[j].level;
89
+ if(clear(s,s.tank[j].pos,s.base_pos[side]))threat+=18.f;
90
+ }
91
+ }
92
+ options[t][4+e]=threat-1.5f*hd[i][e][p]-(t==1?8.f:0.f);
93
+ if(t==0||!s.tank[i].alive)options[t][4+e]=-INF;
94
+ }
95
+ }
96
+ float best=-INF*10;int choice[3]={};
97
+ for(int a=0;a<7;a++)for(int b=0;b<7;b++)for(int c=0;c<7;c++){
98
+ if((a&&a==b)||(a&&a==c)||(b&&b==c))continue;
99
+ float v=options[0][a]+options[1][b]+options[2][c];
100
+ if(v>best){best=v;choice[0]=a;choice[1]=b;choice[2]=c;}
101
+ }
102
+ for(int t=0;t<3;t++){
103
+ int i=side*3+t;goal[i]=choice[t]-1;
104
+ for(int p=0;p<CELLS;p++)field[i][p]=goal[i]<0?-bd[i][p]:goal[i]<3?-sd[i][goal[i]][p]:-hd[i][goal[i]-3][p];
105
+ }
106
+ }
107
+ }
108
+ float projectile(const State&s,const Bullet&b){
109
+ int side=seat_of(b.owner),p=b.pos,steps=0;
110
+ for(;;){
111
+ if(p<0||p>=CELLS)return 0;
112
+ int g=s.grid[p];
113
+ if(g==OUTSIDE||g==BRICK||g==STEEL)return 0;
114
+ if(g==BASE0||g==BASE1){
115
+ float value=60.f/(1.f+.08f*steps);
116
+ for(int j=0;j<6;j++)if(seat_of(j)!=side&&s.tank[j].alive){int dd=md(s.tank[j].pos,p);if(dd<steps/2+2)value*=.72f;}
117
+ return (g-BASE0==side?-1.f:1.f)*value;
118
+ }
119
+ for(int j=0;j<6;j++)if(s.tank[j].alive&&s.tank[j].pos==p){
120
+ int escapes=0;for(int d=0;d<4;d++){int n=p+DIR_DELTA[d];if(s.grid[n]==EMPTY&&tank_at(s,n)<0)escapes++;}
121
+ float value=(s.tank[j].hp==1?19.f:9.f)/(1.f+.35f*steps);
122
+ if(steps>0)value*=escapes? .3f:.9f;
123
+ if(steps>0&&can_fire(s,j)&&direction(p,b.pos)>=0)value*=.6f;
124
+ return (seat_of(j)==side?-1.f:1.f)*value;
125
+ }
126
+ p+=DIR_DELTA[b.dir];steps++;
127
+ }
128
+ }
129
+ float evaluate(const State&s,int side){
130
+ if(s.done)return s.winner<0?0.f:(s.winner==side?100000.f:-100000.f);
131
+ float v=140.f*(s.base_hp[side]-s.base_hp[1-side])+30.f*(s.kills[side]-s.kills[1-side])+4.f*(s.stars_eaten[side]-s.stars_eaten[1-side]);
132
+ for(int i=0;i<6;i++){
133
+ auto&t=s.tank[i];float val;
134
+ if(t.alive){
135
+ val=34.f+11.f*t.hp+14.f*t.level;
136
+ val+=5.f*(std::max(-45.f,field[i][t.pos])-anchor[i]);
137
+ if(clear(s,t.pos,s.base_pos[1-seat_of(i)]))val+=25.f/(1.f+.18f*md(t.pos,s.base_pos[1-seat_of(i)]));
138
+ }else val=-4.f*respawn_in(s,i)-20.f;
139
+ v+=(seat_of(i)==side?1.f:-1.f)*val;
140
+ }
141
+ for(int k=0;k<s.n_bullets;k++)v+=(seat_of(s.bullet[k].owner)==side?1.f:-1.f)*projectile(s,s.bullet[k]);
142
+ return v;
143
+ }
144
+ void path(const State&s,int i,Cmd c,int&p1,int&p2){
145
+ p1=p2=s.tank[i].pos;
146
+ int d1=-1,d2=-1;if(is_move(c))d1=c-1;else if(is_move2(c)){d1=(c-9)/4;d2=(c-9)%4;}
147
+ if(d1>=0){int n=p1+DIR_DELTA[d1];if(s.grid[n]==EMPTY&&tank_at(s,n)<0)p1=n;}
148
+ p2=p1;if(d2>=0){int n=p2+DIR_DELTA[d2];if(s.grid[n]==EMPTY&&tank_at(s,n)<0)p2=n;}
149
+ }
150
+ float shot_value(const State&s,int i,int d){
151
+ int p=s.tank[i].pos,side=seat_of(i),steps=0;
152
+ for(int n=p+DIR_DELTA[d];;n+=DIR_DELTA[d]){
153
+ steps++;int g=s.grid[n];if(g==OUTSIDE)return 0;
154
+ if(g==BASE0||g==BASE1)return g-BASE0==side?-200.f:70.f/(1.f+.08f*steps);
155
+ int j=tank_at(s,n);
156
+ if(j>=0){
157
+ if(seat_of(j)==side)return -25.f/(1.f+.1f*steps);
158
+ int exits=0;for(int k=0;k<4;k++)if(s.grid[n+DIR_DELTA[k]]==EMPTY&&tank_at(s,n+DIR_DELTA[k])<0)exits++;
159
+ float value=(s.tank[j].hp==1?20.f:13.f)/(1+.35f*steps);
160
+ if(exits>1)value*=.65f;
161
+ if(can_fire(s,j))value*=.65f;
162
+ return value;
163
+ }
164
+ if(g==BRICK||g==STEEL){
165
+ if(g==STEEL&&s.tank[i].level<2)return 0;
166
+ float gain=field[i][n]-field[i][p];
167
+ float value=std::max(0.f,2.0f*gain-1.f)/(1.f+.2f*steps);
168
+ int base=s.base_pos[1-side];
169
+ if(direction(p,base)==d){
170
+ bool line=true;for(int q=n+DIR_DELTA[d];q!=base;q+=DIR_DELTA[d]){if(s.grid[q]==OUTSIDE||(s.grid[q]==STEEL&&s.tank[i].level<2)){line=false;break;}}
171
+ if(line)value+=12.f/(1.f+.1f*md(p,base));
172
+ }
173
+ int own=s.base_pos[side];if(md(n,own)<=2&&md(p,own)<6)value-=8.f;
174
+ return value;
175
+ }
176
+ }
177
+ }
178
+ float primitive(const State&s,int i,Cmd c){
179
+ if(!s.tank[i].alive)return 0;
180
+ int p=s.tank[i].pos,p1,p2;path(s,i,c,p1,p2);
181
+ float val=3.2f*(field[i][p2]-field[i][p]);
182
+ bool fire=is_fire(c)&&can_fire(s,i);int fd=fire?c-5:-1;
183
+ if(fire)val+=shot_value(s,i,fd);
184
+ if(c==STAY)val-=.12f;
185
+ if(p2==p&&is_move(c))val-=.4f;
186
+ int damage=0;
187
+ for(int k=0;k<s.n_bullets;k++){
188
+ const auto&b=s.bullet[k];int n=b.pos+DIR_DELTA[b.dir],nn=n+DIR_DELTA[b.dir];
189
+ bool cancel=false;
190
+ if(fire){int f1=p+DIR_DELTA[fd],f2=f1+DIR_DELTA[fd];cancel=(f1==n)||(f1==b.pos&&n==p)||(f2==nn)||(f2==n&&nn==f1);}
191
+ if(cancel)continue;
192
+ bool hit=n==p1||(n==p&&b.pos==p1);
193
+ if(!hit&&s.grid[n]!=BRICK&&s.grid[n]!=STEEL&&s.grid[n]!=OUTSIDE&&tank_at(s,n)<0)hit=nn==p2||(nn==p1&&n==p2);
194
+ if(hit)damage++;
195
+ }
196
+ if(damage)val-=damage*17.f+(damage>=s.tank[i].hp?65.f+15*s.tank[i].level:0.f);
197
+ for(int j=0;j<6;j++)if(seat_of(i)!=seat_of(j)&&s.tank[j].alive&&can_fire(s,j)){
198
+ int e=s.tank[j].pos;
199
+ for(int d=0;d<4;d++){
200
+ int n=e+DIR_DELTA[d],nn=n+DIR_DELTA[d];
201
+ bool hit=(n==p1)||(nn==p2&&s.grid[n]!=BRICK&&s.grid[n]!=STEEL&&tank_at(s,n)<0)||(p1==e&&n==p);
202
+ if(hit){if(fire&&fd==(d^1)&&direction(p,e)==fd)continue;val-=(s.tank[i].hp==1?17.f:7.f);}
203
+ }
204
+ }
205
+ for(int j=0;j<6;j++)if(seat_of(j)!=seat_of(i)&&!s.tank[j].alive&&s.spawn[j]==p2&&respawn_in(s,j)<=1)val-=200;
206
+ if(goal[i]>=0&&goal[i]<3&&p2==s.supply[goal[i]]&&s.tank[i].level<2&&(s.star_mask&(1<<goal[i])))val+=28;
207
+ if(p2==previous[i]&&p2!=p)val-=.18f;
208
+ return val;
209
+ }
210
+ struct Rated {Cmd c;float v;};
211
+ struct Plan {Orders o;float v;};
212
+ std::vector<Rated> ranked(const State&s,int i){
213
+ Cmd a[N_CMDS];int n=legal_commands(s,i,a);std::vector<Rated>r;
214
+ for(int k=0;k<n;k++)r.push_back({a[k],primitive(s,i,a[k])});
215
+ std::stable_sort(r.begin(),r.end(),[](auto&a,auto&b){return a.v>b.v;});return r;
216
+ }
217
+ Orders policy_from_r(const State&s,int side,const std::vector<Rated>* rs){
218
+ Orders o;int p1[3],p2[3];
219
+ for(int t=0;t<3;t++){
220
+ int i=side*3+t;const auto&r=rs[t];float best=-INF;
221
+ for(auto x:r){int a,b;path(s,i,x.c,a,b);float v=x.v;
222
+ for(int j=0;j<t;j++)if(s.tank[side*3+j].alive&&s.tank[i].alive){if(a==p1[j])v-=20;if(b==p2[j])v-=20;}
223
+ if(v>best){best=v;o.cmd[t]=x.c;p1[t]=a;p2[t]=b;}
224
+ }
225
+ }
226
+ return o;
227
+ }
228
+ Orders policy(const State&s,int side){
229
+ std::vector<Rated> rs[3];for(int t=0;t<3;t++)rs[t]=ranked(s,side*3+t);
230
+ return policy_from_r(s,side,rs);
231
+ }
232
+ std::vector<Orders> plans(const State&s,int side){
233
+ std::vector<Rated> r[3];for(int t=0;t<3;t++)r[t]=ranked(s,side*3+t);
234
+ std::vector<Plan> all;
235
+ for(int a=0;a<std::min(4,(int)r[0].size());a++)for(int b=0;b<std::min(4,(int)r[1].size());b++)for(int c=0;c<std::min(4,(int)r[2].size());c++){
236
+ Orders o;o.cmd[0]=r[0][a].c;o.cmd[1]=r[1][b].c;o.cmd[2]=r[2][c].c;
237
+ int p1[3],p2[3];float v=r[0][a].v+r[1][b].v+r[2][c].v;
238
+ for(int t=0;t<3;t++)path(s,side*3+t,o.cmd[t],p1[t],p2[t]);
239
+ for(int t=0;t<3;t++)for(int j=t+1;j<3;j++)if(s.tank[side*3+t].alive&&s.tank[side*3+j].alive){if(p1[t]==p1[j])v-=20;if(p2[t]==p2[j])v-=20;}
240
+ all.push_back({o,v});
241
+ }
242
+ std::stable_sort(all.begin(),all.end(),[](auto&a,auto&b){return a.v>b.v;});
243
+ std::vector<Orders>out;
244
+ auto add=[&](Orders o){for(auto q:out)if(q==o)return;out.push_back(o);};
245
+ add(policy_from_r(s,side,r));for(int k=0;k<std::min(14,(int)all.size());k++)add(all[k].o);
246
+ Orders best=out[0];
247
+ for(int t=0;t<3;t++)for(int a=0;a<std::min(7,(int)r[t].size());a++){Orders o=best;o.cmd[t]=r[t][a].c;add(o);}
248
+ add(Orders{});return out;
249
+ }
250
+ std::vector<Orders> smallplans(const State&s,int side){
251
+ std::vector<Rated> rs[3];for(int t=0;t<3;t++)rs[t]=ranked(s,side*3+t);
252
+ Orders base=policy_from_r(s,side,rs);std::vector<Orders> a{base};
253
+ for(int t=0;t<3;t++){
254
+ const auto&r=rs[t];int got=0;
255
+ for(auto x:r)if(x.c!=base.cmd[t]){Orders q=base;q.cmd[t]=x.c;if(std::find(a.begin(),a.end(),q)==a.end())a.push_back(q);if(++got>=2)break;}
256
+ }
257
+ return a;
258
+ }
259
+ float subgame(const State&s,int side){
260
+ if(s.done)return evaluate(s,side);
261
+ auto a=smallplans(s,side),b=smallplans(s,1-side);int n=a.size(),m=b.size();
262
+ float M[8][8];for(int i=0;i<n;i++)for(int j=0;j<m;j++){State z=s;step_as(z,side,a[i],b[j]);M[i][j]=evaluate(z,side);}
263
+ double u[8]={},v[8]={},ca[8]={},cb[8]={};int x=0,y=0;
264
+ for(int it=0;it<160;it++){
265
+ if(it>=40){ca[x]++;cb[y]++;}
266
+ for(int i=0;i<n;i++)u[i]+=M[i][y];
267
+ for(int j=0;j<m;j++)v[j]+=M[x][j];
268
+ x=std::max_element(u,u+n)-u;y=std::min_element(v,v+m)-v;
269
+ }
270
+ double ans=0;for(int i=0;i<n;i++)for(int j=0;j<m;j++)ans+=ca[i]*cb[j]*M[i][j];return ans/14400;
271
+ }
272
+ struct GameMix {std::vector<double> a,b;};
273
+ GameMix solvegame(const std::vector<std::vector<float>>&M){
274
+ int n=M.size(),m=M[0].size();
275
+ std::vector<double>u(n,0),v(m,0),ca(n,0),cb(m,0);int x=0,y=0;
276
+ for(int it=0;it<1200;it++){
277
+ if(it>=300){ca[x]++;cb[y]++;}
278
+ for(int j=0;j<n;j++)u[j]+=M[j][y];
279
+ for(int j=0;j<m;j++)v[j]+=M[x][j];
280
+ x=std::max_element(u.begin(),u.end())-u.begin();y=std::min_element(v.begin(),v.end())-v.begin();
281
+ }
282
+ for(double &x:ca)x/=900;
283
+ for(double &x:cb)x/=900;
284
+ return {ca,cb};
285
+ }
286
+ uint64_t code(Orders o){return o.cmd[0]|(uint64_t(o.cmd[1])<<8)|(uint64_t(o.cmd[2])<<16);}
287
+ Orders choose_oracle(const State&s,int side){
288
+ prepare(s);for(int i=0;i<6;i++)anchor[i]=std::max(-45.f,field[i][s.tank[i].alive?s.tank[i].pos:s.spawn[i]]);auto a=plans(s,side),b=plans(s,1-side);
289
+ std::unordered_map<uint64_t,float>cache;cache.reserve(4000);
290
+ auto ev=[&](Orders a,Orders b){
291
+ uint64_t key=code(a)|(code(b)<<24);auto it=cache.find(key);if(it!=cache.end())return it->second;
292
+ State z=s;step_as(z,side,a,b);float first=evaluate(z,side);
293
+ for(int h=0;h<2&&!z.done;h++){Orders u=policy(z,side),v=policy(z,1-side);step_as(z,side,u,v);}
294
+ float ans=.3f*first+.7f*evaluate(z,side);cache.emplace(key,ans);return ans;
295
+ };
296
+ GameMix mix;
297
+ for(int round=0;round<3;round++){
298
+ std::vector<std::vector<float>>M(a.size(),std::vector<float>(b.size()));
299
+ for(int x=0;x<(int)a.size();x++)for(int y=0;y<(int)b.size();y++)M[x][y]=ev(a[x],b[y]);
300
+ mix=solvegame(M);if(round==2||budget_left()<18)break;
301
+ std::vector<std::pair<double,Orders>>sa,sb;
302
+ for(int x=0;x<(int)a.size();x++)if(mix.a[x]>.001)sa.emplace_back(mix.a[x],a[x]);
303
+ for(int y=0;y<(int)b.size();y++)if(mix.b[y]>.001)sb.emplace_back(mix.b[y],b[y]);
304
+ auto prep=[](auto&v){std::sort(v.begin(),v.end(),[](auto&a,auto&b){return a.first>b.first;});if(v.size()>6)v.resize(6);double sum=0;for(auto &x:v)sum+=x.first;for(auto &x:v)x.first/=sum;};prep(sa);prep(sb);
305
+ auto response=[&](int who,Orders best,const std::vector<std::pair<double,Orders>>&support){
306
+ auto val=[&](Orders o){double v=0;for(auto &[p,e]:support)v+=p*(who==side?ev(o,e):-ev(e,o));return v;};
307
+ double current=val(best);
308
+ for(int pass=0;pass<2;pass++)for(int t=0;t<3;t++){
309
+ if(budget_left()<7)return best;
310
+ Cmd list[N_CMDS];int n=legal_commands(s,who*3+t,list);Orders old=best;
311
+ for(int c=0;c<n;c++){Orders trial=old;trial.cmd[t]=list[c];double v=val(trial);if(v>current+.001){current=v;best=trial;}}
312
+ }
313
+ return best;
314
+ };
315
+ int ai=std::max_element(mix.a.begin(),mix.a.end())-mix.a.begin(),bi=std::max_element(mix.b.begin(),mix.b.end())-mix.b.begin();
316
+ Orders ar=response(side,a[ai],sb),br=response(1-side,b[bi],sa);
317
+ if(std::find(a.begin(),a.end(),ar)==a.end())a.push_back(ar);
318
+ if(std::find(b.begin(),b.end(),br)==b.end())b.push_back(br);
319
+ }
320
+ double target=rand01(),sum=0;for(int x=0;x<(int)a.size();x++){sum+=mix.a[x];if(sum>=target)return a[x];}
321
+ return a.back();
322
+ }
323
+ Orders choose_nested(const State&s,int side){
324
+ prepare(s);for(int i=0;i<6;i++)anchor[i]=std::max(-45.f,field[i][s.tank[i].alive?s.tank[i].pos:s.spawn[i]]);
325
+ auto a=plans(s,side),b=plans(s,1-side);
326
+ int n=a.size(),m=b.size();std::vector<float>matrix(n*m);
327
+ for(int x=0;x<n;x++)for(int y=0;y<m;y++){
328
+ if((y&3)==0&&budget_left()<5)return policy(s,side);
329
+ State z=s;step_as(z,side,a[x],b[y]);float first=evaluate(z,side);
330
+ matrix[x*m+y]=.15f*first+.85f*subgame(z,side);
331
+ }
332
+ std::vector<double>u(n,0),v(m,0),counts(n,0),opp(m,0);int x=0,y=0;
333
+ for(int it=0;it<220;it++){
334
+ counts[x]++;opp[y]++;
335
+ for(int j=0;j<n;j++)u[j]+=matrix[j*m+y];
336
+ for(int j=0;j<m;j++)v[j]+=matrix[x*m+j];
337
+ x=std::max_element(u.begin(),u.end())-u.begin();y=std::min_element(v.begin(),v.end())-v.begin();
338
+ }
339
+ double target=rand01()*220,acc=0;int chosen=n-1;
340
+ for(int j=0;j<n;j++){acc+=counts[j];if(acc>target){chosen=j;break;}}
341
+ return a[chosen];
342
+ }
343
+ Orders choose(const State&s,int side){
344
+ bool combat=false;
345
+ for(int i=side*3;i<side*3+3;i++)if(s.tank[i].alive){
346
+ for(int j=(1-side)*3;j<(1-side)*3+3;j++)if(s.tank[j].alive){
347
+ int d=md(s.tank[i].pos,s.tank[j].pos);
348
+ if(d<=3||(d<=6&&clear(s,s.tank[i].pos,s.tank[j].pos)))combat=true;
349
+ }
350
+ for(int k=0;k<s.n_bullets;k++)if(md(s.bullet[k].pos,s.tank[i].pos)<=4)combat=true;
351
+ }
352
+ return combat?choose_nested(s,side):choose_oracle(s,side);
353
+ }
354
+ }
355
+ void init(const State&s,int me){bot::rng=0x7d2543a71b9ULL^s.wall_hash^(me*987654321ULL);for(int i=0;i<6;i++)bot::previous[i]=-1;}
356
+ Orders decide(const State&s,int me){Orders o=bot::choose(s,me);for(int i=0;i<6;i++)bot::previous[i]=s.tank[i].alive?s.tank[i].pos:-1;return o;}