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.
- package/README.md +91 -13
- package/assets/bomberman/workspace.zip +0 -0
- package/assets/commit0/instance.json +30 -0
- package/assets/commit0/workspace.zip +0 -0
- package/assets/ctf/workspace.zip +0 -0
- package/assets/featurebench/hidden/test_regression.py +690 -0
- package/assets/featurebench/instance.json +16 -0
- package/assets/featurebench/workspace.zip +0 -0
- package/assets/swe-bench-pro/hidden/test.patch +36 -0
- package/assets/swe-bench-pro/instance.json +10 -0
- package/assets/swe-bench-pro/workspace.zip +0 -0
- package/assets/tank/workspace.zip +0 -0
- package/eval/README.md +18 -0
- package/eval/arena/arena/README.md +21 -0
- package/eval/arena/arena/bt.py +104 -0
- package/eval/arena/arena/clock.py +15 -0
- package/eval/arena/arena/core.py +265 -0
- package/eval/arena/arena/run.cmd +24 -0
- package/eval/arena/arena/run.sh +11 -0
- package/eval/arena/arena/schedule.py +79 -0
- package/eval/arena/arena/tournament.py +183 -0
- package/eval/arena/bomberman/bots/README.md +16 -0
- package/eval/arena/bomberman/bots/deepseek-v4.1-flash.cpp +447 -0
- package/eval/arena/bomberman/bots/doubao-seed-2.1.cpp +542 -0
- package/eval/arena/bomberman/bots/glm-5.3.cpp +406 -0
- package/eval/arena/bomberman/bots/gpt-6-astra.cpp +768 -0
- package/eval/arena/bomberman/bots/gpt-6-sol.cpp +444 -0
- package/eval/arena/bomberman/bots/kimi-k3.cpp +432 -0
- package/eval/arena/bomberman/bots/mimo-v2.6-pro.cpp +529 -0
- package/eval/arena/bomberman/bots/opus-5.5.cpp +548 -0
- package/eval/arena/bomberman/bots/qwen-3.8-max.cpp +836 -0
- package/eval/arena/bomberman/tournament/README.md +11 -0
- package/eval/arena/bomberman/tournament/bt.py +56 -0
- package/eval/arena/bomberman/tournament/evaluate.py +199 -0
- package/eval/arena/bomberman/tournament/run.py +79 -0
- package/eval/arena/bomberman/tournament/schedule-2to10.json.gz +0 -0
- package/eval/arena/bomberman/workspace/MANIFEST.json +13 -0
- package/eval/arena/bomberman/workspace/README.md +29 -0
- package/eval/arena/bomberman/workspace/RULES.md +100 -0
- package/eval/arena/bomberman/workspace/baseline.cpp +240 -0
- package/eval/arena/bomberman/workspace/clock.py +25 -0
- package/eval/arena/bomberman/workspace/engine/arena.py +198 -0
- package/eval/arena/bomberman/workspace/engine/build.py +35 -0
- package/eval/arena/bomberman/workspace/engine/engine.py +256 -0
- package/eval/arena/bomberman/workspace/engine/verify_replay.py +24 -0
- package/eval/arena/bomberman/workspace/run.cmd +28 -0
- package/eval/arena/bomberman/workspace/run.sh +16 -0
- package/eval/arena/bomberman/workspace/viewer/index.html +42 -0
- package/eval/arena/ctf/bots/README.md +18 -0
- package/eval/arena/ctf/bots/deepseek-v4.1-flash.cpp +601 -0
- package/eval/arena/ctf/bots/doubao-seed-2.1-turbo.cpp +320 -0
- package/eval/arena/ctf/bots/fable-5.1.cpp +634 -0
- package/eval/arena/ctf/bots/glm-5.3.cpp +689 -0
- package/eval/arena/ctf/bots/gpt-6-astra.cpp +657 -0
- package/eval/arena/ctf/bots/gpt-6.1-sol.cpp +725 -0
- package/eval/arena/ctf/bots/kimi-k3.cpp +667 -0
- package/eval/arena/ctf/bots/mimo-v2.6-pro.cpp +533 -0
- package/eval/arena/ctf/bots/opus-5.5.cpp +645 -0
- package/eval/arena/ctf/bots/qwen-3.8-max.cpp +726 -0
- package/eval/arena/ctf/bots/sonnet-5.5.cpp +569 -0
- package/eval/arena/ctf/tournament/README.md +15 -0
- package/eval/arena/ctf/tournament/formal-2to8.json +31 -0
- package/eval/arena/ctf/tournament/formal-9to15.json +31 -0
- package/eval/arena/ctf/workspace/README.md +41 -0
- package/eval/arena/ctf/workspace/RULES.md +119 -0
- package/eval/arena/ctf/workspace/arena.py +186 -0
- package/eval/arena/ctf/workspace/baseline.cpp +257 -0
- package/eval/arena/ctf/workspace/clock.py +15 -0
- package/eval/arena/ctf/workspace/core.py +265 -0
- package/eval/arena/ctf/workspace/engine.py +389 -0
- package/eval/arena/ctf/workspace/run.cmd +24 -0
- package/eval/arena/ctf/workspace/run.sh +11 -0
- package/eval/arena/ctf/workspace/viewer.html +71 -0
- package/eval/arena/land/bots/README.md +17 -0
- package/eval/arena/land/bots/deepseek-4.1f@workbuddy#1/bot.cpp +608 -0
- package/eval/arena/land/bots/glm-5.3@workbuddy#1/bot.cpp +521 -0
- package/eval/arena/land/bots/gpt-6-astra@codex#1/bot.cpp +373 -0
- package/eval/arena/land/bots/gpt-6-sol@codex#1/bot.cpp +341 -0
- package/eval/arena/land/bots/kimi-k3@workbuddy#1/bot.cpp +492 -0
- package/eval/arena/land/bots/mimo-2.6-pro@zcode#1/bot.cpp +652 -0
- package/eval/arena/land/bots/mystery-model@zcode#1/bot.cpp +466 -0
- package/eval/arena/land/bots/opus-5.5@claude-code#1/bot.cpp +630 -0
- package/eval/arena/land/bots/sonnet-5@claude-code#1/bot.cpp +619 -0
- package/eval/arena/land/tournament/make_replay_page.py +17 -0
- package/eval/arena/land/tournament/rate.py +290 -0
- package/eval/arena/land/tournament/round_robin.py +172 -0
- package/eval/arena/land/tournament/sparring.cpp +356 -0
- package/eval/arena/land/workspace/RULES.md +114 -0
- package/eval/arena/land/workspace/TASK.md +46 -0
- package/eval/arena/land/workspace/anchors/.build/greedy_f2e6d2dea5ca +0 -0
- package/eval/arena/land/workspace/anchors/greedy.cpp +194 -0
- package/eval/arena/land/workspace/anchors/random.cpp +80 -0
- package/eval/arena/land/workspace/clock.py +64 -0
- package/eval/arena/land/workspace/engine/build.py +33 -0
- package/eval/arena/land/workspace/engine/game.py +273 -0
- package/eval/arena/land/workspace/engine/referee.py +308 -0
- package/eval/arena/land/workspace/starter/.build/bot_be32b45b4699 +0 -0
- package/eval/arena/land/workspace/starter/bot.cpp +82 -0
- package/eval/arena/land/workspace/viewer/viewer.html +210 -0
- package/eval/arena/tank/bots/README.md +24 -0
- package/eval/arena/tank/bots/half1/deepseek-v4.1-flash.cpp +367 -0
- package/eval/arena/tank/bots/half1/doubao-seed-evolving.cpp +402 -0
- package/eval/arena/tank/bots/half1/gemini-4-argon.cpp +1132 -0
- package/eval/arena/tank/bots/half1/glm-5.3.cpp +551 -0
- package/eval/arena/tank/bots/half1/gpt-6-astra.cpp +233 -0
- package/eval/arena/tank/bots/half1/gpt-6.1-sol-ultrafast.cpp +350 -0
- package/eval/arena/tank/bots/half1/gpt-6.1-sol.cpp +78 -0
- package/eval/arena/tank/bots/half1/grok-4.7.cpp +1099 -0
- package/eval/arena/tank/bots/half1/haiku-5.5.cpp +210 -0
- package/eval/arena/tank/bots/half1/kimi-k3.cpp +353 -0
- package/eval/arena/tank/bots/half1/mimo-v2.6-pro.cpp +336 -0
- package/eval/arena/tank/bots/half1/muse-wonder-full.cpp +560 -0
- package/eval/arena/tank/bots/half1/opus-5.5.cpp +435 -0
- package/eval/arena/tank/bots/half1/qwen-3.8-max.cpp +537 -0
- package/eval/arena/tank/bots/half2/deepseek-v4.1-flash.cpp +425 -0
- package/eval/arena/tank/bots/half2/doubao-seed-evolving.cpp +308 -0
- package/eval/arena/tank/bots/half2/gemini-4-argon.cpp +1390 -0
- package/eval/arena/tank/bots/half2/glm-5.3.cpp +651 -0
- package/eval/arena/tank/bots/half2/gpt-6-astra.cpp +241 -0
- package/eval/arena/tank/bots/half2/gpt-6.1-sol-ultrafast.cpp +356 -0
- package/eval/arena/tank/bots/half2/gpt-6.1-sol.cpp +87 -0
- package/eval/arena/tank/bots/half2/grok-4.7.cpp +1205 -0
- package/eval/arena/tank/bots/half2/haiku-5.5.cpp +210 -0
- package/eval/arena/tank/bots/half2/kimi-k3.cpp +487 -0
- package/eval/arena/tank/bots/half2/mimo-v2.6-pro.cpp +336 -0
- package/eval/arena/tank/bots/half2/muse-wonder-full.cpp +560 -0
- package/eval/arena/tank/bots/half2/opus-5.5.cpp +476 -0
- package/eval/arena/tank/bots/half2/qwen-3.8-max.cpp +392 -0
- package/eval/arena/tank/tournament/README.md +24 -0
- package/eval/arena/tank/tournament/bt.py +218 -0
- package/eval/arena/tank/tournament/final.json +202 -0
- package/eval/arena/tank/tournament/halftime.json +146 -0
- package/eval/arena/tank/tournament/progress.json +911 -0
- package/eval/arena/tank/tournament/schedule.py +100 -0
- package/eval/arena/tank/tournament/sparring.cpp +928 -0
- package/eval/arena/tank/tournament/tournament.py +1426 -0
- package/eval/arena/tank/workspace/README.md +169 -0
- package/eval/arena/tank/workspace/RULES.md +443 -0
- package/eval/arena/tank/workspace/arena.py +862 -0
- package/eval/arena/tank/workspace/baseline.cpp +259 -0
- package/eval/arena/tank/workspace/clock.py +103 -0
- package/eval/arena/tank/workspace/core.py +712 -0
- package/eval/arena/tank/workspace/engine.py +573 -0
- package/eval/arena/tank/workspace/history/.lock +0 -0
- package/eval/arena/tank/workspace/history/20261017-193610-08715287f91f-bot.cpp +109 -0
- package/eval/arena/tank/workspace/history/20261017-193619-f00b2d5635fa-gpt-6-astra.cpp +241 -0
- package/eval/arena/tank/workspace/history/20261017-193643-63319e0a2b1a-gpt-6_1-sol-ultrafast.cpp +356 -0
- package/eval/arena/tank/workspace/history/20261017-193647-41c1341d0a8a-gemini-4-argon.cpp +1390 -0
- package/eval/arena/tank/workspace/history/20261017-193652-e34c0f45539a-gpt-6_1-sol.cpp +87 -0
- package/eval/arena/tank/workspace/history/20261017-193654-c026348ce96e-opus-5_5.cpp +476 -0
- package/eval/arena/tank/workspace/history/20261017-193655-4a21366e94d1-muse-wonder-full.cpp +560 -0
- package/eval/arena/tank/workspace/history/20261017-193657-dbc4e9969c52-mimo-v2_6-pro.cpp +336 -0
- package/eval/arena/tank/workspace/history/20261017-193703-723cd036eb31-grok-4_7.cpp +1205 -0
- package/eval/arena/tank/workspace/history/20261017-193707-1ebbb227be68-deepseek-v4_1-flash.cpp +425 -0
- package/eval/arena/tank/workspace/history/20261017-193709-aeb0e7202ad5-doubao-seed-evolving.cpp +308 -0
- package/eval/arena/tank/workspace/history/20261017-193710-b21ebeb9bc76-kimi-k3.cpp +487 -0
- package/eval/arena/tank/workspace/history/20261017-193712-54cd86531905-haiku-5_5.cpp +210 -0
- package/eval/arena/tank/workspace/history/20261017-193714-efdb8e35c0bf-qwen-3_8-max.cpp +392 -0
- package/eval/arena/tank/workspace/history/20261017-193715-681423c23fdb-glm-5_3.cpp +651 -0
- package/eval/arena/tank/workspace/history/20261017-193717-1a8b3c75181d-sparring.cpp +928 -0
- package/eval/arena/tank/workspace/history/20261017-193720-1e0803a541e8-baseline.cpp +259 -0
- package/eval/arena/tank/workspace/history/log.jsonl +103 -0
- package/eval/arena/tank/workspace/judge/cycles.hpp +53 -0
- package/eval/arena/tank/workspace/judge/fast.cpp +337 -0
- package/eval/arena/tank/workspace/judge/referee.cpp +125 -0
- package/eval/arena/tank/workspace/judge/speed.cpp +99 -0
- package/eval/arena/tank/workspace/run.cmd +31 -0
- package/eval/arena/tank/workspace/run.sh +23 -0
- package/eval/arena/tank/workspace/tank.hpp +1762 -0
- package/eval/arena/tank/workspace/tank_main.cpp +215 -0
- package/eval/arena/tank/workspace/viewer.html +1150 -0
- package/eval/arena/warehouse/workspace/SPEC.md +130 -0
- package/eval/arena/warehouse/workspace/TASK.md +71 -0
- package/eval/arena/warehouse/workspace/baseline/common.h +88 -0
- package/eval/arena/warehouse/workspace/baseline/main.cpp +27 -0
- package/eval/arena/warehouse/workspace/baseline/old_stuff.cpp +87 -0
- package/eval/arena/warehouse/workspace/baseline/sim.cpp +427 -0
- package/eval/arena/warehouse/workspace/baseline/util.cpp +220 -0
- package/eval/arena/warehouse/workspace/clock.py +42 -0
- package/eval/arena/warehouse/workspace/src/common.h +88 -0
- package/eval/arena/warehouse/workspace/src/main.cpp +27 -0
- package/eval/arena/warehouse/workspace/src/old_stuff.cpp +87 -0
- package/eval/arena/warehouse/workspace/src/sim.cpp +427 -0
- package/eval/arena/warehouse/workspace/src/util.cpp +220 -0
- package/eval/arena/warehouse/workspace/tools/bench.py +119 -0
- package/eval/arena/warehouse/workspace/tools/check_input.py +161 -0
- package/eval/arena/warehouse/workspace/tools/gen.py +132 -0
- package/eval/arena/warehouse/workspace/tools/measure.py +107 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.in +1420 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.out +9162 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.in +1465 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.out +3439 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_flood.in +2757 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_flood.out +3126 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_small.in +731 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_small.out +2578 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_wide.in +528 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_wide.out +2026 -0
- package/eval/bomberman.py +20 -0
- package/eval/commit0.py +21 -0
- package/eval/common.py +61 -0
- package/eval/ctf.py +20 -0
- package/eval/featurebench.py +25 -0
- package/eval/land.py +20 -0
- package/eval/legacy/bomberman-prices.json +4 -0
- package/eval/legacy/bomberman.py +161 -0
- package/eval/legacy/commit0.py +91 -0
- package/eval/legacy/ctf-prices.json +4 -0
- package/eval/legacy/ctf.py +178 -0
- package/eval/legacy/featurebench.py +103 -0
- package/eval/legacy/land-prices.json +4 -0
- package/eval/legacy/land.py +177 -0
- package/eval/legacy/swe_bench_pro.py +116 -0
- package/eval/legacy/tank-prices.json +3 -0
- package/eval/legacy/tank.py +408 -0
- package/eval/legacy/warehouse-prices.json +4 -0
- package/eval/legacy/warehouse.py +365 -0
- package/eval/swe-bench-pro.py +25 -0
- package/eval/tank.py +20 -0
- package/eval/warehouse.py +20 -0
- package/lib/client/index.js +376 -63
- package/lib/client/index.js.map +1 -1
- package/lib/index.js +684 -27
- package/package.json +2 -1
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
#include <algorithm>
|
|
2
|
+
#include <array>
|
|
3
|
+
#include <chrono>
|
|
4
|
+
#include <cmath>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
#include <limits>
|
|
8
|
+
#include <queue>
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <vector>
|
|
11
|
+
using namespace std;
|
|
12
|
+
|
|
13
|
+
// All state is supplied by the referee. No files, network, or subprocesses.
|
|
14
|
+
constexpr int CMAX=625, HH=12, INF=10000;
|
|
15
|
+
const char* DIR="UDLRS";
|
|
16
|
+
int N,P,ME,T,LIMIT,FUSE,RANGE,CAP,FIRE,SHRINK,EVERY,C,EXTINCTION;
|
|
17
|
+
int nb[CMAX][5],edge[CMAX],collapse[CMAX];
|
|
18
|
+
struct Player {int c=0,alive=0,death=-1; double kills=0;};
|
|
19
|
+
struct Bomb {int owner,c,at,born;};
|
|
20
|
+
struct Flame {int c,end;};
|
|
21
|
+
struct Source {int c,owner,end;};
|
|
22
|
+
vector<Player> ps;
|
|
23
|
+
vector<Bomb> bombs;
|
|
24
|
+
vector<Flame> flames;
|
|
25
|
+
vector<Source> sources;
|
|
26
|
+
array<char,CMAX> board;
|
|
27
|
+
array<double,CMAX> visits{},central{},field{},site{},boxvalue{};
|
|
28
|
+
array<double,CMAX> tunnelRisk{};
|
|
29
|
+
array<int,CMAX> distme{},enemyDist{},degree{};
|
|
30
|
+
double accessibleCenter;
|
|
31
|
+
int previousCell[10],lastMove[10],age[10],aliveCount;
|
|
32
|
+
int lastOrigin=-1,lastRequested=4,blockedCell=-1,blockStreak=0;
|
|
33
|
+
chrono::steady_clock::time_point collisionDeadline;
|
|
34
|
+
struct SearchBudget {};
|
|
35
|
+
uint64_t rng=0x123456789abcdefULL;
|
|
36
|
+
double noise(){rng^=rng<<13;rng^=rng>>7;rng^=rng<<17;return (rng&65535)/65535.0;}
|
|
37
|
+
int layer(int t){return t<SHRINK?0:1+(t-SHRINK)/EVERY;}
|
|
38
|
+
bool canBomb(int id){
|
|
39
|
+
int n=0;for(auto b:bombs){if(collapse[b.c]<=T)continue;if(b.c==ps[id].c)return false;if(b.owner==id)n++;}return n<CAP;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
struct Forecast {
|
|
43
|
+
int h;
|
|
44
|
+
uint8_t open[HH][CMAX]{},occupied[HH][CMAX]{},safe[HH][CMAX]{};
|
|
45
|
+
uint8_t good[HH+1][CMAX]{};
|
|
46
|
+
uint16_t owners[HH][CMAX]{};
|
|
47
|
+
int destroyed[CMAX];
|
|
48
|
+
Forecast(const vector<Bomb>& input,int horizon=HH,bool provenance=false):h(max(1,min({horizon,LIMIT-T,EXTINCTION-T}))) {
|
|
49
|
+
auto g=board;vector<Bomb> bs=input;
|
|
50
|
+
int expiry[CMAX];fill(expiry,expiry+CMAX,-1);fill(destroyed,destroyed+CMAX,INF);
|
|
51
|
+
for(auto f:flames)expiry[f.c]=max(expiry[f.c],f.end);
|
|
52
|
+
int sourceExp[10][CMAX];
|
|
53
|
+
if(provenance){for(auto &row:sourceExp)fill(row,row+CMAX,-1);for(auto s:sources)sourceExp[s.owner][s.c]=s.end;}
|
|
54
|
+
for(int k=0;k<h;k++){
|
|
55
|
+
int now=T+k;
|
|
56
|
+
for(int c=0;c<C;c++)if(collapse[c]<=now){g[c]='#';expiry[c]=-1;}
|
|
57
|
+
bs.erase(remove_if(bs.begin(),bs.end(),[&](const Bomb& b){return g[b.c]=='#';}),bs.end());
|
|
58
|
+
int at[CMAX];fill(at,at+CMAX,-1);
|
|
59
|
+
for(int i=0;i<(int)bs.size();i++)if(bs[i].born<=now){at[bs[i].c]=i;occupied[k][bs[i].c]=1;}
|
|
60
|
+
for(int c=0;c<C;c++)open[k][c]=(g[c]=='.');
|
|
61
|
+
uint8_t hit[CMAX]={};uint16_t hitOwner[CMAX]={};uint64_t gone=0;int q[128],qh=0,qt=0;
|
|
62
|
+
for(int i=0;i<(int)bs.size();i++)if(bs[i].born<=now&&(bs[i].at<=now||expiry[bs[i].c]>=now)){q[qt++]=i;gone|=1ULL<<i;}
|
|
63
|
+
while(qh<qt){
|
|
64
|
+
int i=q[qh++],c=bs[i].c;hit[c]=1;if(provenance)hitOwner[c]|=1<<bs[i].owner;
|
|
65
|
+
for(int d=0;d<4;d++){
|
|
66
|
+
int z=c;for(int r=0;r<RANGE;r++){
|
|
67
|
+
z=nb[z][d];if(z<0||g[z]=='#')break;
|
|
68
|
+
hit[z]=1;if(provenance)hitOwner[z]|=1<<bs[i].owner;if(g[z]=='+')break;
|
|
69
|
+
if(at[z]>=0){int j=at[z];if(!(gone>>j&1)){gone|=1ULL<<j;q[qt++]=j;}break;}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
int out=0;for(int i=0;i<(int)bs.size();i++)if(!(gone>>i&1))bs[out++]=bs[i];bs.resize(out);
|
|
74
|
+
for(int c=0;c<C;c++){
|
|
75
|
+
if(hit[c]){expiry[c]=max(expiry[c],now+FIRE-1);if(g[c]=='+'){g[c]='.';destroyed[c]=k;}}
|
|
76
|
+
safe[k][c]=(g[c]=='.'&&expiry[c]<now);
|
|
77
|
+
if(provenance&&g[c]!='#')for(int id=0;id<P;id++){
|
|
78
|
+
if(hitOwner[c]>>id&1)sourceExp[id][c]=max(sourceExp[id][c],now+FIRE-1);
|
|
79
|
+
if(sourceExp[id][c]>=now)owners[k][c]|=1<<id;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
for(int c=0;c<C;c++)good[h][c]=(g[c]=='.');
|
|
84
|
+
for(int k=h-1;k>=0;k--)for(int c=0;c<C;c++)if(open[k][c]){
|
|
85
|
+
for(int d=0;d<5;d++){
|
|
86
|
+
int z=nb[c][d];if(z<0||!open[k][z]||(occupied[k][z]&&z!=c))z=c;
|
|
87
|
+
if(safe[k][z]&&good[k+1][z]){good[k][c]=1;break;}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
int dest(int k,int c,int d)const {int z=nb[c][d];return z>=0&&open[k][z]&&(!occupied[k][z]||z==c)?z:c;}
|
|
92
|
+
void rebuildGood(){
|
|
93
|
+
for(int k=0;k<h;k++)fill(good[k],good[k]+CMAX,0);
|
|
94
|
+
fill(good[h],good[h]+CMAX,1);
|
|
95
|
+
for(int k=h-1;k>=0;k--)for(int c=0;c<C;c++)if(open[k][c])for(int d=0;d<5;d++){
|
|
96
|
+
int z=dest(k,c,d);if(safe[k][z]&&good[k+1][z]){good[k][c]=1;break;}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
struct Reach {
|
|
102
|
+
int life[5]{},count[5]{},width[5]{};
|
|
103
|
+
int counts[HH][5]{};
|
|
104
|
+
double utility[5];
|
|
105
|
+
int total=0,mask=0;
|
|
106
|
+
Reach(){fill(utility,utility+5,-1e6);fill(width,width+5,INF);}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
Reach reach(const Forecast& f,int start,bool utility=false){
|
|
110
|
+
uint8_t cur[CMAX]={},nxt[CMAX];cur[start]=31;
|
|
111
|
+
Reach r;
|
|
112
|
+
for(int k=0;k<f.h;k++){
|
|
113
|
+
fill(nxt,nxt+CMAX,0);
|
|
114
|
+
for(int c=0;c<C;c++)if(cur[c]&&f.open[k][c]){
|
|
115
|
+
for(int d=0;d<5;d++){
|
|
116
|
+
int z=f.dest(k,c,d);
|
|
117
|
+
if(f.safe[k][z])nxt[z]|=k?cur[c]:(1<<d);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for(int c=0;c<C;c++)if(nxt[c]){
|
|
121
|
+
int mask=nxt[c];for(int d=0;d<5;d++)if(mask>>d&1){
|
|
122
|
+
r.life[d]=k+1;
|
|
123
|
+
if(f.good[k+1][c])r.counts[k][d]++;
|
|
124
|
+
if(k==f.h-1){r.count[d]++;if(utility)r.utility[d]=max(r.utility[d],field[c]>-1e5?field[c]:-.4*central[c]);}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
copy(nxt,nxt+C,cur);
|
|
128
|
+
}
|
|
129
|
+
for(int c=0;c<C;c++)if(cur[c])r.total++;
|
|
130
|
+
for(int d=0;d<5;d++){
|
|
131
|
+
if(r.count[d])r.mask|=1<<d;
|
|
132
|
+
for(int k=1;k<min(7,f.h);k++)r.width[d]=min(r.width[d],r.counts[k][d]);
|
|
133
|
+
}
|
|
134
|
+
return r;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
array<int,CMAX> distances(int start,bool boxes=false){
|
|
138
|
+
array<int,CMAX> dist;dist.fill(INF);
|
|
139
|
+
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
|
|
140
|
+
if(start<0)return dist;dist[start]=0;q.push({0,start});
|
|
141
|
+
while(!q.empty()){
|
|
142
|
+
auto [v,c]=q.top();q.pop();if(v!=dist[c])continue;
|
|
143
|
+
for(int d=0;d<4;d++){int z=nb[c][d];if(z<0||board[z]=='#'||(!boxes&&board[z]=='+'))continue;
|
|
144
|
+
int nv=v+(board[z]=='+'?7:1);if(nv<dist[z]){dist[z]=nv;q.push({nv,z});}
|
|
145
|
+
}
|
|
146
|
+
}return dist;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
void strategy(const Forecast& f){
|
|
150
|
+
int mine=ps[ME].c;
|
|
151
|
+
for(int c=0;c<C;c++)visits[c]*=.89;
|
|
152
|
+
visits[mine]+=1;
|
|
153
|
+
distme=distances(mine);enemyDist.fill(INF);
|
|
154
|
+
aliveCount=0;
|
|
155
|
+
for(int i=0;i<P;i++)if(ps[i].alive){aliveCount++;if(i!=ME){auto dd=distances(ps[i].c);for(int c=0;c<C;c++)enemyDist[c]=min(enemyDist[c],dd[c]);}}
|
|
156
|
+
// A weighted route through boxes prevents apparently roomy outer pockets
|
|
157
|
+
// from being selected over the last accessible route through a closing ring.
|
|
158
|
+
central.fill(INF);
|
|
159
|
+
priority_queue<pair<double,int>,vector<pair<double,int>>,greater<pair<double,int>>>q;
|
|
160
|
+
int maxedge=0;for(int c=0;c<C;c++)if(board[c]!='#')maxedge=max(maxedge,edge[c]);
|
|
161
|
+
for(int c=0;c<C;c++)if(board[c]!='#'&&edge[c]>=maxedge-1){central[c]=(maxedge-edge[c])*1.5;q.push({central[c],c});}
|
|
162
|
+
while(!q.empty()){
|
|
163
|
+
auto [v,c]=q.top();q.pop();if(v!=central[c])continue;
|
|
164
|
+
for(int d=0;d<4;d++){int z=nb[c][d];if(z<0||board[z]=='#')continue;
|
|
165
|
+
double nv=v+(board[c]=='+'?7.:1.);if(nv<central[z]){central[z]=nv;q.push({nv,z});}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
accessibleCenter=INF;
|
|
169
|
+
for(int c=0;c<C;c++)if(distme[c]<INF)accessibleCenter=min(accessibleCenter,central[c]);
|
|
170
|
+
for(int c=0;c<C;c++){
|
|
171
|
+
degree[c]=0;for(int d=0;d<4;d++){int z=nb[c][d];if(z>=0&&board[z]=='.')degree[c]++;}
|
|
172
|
+
boxvalue[c]=0;
|
|
173
|
+
if(board[c]=='.')for(int d=0;d<4;d++){
|
|
174
|
+
int z=c;for(int r=0;r<RANGE;r++){
|
|
175
|
+
z=nb[z][d];if(z<0||board[z]=='#')break;
|
|
176
|
+
if(board[z]=='+'){
|
|
177
|
+
if(f.destroyed[z]==INF)boxvalue[c]+=(accessibleCenter<=2?.35:1.0)+.12*max(0.0,central[c]-central[z]);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// A long straight passage is dangerous even when each individual bomb has
|
|
184
|
+
// an escape: different opponents can seal its two ends on different turns.
|
|
185
|
+
for(int c=0;c<C;c++){
|
|
186
|
+
tunnelRisk[c]=0;if(board[c]!='.'||degree[c]>=3)continue;
|
|
187
|
+
int dirs[4],dn=0;for(int d=0;d<4;d++){int z=nb[c][d];if(z>=0&&board[z]=='.')dirs[dn++]=d;}
|
|
188
|
+
if(dn==2&&(dirs[0]^1)!=dirs[1])continue;
|
|
189
|
+
int exits=0,contested=0,longest=0,shortest=INF;
|
|
190
|
+
for(int ii=0;ii<dn;ii++){
|
|
191
|
+
int d=dirs[ii],z=c,len=0;
|
|
192
|
+
while(true){
|
|
193
|
+
int v=nb[z][d];if(v<0||board[v]!='.')break;z=v;len++;
|
|
194
|
+
bool turn=false;for(int e=0;e<4;e++)if(e!=d&&e!=(d^1)){int q=nb[z][e];if(q>=0&&board[q]=='.')turn=true;}
|
|
195
|
+
if(turn){exits++;longest=max(longest,len);shortest=min(shortest,len);contested+=enemyDist[z]<=len+1;break;}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if(exits&&contested==exits){tunnelRisk[c]=exits==1?13+1.2*shortest:8+2*min(4,shortest);}
|
|
199
|
+
else if(exits==2&&contested&&longest>=4)tunnelRisk[c]=5;
|
|
200
|
+
}
|
|
201
|
+
// Select a reachable staging cell. Movement follows a distance transform of
|
|
202
|
+
// these objectives rather than a repeatedly replanned distant straight line.
|
|
203
|
+
field.fill(-1e6);
|
|
204
|
+
priority_queue<pair<double,int>>pq;
|
|
205
|
+
for(int c=0;c<C;c++)if(board[c]=='.'){
|
|
206
|
+
int remain=collapse[c]-T;
|
|
207
|
+
double centerWeight=.26+(T>SHRINK-45?.15:0);
|
|
208
|
+
double v=-centerWeight*central[c]+.30*min(3,degree[c]);
|
|
209
|
+
if(remain<30)v-=max(0.,30.-remain)*1.0;
|
|
210
|
+
if(remain<distme[c]+10)v-=20;
|
|
211
|
+
// Productive excavation, with little incentive to keep farming remote boxes.
|
|
212
|
+
v+=1.65*boxvalue[c];
|
|
213
|
+
if(aliveCount==2&&enemyDist[c]<INF){
|
|
214
|
+
v+=max(-3.,2.4-.55*abs(enemyDist[c]-4));
|
|
215
|
+
} else if(enemyDist[c]<7) v-=1.15*(7-enemyDist[c]);
|
|
216
|
+
v-=.42*visits[c];
|
|
217
|
+
site[c]=v;
|
|
218
|
+
field[c]=v;pq.push({v,c});
|
|
219
|
+
}
|
|
220
|
+
while(!pq.empty()){
|
|
221
|
+
auto [v,c]=pq.top();pq.pop();if(v+1e-8<field[c])continue;
|
|
222
|
+
for(int d=0;d<4;d++){int z=nb[c][d];if(z<0||board[z]!='.')continue;
|
|
223
|
+
double nv=v-.72;if(nv>field[z]+1e-8){field[z]=nv;pq.push({nv,z});}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
struct Scenario {int id,c,delay;double weight;};
|
|
229
|
+
vector<Scenario> threats(const Forecast& normal){
|
|
230
|
+
array<int,CMAX> futureDist;futureDist.fill(INF);
|
|
231
|
+
int queue[CMAX],head=0,tail=0;futureDist[ps[ME].c]=0;queue[tail++]=ps[ME].c;
|
|
232
|
+
while(head<tail){int c=queue[head++];for(int d=0;d<4;d++){int z=nb[c][d];if(z>=0&&normal.open[normal.h-1][z]&&futureDist[z]==INF){futureDist[z]=futureDist[c]+1;queue[tail++]=z;}}}
|
|
233
|
+
vector<pair<int,int>> near;
|
|
234
|
+
for(int i=0;i<P;i++)if(i!=ME&&ps[i].alive){
|
|
235
|
+
int d=futureDist[ps[i].c];
|
|
236
|
+
if(d<=8)near.push_back({d,i});
|
|
237
|
+
}
|
|
238
|
+
sort(near.begin(),near.end());vector<Scenario> out;
|
|
239
|
+
for(auto [distance,id]:near){
|
|
240
|
+
uint8_t current[CMAX]={},next[CMAX];current[ps[id].c]=1;
|
|
241
|
+
int depth=distance<=6?3:1;
|
|
242
|
+
for(int delay=0;delay<=depth&&delay<normal.h;delay++){
|
|
243
|
+
int active=0;for(auto b:bombs)if(b.owner==id&&normal.occupied[delay][b.c])active++;
|
|
244
|
+
if(active<CAP)for(int c=0;c<C;c++)if(current[c]&&!normal.occupied[delay][c]&&normal.open[delay][c]&&futureDist[c]<=7){
|
|
245
|
+
double weight=delay==0?1.:delay==1?.85:delay==2?.70:.55;
|
|
246
|
+
out.push_back({id,c,delay,weight});
|
|
247
|
+
}
|
|
248
|
+
fill(next,next+CMAX,0);
|
|
249
|
+
for(int c=0;c<C;c++)if(current[c]&&normal.open[delay][c])for(int d=0;d<5;d++){
|
|
250
|
+
int z=normal.dest(delay,c,d);if(normal.safe[delay][z])next[z]=1;
|
|
251
|
+
}
|
|
252
|
+
copy(next,next+C,current);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
stable_sort(out.begin(),out.end(),[&](const Scenario&a,const Scenario&b){
|
|
256
|
+
double va=(a.delay?2.*a.delay:-10.)+.4*futureDist[a.c];
|
|
257
|
+
double vb=(b.delay?2.*b.delay:-10.)+.4*futureDist[b.c];return va<vb;
|
|
258
|
+
});
|
|
259
|
+
if(out.size()>64)out.resize(64);
|
|
260
|
+
return out;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
struct Decision {int d=4,b=0;double val=-1e100;};
|
|
264
|
+
|
|
265
|
+
// Small-board full game search. Unlike the fixed-schedule movement game below,
|
|
266
|
+
// this includes both players' future bomb placements and all chain reactions.
|
|
267
|
+
namespace Small {
|
|
268
|
+
using U=uint64_t;
|
|
269
|
+
struct State {
|
|
270
|
+
U crates=0,bomb[2][5]{},fire[2]{};
|
|
271
|
+
uint8_t pos[2]{},k=0;
|
|
272
|
+
int16_t result=2001;
|
|
273
|
+
};
|
|
274
|
+
struct Entry {U key=0;int16_t value=0;uint8_t depth=0,flag=0;uint32_t stamp=0;};
|
|
275
|
+
static Entry table[1<<18];
|
|
276
|
+
static uint32_t stamp=0;
|
|
277
|
+
struct Solver {
|
|
278
|
+
int enemy,K=0,cells[64],index[CMAX],next[64][5],ray[64][4][3];
|
|
279
|
+
U bits[64],available[32],adj[64],zBomb[2][5][64],zFire[2][64],zCrate[64],zPos[2][64],zTime[32];
|
|
280
|
+
double killDiff;
|
|
281
|
+
State initial;
|
|
282
|
+
chrono::steady_clock::time_point deadline;
|
|
283
|
+
bool aborted=false;int nodes=0;
|
|
284
|
+
Solver(int e,chrono::steady_clock::time_point end):enemy(e),killDiff(ps[ME].kills-ps[e].kills),deadline(end){
|
|
285
|
+
fill(index,index+C,-1);
|
|
286
|
+
for(int c=0;c<C;c++)if(board[c]!='#'){index[c]=K;cells[K]=c;bits[K]=1ULL<<K;K++;}
|
|
287
|
+
for(int i=0;i<K;i++){
|
|
288
|
+
int c=cells[i];if(board[c]=='+')initial.crates|=bits[i];adj[i]=0;
|
|
289
|
+
for(int d=0;d<5;d++){int z=nb[c][d];next[i][d]=z>=0?index[z]:-1;if(d<4&&next[i][d]>=0)adj[i]|=bits[next[i][d]];}
|
|
290
|
+
for(int d=0;d<4;d++){
|
|
291
|
+
int z=c;for(int r=0;r<3;r++){z=z<0?-1:nb[z][d];ray[i][d][r]=z<0?-1:index[z];}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
for(int k=0;k<32;k++){available[k]=0;for(int i=0;i<K;i++)if(collapse[cells[i]]>T+k)available[k]|=bits[i];}
|
|
295
|
+
initial.pos[0]=index[ps[ME].c];initial.pos[1]=index[ps[e].c];
|
|
296
|
+
for(auto b:bombs){int owner=b.owner==ME?0:1;initial.bomb[owner][clamp(b.at-T,0,4)]|=bits[index[b.c]];}
|
|
297
|
+
for(auto s:sources)if(s.end>=T){int owner=s.owner==ME?0:1;initial.fire[owner]|=bits[index[s.c]];}
|
|
298
|
+
// All positions are hashed independently of the move ordering RNG.
|
|
299
|
+
U seed=0x1e390dc89f3795bdULL;
|
|
300
|
+
auto random=[&](){seed+=0x9e3779b97f4a7c15ULL;U z=seed;z=(z^(z>>30))*0xbf58476d1ce4e5b9ULL;z=(z^(z>>27))*0x94d049bb133111ebULL;return z^(z>>31);};
|
|
301
|
+
for(int i=0;i<K;i++){
|
|
302
|
+
zCrate[i]=random();for(int p=0;p<2;p++){zPos[p][i]=random();zFire[p][i]=random();for(int k=0;k<5;k++)zBomb[p][k][i]=random();}
|
|
303
|
+
}
|
|
304
|
+
for(auto &v:zTime)v=random();
|
|
305
|
+
stamp++;if(!stamp){for(auto &v:table)v.stamp=0;stamp=1;}
|
|
306
|
+
}
|
|
307
|
+
U allBombs(const State& s)const {U b=0;for(auto &owner:s.bomb)for(U v:owner)b|=v;return b;}
|
|
308
|
+
U neighbors(U cellsMask)const {U out=0;while(cellsMask){int c=__builtin_ctzll(cellsMask);cellsMask&=cellsMask-1;out|=adj[c];}return out;}
|
|
309
|
+
int outcome(bool a,bool b,U fire0,U fire1,int ca,int cb)const {
|
|
310
|
+
double diff=killDiff+(!b&&bool(fire0&bits[cb]))-(!a&&bool(fire1&bits[ca]));
|
|
311
|
+
double score=(a?1.:0.)-(b?1.:0.)+.5*diff;
|
|
312
|
+
return score>1e-8?1000:score< -1e-8?-1000:0;
|
|
313
|
+
}
|
|
314
|
+
State step(const State& in,int a,int b,U* lethal=nullptr,U* walkable=nullptr)const {
|
|
315
|
+
State s=in;int k=s.k;U valid=available[min(k,31)];
|
|
316
|
+
s.crates&=valid;
|
|
317
|
+
for(int p=0;p<2;p++){s.fire[p]&=valid;for(int t=0;t<5;t++)s.bomb[p][t]&=valid;}
|
|
318
|
+
bool live[2]={bool(valid&bits[s.pos[0]]),bool(valid&bits[s.pos[1]])};
|
|
319
|
+
U occupied=allBombs(s);
|
|
320
|
+
int actions[2]={a,b};
|
|
321
|
+
for(int p=0;p<2;p++)if(live[p]&&actions[p]>=5&&!(occupied&bits[s.pos[p]])){
|
|
322
|
+
U own=0;for(U v:s.bomb[p])own|=v;
|
|
323
|
+
if(__builtin_popcountll(own)<CAP){s.bomb[p][4]|=bits[s.pos[p]];occupied|=bits[s.pos[p]];}
|
|
324
|
+
}
|
|
325
|
+
U floor=valid&~s.crates;
|
|
326
|
+
int dest[2];
|
|
327
|
+
for(int p=0;p<2;p++){
|
|
328
|
+
int c=s.pos[p],z=next[c][actions[p]%5];
|
|
329
|
+
dest[p]=live[p]&&z>=0&&(floor&bits[z])&&(!(occupied&bits[z])||z==c)?z:c;
|
|
330
|
+
}
|
|
331
|
+
if(live[0]&&live[1]&&dest[0]==dest[1]){dest[0]=s.pos[0];dest[1]=s.pos[1];}
|
|
332
|
+
U oldfire=s.fire[0]|s.fire[1];
|
|
333
|
+
U queued=s.bomb[0][0]|s.bomb[1][0]|(oldfire&occupied),exploded=0,hit[2]={};
|
|
334
|
+
U owner0=0;for(U v:s.bomb[0])owner0|=v;
|
|
335
|
+
while(queued){
|
|
336
|
+
int c=__builtin_ctzll(queued);queued&=queued-1;if(exploded&bits[c])continue;
|
|
337
|
+
exploded|=bits[c];int owner=(owner0&bits[c])?0:1;hit[owner]|=bits[c];
|
|
338
|
+
for(int d=0;d<4;d++)for(int r=0;r<3;r++){
|
|
339
|
+
int z=ray[c][d][r];if(z<0||!(valid&bits[z]))break;
|
|
340
|
+
hit[owner]|=bits[z];if(s.crates&bits[z])break;
|
|
341
|
+
if(occupied&bits[z]){queued|=bits[z]&~exploded;break;}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
U danger=oldfire|hit[0]|hit[1];
|
|
345
|
+
if(lethal)*lethal=danger;if(walkable)*walkable=floor&~occupied;
|
|
346
|
+
bool after[2]={live[0]&&!(danger&bits[dest[0]]),live[1]&&!(danger&bits[dest[1]])};
|
|
347
|
+
if(!after[0]||!after[1])s.result=outcome(after[0],after[1],s.fire[0]|hit[0],s.fire[1]|hit[1],dest[0],dest[1]);
|
|
348
|
+
s.crates&=~(hit[0]|hit[1]);
|
|
349
|
+
for(int p=0;p<2;p++){
|
|
350
|
+
for(int t=0;t<4;t++)s.bomb[p][t]=s.bomb[p][t+1]&~exploded;
|
|
351
|
+
s.bomb[p][4]=0;s.fire[p]=hit[p];s.pos[p]=dest[p];
|
|
352
|
+
}
|
|
353
|
+
s.k++;
|
|
354
|
+
return s;
|
|
355
|
+
}
|
|
356
|
+
int actions(const State& s,int p,int out[10])const {
|
|
357
|
+
U occ=allBombs(s),own=0;for(U v:s.bomb[p])own|=v;
|
|
358
|
+
int c=s.pos[p],count=0;
|
|
359
|
+
bool drop=__builtin_popcountll(own)<CAP&&!(occ&bits[c]);
|
|
360
|
+
U floor=available[min(31,int(s.k))]&~s.crates;
|
|
361
|
+
for(int d=0;d<5;d++){
|
|
362
|
+
int z=next[c][d];if(d<4&&(z<0||!(floor&bits[z])||(occ&bits[z])))continue;
|
|
363
|
+
out[count++]=d;if(drop)out[count++]=d+5;
|
|
364
|
+
}
|
|
365
|
+
return count;
|
|
366
|
+
}
|
|
367
|
+
U hash(const State& s)const {
|
|
368
|
+
U h=zTime[min(31,int(s.k))]^zPos[0][s.pos[0]]^zPos[1][s.pos[1]];
|
|
369
|
+
U v=s.crates;while(v){int c=__builtin_ctzll(v);v&=v-1;h^=zCrate[c];}
|
|
370
|
+
for(int p=0;p<2;p++){
|
|
371
|
+
v=s.fire[p];while(v){int c=__builtin_ctzll(v);v&=v-1;h^=zFire[p][c];}
|
|
372
|
+
for(int t=0;t<5;t++){v=s.bomb[p][t];while(v){int c=__builtin_ctzll(v);v&=v-1;h^=zBomb[p][t][c];}}
|
|
373
|
+
}
|
|
374
|
+
return h;
|
|
375
|
+
}
|
|
376
|
+
int evaluate(const State& start)const {
|
|
377
|
+
State s=start;U r[2]={bits[s.pos[0]],bits[s.pos[1]]};int life[2]={0,0};
|
|
378
|
+
double room[2]={0,0};
|
|
379
|
+
for(int k=0;k<6;k++){
|
|
380
|
+
int now=s.k;U danger,walk;
|
|
381
|
+
State after=step(s,4,4,&danger,&walk);
|
|
382
|
+
for(int p=0;p<2;p++){
|
|
383
|
+
r[p]&=available[min(now,31)];
|
|
384
|
+
r[p]=(r[p]|(neighbors(r[p])&walk))&~danger;
|
|
385
|
+
if(r[p])life[p]=k+1;
|
|
386
|
+
room[p]+=log(1.+__builtin_popcountll(r[p]));
|
|
387
|
+
}
|
|
388
|
+
s=after;
|
|
389
|
+
if(!available[min(int(s.k),31)]){
|
|
390
|
+
// The next shrink terminates the board. Survivors are tied on survival.
|
|
391
|
+
if(r[0]&&r[1])return killDiff>1e-8?900:killDiff< -1e-8?-900:0;
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if(!r[0]||!r[1]){
|
|
396
|
+
if(r[0])return 850;if(r[1])return -850;
|
|
397
|
+
return life[0]>life[1]?800:life[0]<life[1]?-800:0;
|
|
398
|
+
}
|
|
399
|
+
return int(4*(room[0]-room[1])+2*(__builtin_popcountll(r[0])-__builtin_popcountll(r[1])));
|
|
400
|
+
}
|
|
401
|
+
int search(const State& s,int depth,int alpha,int beta){
|
|
402
|
+
if(s.result!=2001)return s.result;
|
|
403
|
+
if((++nodes&127)==0&&chrono::steady_clock::now()>=deadline){aborted=true;return 0;}
|
|
404
|
+
if(!depth)return evaluate(s);
|
|
405
|
+
U key=hash(s);Entry &entry=table[key&((1<<18)-1)];
|
|
406
|
+
int preferred=-1;
|
|
407
|
+
if(entry.stamp==stamp&&entry.key==key)preferred=entry.flag>>2;
|
|
408
|
+
if(entry.stamp==stamp&&entry.key==key&&entry.depth>=depth){
|
|
409
|
+
int bound=entry.flag&3;
|
|
410
|
+
if(bound==0)return entry.value;
|
|
411
|
+
if(bound==1)alpha=max(alpha,int(entry.value));else beta=min(beta,int(entry.value));
|
|
412
|
+
if(alpha>=beta)return entry.value;
|
|
413
|
+
}
|
|
414
|
+
int alphaStart=alpha,betaStart=beta;
|
|
415
|
+
int aa[10],bb[10];int an=actions(s,0,aa),bn=actions(s,1,bb);
|
|
416
|
+
for(int i=0;i<an;i++)if(aa[i]==preferred)swap(aa[i],aa[0]);
|
|
417
|
+
// Quiet moves first are a useful baseline for pruning speculative bombs.
|
|
418
|
+
int best=-1100,bestAction=aa[0];
|
|
419
|
+
for(int i=0;i<an;i++){
|
|
420
|
+
int worst=1100;
|
|
421
|
+
for(int j=0;j<bn;j++){
|
|
422
|
+
State child=step(s,aa[i],bb[j]);
|
|
423
|
+
int v=search(child,depth-1,alpha,min(beta,worst));
|
|
424
|
+
if(aborted)return 0;
|
|
425
|
+
worst=min(worst,v);if(worst<=alpha)break;
|
|
426
|
+
}
|
|
427
|
+
if(worst>best){best=worst;bestAction=aa[i];}alpha=max(alpha,best);if(alpha>=beta)break;
|
|
428
|
+
}
|
|
429
|
+
entry={key,(int16_t)best,(uint8_t)depth,(uint8_t)((best<=alphaStart?2:best>=betaStart?1:0)|(bestAction<<2)),stamp};
|
|
430
|
+
return best;
|
|
431
|
+
}
|
|
432
|
+
Decision choose(Decision fallback){
|
|
433
|
+
int aa[10],bb[10],an=actions(initial,0,aa),bn=actions(initial,1,bb);
|
|
434
|
+
int preferred=fallback.d+5*fallback.b;
|
|
435
|
+
for(int i=0;i<an;i++)if(aa[i]==preferred)swap(aa[0],aa[i]);
|
|
436
|
+
Decision chosen=fallback;
|
|
437
|
+
double finalPolicy[10]={};int policyActions[10],policyCount=0;
|
|
438
|
+
for(int depth=1;depth<=7;depth++){
|
|
439
|
+
int best=-1100,choice=-1;double bestAverage=-1e10;
|
|
440
|
+
int matrix[10][10]{};
|
|
441
|
+
for(int i=0;i<an;i++){
|
|
442
|
+
int worst=1100;double average=0;
|
|
443
|
+
for(int j=0;j<bn;j++){
|
|
444
|
+
int v=search(step(initial,aa[i],bb[j]),depth-1,-1100,1100);
|
|
445
|
+
if(aborted)break;
|
|
446
|
+
matrix[i][j]=v;
|
|
447
|
+
worst=min(worst,v);average+=v;
|
|
448
|
+
}
|
|
449
|
+
if(aborted)break;
|
|
450
|
+
if(worst>best||(worst==best&&average>bestAverage+.01)){
|
|
451
|
+
best=worst;choice=aa[i];bestAverage=average;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if(aborted||choice<0)break;
|
|
455
|
+
chosen={choice%5,choice/5,double(best)};
|
|
456
|
+
// Fictitious play supplies a mixed maximin strategy when deterministic
|
|
457
|
+
// actions are exploitable by a different simultaneous counter-move each.
|
|
458
|
+
double rowCount[10]={},colCount[10]={},rowSum[10]={},colSum[10]={};
|
|
459
|
+
for(int iteration=0;iteration<600;iteration++){
|
|
460
|
+
int ri=0,cj=0;
|
|
461
|
+
for(int i=1;i<an;i++)if(rowSum[i]>rowSum[ri])ri=i;
|
|
462
|
+
for(int j=1;j<bn;j++)if(colSum[j]<colSum[cj])cj=j;
|
|
463
|
+
rowCount[ri]++;colCount[cj]++;
|
|
464
|
+
for(int i=0;i<an;i++)rowSum[i]+=matrix[i][cj];
|
|
465
|
+
for(int j=0;j<bn;j++)colSum[j]+=matrix[ri][j];
|
|
466
|
+
}
|
|
467
|
+
double lower=1e9;for(int j=0;j<bn;j++)lower=min(lower,colSum[j]/600.);
|
|
468
|
+
policyCount=0;
|
|
469
|
+
if(lower>best+8){
|
|
470
|
+
policyCount=an;for(int i=0;i<an;i++){policyActions[i]=aa[i];finalPolicy[i]=rowCount[i]/600.;}
|
|
471
|
+
}
|
|
472
|
+
for(int i=0;i<an;i++)if(aa[i]==choice)swap(aa[0],aa[i]);
|
|
473
|
+
if(best>=1000)break;
|
|
474
|
+
}
|
|
475
|
+
if(policyCount){double draw=noise();for(int i=0;i<policyCount;i++){draw-=finalPolicy[i];if(draw<=0){chosen.d=policyActions[i]%5;chosen.b=policyActions[i]/5;break;}}}
|
|
476
|
+
return chosen;
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Exact movement game with a fixed bomb schedule. Each move is simultaneous:
|
|
482
|
+
// the adversary may contest a square, stay to block it, or exchange positions.
|
|
483
|
+
// Memoization is over (time, our square, their square), not independent paths.
|
|
484
|
+
struct MovementGame {
|
|
485
|
+
const Forecast& f;
|
|
486
|
+
int enemy,h,K=0,map[CMAX],cells[CMAX],nodes=0;
|
|
487
|
+
vector<int16_t> memo;
|
|
488
|
+
MovementGame(const Forecast& ff,int e):f(ff),enemy(e),h(min(7,ff.h)){
|
|
489
|
+
fill(map,map+C,-1);
|
|
490
|
+
for(int c=0;c<C;c++)if(board[c]!='#'){
|
|
491
|
+
int a=ps[ME].c,b=ps[e].c;
|
|
492
|
+
int da=abs(c%N-a%N)+abs(c/N-a/N),db=abs(c%N-b%N)+abs(c/N-b/N);
|
|
493
|
+
if(min(da,db)<=h){map[c]=K;cells[K++]=c;}
|
|
494
|
+
}
|
|
495
|
+
memo.assign(h*K*K,32767);
|
|
496
|
+
}
|
|
497
|
+
int terminal(int k,int a,int b,bool la,bool lb){
|
|
498
|
+
if(la&&lb)return 2001;
|
|
499
|
+
if(aliveCount>2){
|
|
500
|
+
if(!la)return lb?-1000:-750;
|
|
501
|
+
return k+1>=f.h||f.good[k+1][a]?700:-500;
|
|
502
|
+
}
|
|
503
|
+
double diff=ps[ME].kills-ps[enemy].kills;
|
|
504
|
+
if(!la&&f.open[k][a]){
|
|
505
|
+
unsigned owners=f.owners[k][a]&~(1U<<ME);
|
|
506
|
+
if(owners>>enemy&1)diff-=1./__builtin_popcount(owners);
|
|
507
|
+
}
|
|
508
|
+
if(!lb&&f.open[k][b]){
|
|
509
|
+
unsigned owners=f.owners[k][b]&~(1U<<enemy);
|
|
510
|
+
if(owners>>ME&1)diff+=1./__builtin_popcount(owners);
|
|
511
|
+
}
|
|
512
|
+
double score=(la?1:0)-(lb?1:0)+.5*diff;
|
|
513
|
+
return score>1e-7?1000:score< -1e-7?-1000:0;
|
|
514
|
+
}
|
|
515
|
+
int transition(int k,int a,int b,int na,int nb){
|
|
516
|
+
bool activeA=f.open[k][a],activeB=f.open[k][b];
|
|
517
|
+
if(!activeA)na=a;if(!activeB)nb=b;
|
|
518
|
+
if(activeA&&activeB&&na==nb){na=a;nb=b;}
|
|
519
|
+
// With two players, target equality is the only collision needed: targeting
|
|
520
|
+
// a stationary player also equals that player's target. Swaps stay legal.
|
|
521
|
+
bool la=activeA&&f.safe[k][na],lb=activeB&&f.safe[k][nb];
|
|
522
|
+
int v=terminal(k,na,nb,la,lb);
|
|
523
|
+
if(v!=2001)return v;
|
|
524
|
+
return solve(k+1,na,nb);
|
|
525
|
+
}
|
|
526
|
+
bool enemyCanLive(int k,int a,int b,int na,int nb)const {
|
|
527
|
+
if(!f.open[k][b])return false;
|
|
528
|
+
if(f.open[k][a]&&na==nb)nb=b;
|
|
529
|
+
return f.safe[k][nb]&&f.good[k+1][nb];
|
|
530
|
+
}
|
|
531
|
+
int solve(int k,int a,int b){
|
|
532
|
+
if(k>=h)return 0;
|
|
533
|
+
if((++nodes&255)==0&&chrono::steady_clock::now()>=collisionDeadline)throw SearchBudget{};
|
|
534
|
+
int index=(k*K+map[a])*K+map[b];
|
|
535
|
+
int cached=memo[index];if(cached!=32767)return cached;
|
|
536
|
+
int aa[5],bb[5],an=0,bn=0;
|
|
537
|
+
for(int d=0;d<5;d++){
|
|
538
|
+
int z=f.dest(k,a,d);if(find(aa,aa+an,z)==aa+an)aa[an++]=z;
|
|
539
|
+
z=f.dest(k,b,d);if(find(bb,bb+bn,z)==bb+bn)bb[bn++]=z;
|
|
540
|
+
}
|
|
541
|
+
int best=-1001;
|
|
542
|
+
for(int i=0;i<an;i++){
|
|
543
|
+
int worst=1001;
|
|
544
|
+
bool rational=false;
|
|
545
|
+
if(aliveCount>2)for(int j=0;j<bn;j++)rational|=enemyCanLive(k,a,b,aa[i],bb[j]);
|
|
546
|
+
for(int j=0;j<bn;j++){
|
|
547
|
+
if(rational&&!enemyCanLive(k,a,b,aa[i],bb[j]))continue;
|
|
548
|
+
worst=min(worst,transition(k,a,b,aa[i],bb[j]));
|
|
549
|
+
if(worst<=best)break;
|
|
550
|
+
}
|
|
551
|
+
best=max(best,worst);if(best>=1000)break;
|
|
552
|
+
}
|
|
553
|
+
memo[index]=best;return best;
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
void collisionGame(double values[2][5]){
|
|
558
|
+
vector<pair<int,int>> rivals;
|
|
559
|
+
for(int i=0;i<P;i++)if(ps[i].alive&&i!=ME&&distme[ps[i].c]<=(aliveCount==2?9:6))rivals.push_back({distme[ps[i].c],i});
|
|
560
|
+
sort(rivals.begin(),rivals.end());if(rivals.size()>2)rivals.resize(2);
|
|
561
|
+
for(auto [distance,enemy]:rivals){
|
|
562
|
+
double local[2][5]{};
|
|
563
|
+
try {
|
|
564
|
+
for(int place=0;place<2;place++){
|
|
565
|
+
if(place&&!canBomb(ME))continue;
|
|
566
|
+
int worst[5];fill(worst,worst+5,1001);double average[5]={};int samples=0;
|
|
567
|
+
for(int eb=0;eb<2;eb++){
|
|
568
|
+
if(eb&&!canBomb(enemy))continue;
|
|
569
|
+
auto bs=bombs;if(place)bs.push_back({ME,ps[ME].c,T+FUSE,T});if(eb)bs.push_back({enemy,ps[enemy].c,T+FUSE,T});
|
|
570
|
+
Forecast f(bs,HH,true);MovementGame game(f,enemy);
|
|
571
|
+
int moves[5],mn=0;
|
|
572
|
+
for(int ed=0;ed<5;ed++){int z=f.dest(0,ps[enemy].c,ed);if(find(moves,moves+mn,z)==moves+mn)moves[mn++]=z;}
|
|
573
|
+
for(int d=0;d<5;d++){
|
|
574
|
+
int dest=f.dest(0,ps[ME].c,d);bool rational=false;
|
|
575
|
+
if(aliveCount>2)for(int j=0;j<mn;j++)rational|=game.enemyCanLive(0,ps[ME].c,ps[enemy].c,dest,moves[j]);
|
|
576
|
+
for(int j=0;j<mn;j++){
|
|
577
|
+
if(rational&&!game.enemyCanLive(0,ps[ME].c,ps[enemy].c,dest,moves[j]))continue;
|
|
578
|
+
int val=game.transition(0,ps[ME].c,ps[enemy].c,dest,moves[j]);
|
|
579
|
+
worst[d]=min(worst[d],val);average[d]+=val;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
samples+=mn;
|
|
583
|
+
}
|
|
584
|
+
for(int d=0;d<5;d++)local[place][d]=(worst[d]<0?2.0:.060)*worst[d]+.012*average[d]/max(1,samples);
|
|
585
|
+
}
|
|
586
|
+
} catch(const SearchBudget&) {return;}
|
|
587
|
+
for(int b=0;b<2;b++)for(int d=0;d<5;d++)values[b][d]+=local[b][d];
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
Decision decide(){
|
|
592
|
+
auto start=chrono::steady_clock::now();
|
|
593
|
+
collisionDeadline=start+chrono::milliseconds(6);
|
|
594
|
+
int mine=ps[ME].c;
|
|
595
|
+
if(lastRequested<4&&mine==lastOrigin){blockedCell=nb[mine][lastRequested];blockStreak++;}
|
|
596
|
+
else {blockStreak=0;blockedCell=-1;}
|
|
597
|
+
for(int i=0;i<P;i++)if(previousCell[i]>=0)for(int d=0;d<4;d++)if(nb[previousCell[i]][d]==ps[i].c)lastMove[i]=d;
|
|
598
|
+
if(T>=EXTINCTION)return {4,canBomb(ME),0};
|
|
599
|
+
Forecast normal(bombs);
|
|
600
|
+
strategy(normal);
|
|
601
|
+
double collision[2][5]{};
|
|
602
|
+
collisionGame(collision);
|
|
603
|
+
Reach enemyBase[10];
|
|
604
|
+
for(int i=0;i<P;i++)if(i!=ME&&ps[i].alive&&distme[ps[i].c]<18)enemyBase[i]=reach(normal,ps[i].c);
|
|
605
|
+
Decision best;
|
|
606
|
+
for(int place=0;place<2;place++){
|
|
607
|
+
if(place&&!canBomb(ME))continue;
|
|
608
|
+
auto bs=bombs;if(place)bs.push_back({ME,mine,T+FUSE,T});
|
|
609
|
+
Forecast f(bs);Reach own=reach(f,mine,true);
|
|
610
|
+
auto threat=threats(f);
|
|
611
|
+
double attack=0,excavate=0;
|
|
612
|
+
if(place){
|
|
613
|
+
for(int c=0;c<C;c++)if(board[c]=='+'&&f.destroyed[c]<normal.destroyed[c]){
|
|
614
|
+
excavate+=(accessibleCenter<=2?.65:2.0)+.25*max(0.,central[mine]-central[c]);
|
|
615
|
+
}
|
|
616
|
+
for(int i=0;i<P;i++)if(i!=ME&&ps[i].alive&&enemyBase[i].total){
|
|
617
|
+
Reach after=reach(f,ps[i].c);
|
|
618
|
+
if(!after.total)attack+=85;
|
|
619
|
+
else {
|
|
620
|
+
double ratio=double(after.total)/enemyBase[i].total;
|
|
621
|
+
attack+=3.2*max(0.,1-ratio);
|
|
622
|
+
int n1=__builtin_popcount((unsigned)enemyBase[i].mask),n2=__builtin_popcount((unsigned)after.mask);
|
|
623
|
+
attack+=.7*max(0,n1-n2);
|
|
624
|
+
int before=0,afterN=0;for(int d=0;d<5;d++){before=max(before,enemyBase[i].counts[min(4,f.h-1)][d]);afterN=max(afterN,after.counts[min(4,f.h-1)][d]);}
|
|
625
|
+
if(before)attack+=2.0*max(0.,1.-double(afterN)/before);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
double worstRisk[5]={},meanRisk[5]={},threatSpace[5]={};int threatN=0;
|
|
630
|
+
Forecast combined=f;
|
|
631
|
+
for(const auto &s:threat){
|
|
632
|
+
auto test=bs;test.push_back({s.id,s.c,T+s.delay+FUSE,T+s.delay});
|
|
633
|
+
Forecast sf(test);Reach r=reach(sf,mine);
|
|
634
|
+
if(aliveCount>2)for(int k=0;k<f.h;k++)for(int c=0;c<C;c++){
|
|
635
|
+
combined.safe[k][c]&=sf.safe[k][c];combined.open[k][c]&=sf.open[k][c];combined.occupied[k][c]|=sf.occupied[k][c];
|
|
636
|
+
}
|
|
637
|
+
// A suicidal enemy bomb is still considered, but receives a smaller weight.
|
|
638
|
+
double w=s.weight;
|
|
639
|
+
if(s.delay==0&&!sf.good[0][ps[s.id].c])w*=.55;
|
|
640
|
+
for(int d=0;d<5;d++){
|
|
641
|
+
double risk=r.life[d]<sf.h?(115+8*(sf.h-r.life[d]))*w:0;
|
|
642
|
+
worstRisk[d]=max(worstRisk[d],risk);meanRisk[d]+=risk;
|
|
643
|
+
threatSpace[d]+=log(1.+r.count[d]);
|
|
644
|
+
}
|
|
645
|
+
threatN++;
|
|
646
|
+
}
|
|
647
|
+
// A simultaneous volley can close two different exits even when either
|
|
648
|
+
// individual bomb is harmless.
|
|
649
|
+
auto volley=bs;int added=0;
|
|
650
|
+
for(auto s:threat)if(s.delay==0){volley.push_back({s.id,s.c,T+FUSE,T});added++;}
|
|
651
|
+
if(added>=2){Forecast sf(volley);Reach r=reach(sf,mine);for(int d=0;d<5;d++){
|
|
652
|
+
double risk=r.life[d]<sf.h?100+6*(sf.h-r.life[d]):0;
|
|
653
|
+
worstRisk[d]=max(worstRisk[d],risk);meanRisk[d]+=risk;threatSpace[d]+=log(1.+r.count[d]);
|
|
654
|
+
}threatN++;}
|
|
655
|
+
Reach robust=own;
|
|
656
|
+
if(aliveCount>2&&threatN){combined.rebuildGood();robust=reach(combined,mine);}
|
|
657
|
+
for(int d=0;d<5;d++){
|
|
658
|
+
int dest=f.dest(0,mine,d);
|
|
659
|
+
if(dest==mine&&d!=4)continue;
|
|
660
|
+
double value=own.life[d]*2000.;
|
|
661
|
+
if(own.life[d]==f.h){
|
|
662
|
+
value+=3.1*field[dest]+.55*own.utility[d];
|
|
663
|
+
value+=1.05*log(1.+own.count[d])+1.1*log(1.+own.width[d]);
|
|
664
|
+
for(int k=1;k<min(6,f.h);k++)value+=.30*log(1.+own.counts[k][d]);
|
|
665
|
+
value-=.75*visits[dest];
|
|
666
|
+
value-=(aliveCount>2?2.8:1.5)*worstRisk[d];if(threatN)value-=.20*meanRisk[d]/threatN;
|
|
667
|
+
if(threatN)value+=.50*threatSpace[d]/threatN;
|
|
668
|
+
// This envelope deliberately overestimates simultaneous future bombs.
|
|
669
|
+
// It is a soft preference, guarding against several individually harmless
|
|
670
|
+
// placements that together close all exits.
|
|
671
|
+
if(aliveCount>2&&threatN&&robust.life[d]<f.h)value-=12+2.5*(f.h-robust.life[d]);
|
|
672
|
+
if(dest==mine)value-=.25;
|
|
673
|
+
for(int k=1;k<min(5,f.h);k++)if(!f.safe[k][dest]){value-=.6*(5-k);break;}
|
|
674
|
+
value+=attack+excavate-(place?1.1:0);
|
|
675
|
+
} else {
|
|
676
|
+
// With no surviving route, retain the possibility of a last-turn trade.
|
|
677
|
+
value+=attack*5+excavate;
|
|
678
|
+
}
|
|
679
|
+
if(dest!=mine){
|
|
680
|
+
double block=0;
|
|
681
|
+
for(int i=0;i<P;i++)if(i!=ME&&ps[i].alive&&f.open[0][ps[i].c]){
|
|
682
|
+
int ec=ps[i].c;
|
|
683
|
+
bool can=false;
|
|
684
|
+
for(int ed=0;ed<5;ed++)if(f.dest(0,ec,ed)==dest){can=true;break;}
|
|
685
|
+
if(can){
|
|
686
|
+
double w=ec==dest?.6:.25;
|
|
687
|
+
if(previousCell[i]>=0&&ec!=previousCell[i]&&nb[ec][lastMove[i]]==dest)w=.65;
|
|
688
|
+
block=max(block,w);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
if(block){
|
|
692
|
+
if(own.life[4]<f.h)value-=block*(6000+2000*(f.h-own.life[4]));
|
|
693
|
+
else value-=block*(1.5+max(0.,worstRisk[4]-worstRisk[d]));
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
// Prefer destinations with independent exits over a contested cul-de-sac.
|
|
697
|
+
if(enemyDist[dest]<=4&°ree[dest]<2)value-=4;
|
|
698
|
+
value-=tunnelRisk[dest]*(aliveCount>2?1.0:.55);
|
|
699
|
+
if(dest==blockedCell&&blockStreak){
|
|
700
|
+
value-=4+min(5,blockStreak)*1.5;
|
|
701
|
+
value-=2.5*max(0.,field[dest]-field[mine]);
|
|
702
|
+
}
|
|
703
|
+
value+=collision[place][d];
|
|
704
|
+
value+=.055*noise();
|
|
705
|
+
if(value>best.val)best={d,place,value};
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if(aliveCount==2){
|
|
709
|
+
int spaces=0,enemy=-1;for(int c=0;c<C;c++)spaces+=board[c]!='#';
|
|
710
|
+
for(int i=0;i<P;i++)if(i!=ME&&ps[i].alive)enemy=i;
|
|
711
|
+
bool clean=true;for(auto b:bombs)if(b.owner!=ME&&b.owner!=enemy)clean=false;
|
|
712
|
+
for(auto s:sources)if(s.end>=T&&s.owner!=ME&&s.owner!=enemy)clean=false;
|
|
713
|
+
if(spaces<=32&&clean&&chrono::steady_clock::now()<start+chrono::milliseconds(12)){
|
|
714
|
+
Small::Solver solver(enemy,start+chrono::milliseconds(18));best=solver.choose(best);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
for(int i=0;i<P;i++)previousCell[i]=ps[i].c;
|
|
718
|
+
lastOrigin=mine;lastRequested=best.d;
|
|
719
|
+
return best;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
bool readState(){
|
|
723
|
+
string w;if(!(cin>>w>>T))return false;
|
|
724
|
+
cin>>w;string row;for(int y=0;y<N;y++){cin>>row;for(int x=0;x<N;x++)board[y*N+x]=row[x];}
|
|
725
|
+
for(int i=0;i<P;i++){int id,x,y,a;cin>>w>>id>>x>>y>>a;ps[id].c=y*N+x;ps[id].alive=a;}
|
|
726
|
+
int k;cin>>w>>k;bombs.resize(k);for(auto &b:bombs){int x,y;cin>>w>>b.owner>>x>>y>>b.at;b.c=y*N+x;b.born=T-1;}
|
|
727
|
+
cin>>w>>k;flames.resize(k);for(auto &f:flames){int x,y;cin>>w>>x>>y>>f.end;f.c=y*N+x;}
|
|
728
|
+
while(cin>>w){
|
|
729
|
+
if(w=="END")return true;
|
|
730
|
+
if(w=="STATUS"){cin>>k;for(int i=0;i<k;i++){int id,a,b;cin>>w>>id>>ps[id].death>>a>>b;ps[id].kills=double(a)/b;}}
|
|
731
|
+
else if(w=="SOURCES"){cin>>k;sources.resize(k);for(auto &s:sources){int x,y;cin>>w>>x>>y>>s.owner>>s.end;s.c=y*N+x;}}
|
|
732
|
+
else {string rest;getline(cin,rest);}
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
int main(int argc,char**argv){
|
|
737
|
+
ios::sync_with_stdio(false);cin.tie(nullptr);
|
|
738
|
+
string w;if(!(cin>>w>>N>>P>>ME>>LIMIT>>FUSE>>RANGE>>CAP>>FIRE>>SHRINK>>EVERY))return 0;
|
|
739
|
+
if(N<3||N>25||P<2||P>10||ME<0||ME>=P)return 0;
|
|
740
|
+
C=N*N;ps.resize(P);fill(previousCell,previousCell+10,-1);fill(lastMove,lastMove+10,4);
|
|
741
|
+
for(int y=0;y<N;y++)for(int x=0;x<N;x++){
|
|
742
|
+
int c=y*N+x;edge[c]=min({x,y,N-1-x,N-1-y});collapse[c]=edge[c]?SHRINK+(edge[c]-1)*EVERY:0;
|
|
743
|
+
nb[c][0]=y?c-N:-1;nb[c][1]=y+1<N?c+N:-1;nb[c][2]=x?c-1:-1;nb[c][3]=x+1<N?c+1:-1;nb[c][4]=c;
|
|
744
|
+
}
|
|
745
|
+
rng^=(uint64_t)(ME+1)*0x9e3779b97f4a7c15ULL;
|
|
746
|
+
int deepest=N/2;if(deepest%2==0)deepest--;
|
|
747
|
+
EXTINCTION=min(LIMIT,SHRINK+(deepest-1)*EVERY);
|
|
748
|
+
while(readState()){
|
|
749
|
+
if(argc>1&&string(argv[1])=="--forecast-sources"){
|
|
750
|
+
Forecast f(bombs,7,true);for(int k=0;k<f.h;k++){for(int c=0;c<C;c++)cout<<f.owners[k][c]<<' ';cout<<'\n';}cout.flush();
|
|
751
|
+
}else if(argc>1&&string(argv[1])=="--forecast-check"){
|
|
752
|
+
Forecast f(bombs,7);for(int k=0;k<f.h;k++){for(int c=0;c<C;c++)cout<<int(f.safe[k][c]);cout<<'\n';}cout.flush();
|
|
753
|
+
}else if(argc>1&&string(argv[1])=="--small-check"){
|
|
754
|
+
int e=ME^1;Small::Solver solver(e,chrono::steady_clock::now());
|
|
755
|
+
for(int a=0;a<10;a++)for(int b=0;b<10;b++){
|
|
756
|
+
auto s=solver.step(solver.initial,a,b);
|
|
757
|
+
cout<<a<<' '<<b<<' '<<solver.cells[s.pos[0]]<<' '<<solver.cells[s.pos[1]]<<' '<<s.result<<' ';
|
|
758
|
+
for(int c=0;c<C;c++){int i=solver.index[c];char v=board[c];if(collapse[c]<=T)v='#';else if(i>=0)v=(s.crates&solver.bits[i])?'+':'.';cout<<v;}
|
|
759
|
+
int count=0;for(auto &owner:s.bomb)for(auto v:owner)count+=__builtin_popcountll(v);cout<<' '<<count;
|
|
760
|
+
for(int p=0;p<2;p++)for(int t=0;t<5;t++){auto v=s.bomb[p][t];while(v){int i=__builtin_ctzll(v);v&=v-1;cout<<' '<<(p?e:ME)<<' '<<solver.cells[i]<<' '<<T+1+t;}}
|
|
761
|
+
for(int p=0;p<2;p++){auto v=s.fire[p];cout<<' '<<__builtin_popcountll(v);while(v){int i=__builtin_ctzll(v);v&=v-1;cout<<' '<<solver.cells[i];}}
|
|
762
|
+
cout<<'\n';
|
|
763
|
+
}cout.flush();
|
|
764
|
+
}else {auto a=decide();cout<<T<<' '<<DIR[a.d]<<' '<<a.b<<'\n'<<flush;}
|
|
765
|
+
}
|
|
766
|
+
return 0;
|
|
767
|
+
}
|
|
768
|
+
|