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