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.
- package/README.md +91 -13
- package/assets/commit0/instance.json +30 -0
- package/assets/commit0/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/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,634 @@
|
|
|
1
|
+
// 多阵营夺旗 bot
|
|
2
|
+
// 思路:全图预计算最短路;每回合预测敌人下一步分布;用带危险权重的 Dijkstra 规划路线;
|
|
3
|
+
// 枚举 3 个角色的任务组合(取旗/回家/截杀携旗者/护送/猎杀/巡游)取总价值最大;
|
|
4
|
+
// 最后按预测命中概率选攻击目标并集火。
|
|
5
|
+
#include <bits/stdc++.h>
|
|
6
|
+
using namespace std;
|
|
7
|
+
|
|
8
|
+
struct Unit { int id, team, x, y, hp, flag, respawn_at; };
|
|
9
|
+
struct Flag { int id; string status; int x, y, holder, return_at; };
|
|
10
|
+
struct Event { string type; vector<int> args; };
|
|
11
|
+
|
|
12
|
+
struct Game {
|
|
13
|
+
int teams = 0, me = 0, size = 0, turns = 0, hp = 0, damage = 0, respawn = 0, flag_return = 0, flag_cooldown = 0;
|
|
14
|
+
vector<string> map;
|
|
15
|
+
vector<pair<int, int>> bases;
|
|
16
|
+
vector<pair<int, int>> spots;
|
|
17
|
+
int turn = 0;
|
|
18
|
+
vector<int> score;
|
|
19
|
+
vector<Unit> units;
|
|
20
|
+
vector<Flag> flags;
|
|
21
|
+
vector<Event> events;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
bool read_turn(Game& g) {
|
|
25
|
+
string w;
|
|
26
|
+
while (cin >> w) {
|
|
27
|
+
if (w == "INIT") {
|
|
28
|
+
cin >> g.teams >> g.me >> g.size >> g.turns >> g.hp >> g.damage >> g.respawn >> g.flag_return >> g.flag_cooldown;
|
|
29
|
+
} else if (w == "MAP") {
|
|
30
|
+
g.map.assign(g.size, "");
|
|
31
|
+
for (auto& row : g.map) cin >> row;
|
|
32
|
+
} else if (w == "BASES") {
|
|
33
|
+
int k; cin >> k; g.bases.resize(k);
|
|
34
|
+
for (auto& b : g.bases) cin >> b.first >> b.second;
|
|
35
|
+
} else if (w == "SPOTS") {
|
|
36
|
+
int k; cin >> k; g.spots.resize(k);
|
|
37
|
+
for (auto& s : g.spots) cin >> s.first >> s.second;
|
|
38
|
+
} else if (w == "TURN") {
|
|
39
|
+
cin >> g.turn;
|
|
40
|
+
} else if (w == "SCORE") {
|
|
41
|
+
g.score.resize(g.teams);
|
|
42
|
+
for (auto& s : g.score) cin >> s;
|
|
43
|
+
} else if (w == "UNITS") {
|
|
44
|
+
int k; cin >> k; g.units.resize(k);
|
|
45
|
+
for (auto& u : g.units) { string tag; cin >> tag >> u.id >> u.team >> u.x >> u.y >> u.hp >> u.flag >> u.respawn_at; }
|
|
46
|
+
} else if (w == "FLAGS") {
|
|
47
|
+
int k; cin >> k; g.flags.resize(k);
|
|
48
|
+
for (auto& f : g.flags) { string tag; cin >> tag >> f.id >> f.status >> f.x >> f.y >> f.holder >> f.return_at; }
|
|
49
|
+
} else if (w == "EVENTS") {
|
|
50
|
+
int k; cin >> k; g.events.assign(k, {});
|
|
51
|
+
string line; getline(cin, line);
|
|
52
|
+
for (auto& e : g.events) {
|
|
53
|
+
getline(cin, line);
|
|
54
|
+
istringstream in(line);
|
|
55
|
+
string tag; in >> tag >> e.type;
|
|
56
|
+
for (int v; in >> v;) e.args.push_back(v);
|
|
57
|
+
}
|
|
58
|
+
} else if (w == "END") {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------- 预计算 ----------------
|
|
66
|
+
static int N = 0, NN = 0;
|
|
67
|
+
static vector<char> W; // 墙
|
|
68
|
+
static vector<int16_t> Dall; // 全图两两最短路
|
|
69
|
+
static bool pre = false;
|
|
70
|
+
static const int INF = 9999;
|
|
71
|
+
static const int DX[5] = {0, 0, 0, -1, 1}, DY[5] = {0, -1, 1, 0, 0};
|
|
72
|
+
static const char MVC[5] = {'S', 'U', 'D', 'L', 'R'};
|
|
73
|
+
|
|
74
|
+
inline int cid(int x, int y) { return y * N + x; }
|
|
75
|
+
inline int cx(int c) { return c % N; }
|
|
76
|
+
inline int cy(int c) { return c / N; }
|
|
77
|
+
inline int D(int a, int b) { if (a < 0 || b < 0) return INF; return Dall[(size_t)a * NN + b]; }
|
|
78
|
+
inline int manh(int a, int b) { return abs(cx(a) - cx(b)) + abs(cy(a) - cy(b)); }
|
|
79
|
+
|
|
80
|
+
void precompute(const Game& g) {
|
|
81
|
+
N = g.size; NN = N * N; W.assign(NN, 0);
|
|
82
|
+
for (int y = 0; y < N; y++) for (int x = 0; x < N; x++) W[cid(x, y)] = (g.map[y][x] == '#');
|
|
83
|
+
Dall.assign((size_t)NN * NN, INF);
|
|
84
|
+
vector<int> q(NN);
|
|
85
|
+
for (int s = 0; s < NN; s++) {
|
|
86
|
+
if (W[s]) continue;
|
|
87
|
+
int16_t* d = &Dall[(size_t)s * NN];
|
|
88
|
+
int h = 0, t = 0; q[t++] = s; d[s] = 0;
|
|
89
|
+
while (h < t) {
|
|
90
|
+
int c = q[h++]; int x = cx(c), y = cy(c);
|
|
91
|
+
for (int k = 1; k < 5; k++) {
|
|
92
|
+
int nx = x + DX[k], ny = y + DY[k];
|
|
93
|
+
if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
|
|
94
|
+
int nc = cid(nx, ny);
|
|
95
|
+
if (W[nc] || d[nc] != INF) continue;
|
|
96
|
+
d[nc] = d[c] + 1; q[t++] = nc;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
pre = true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
bool canAtk(int a, int b) {
|
|
104
|
+
if (a < 0 || b < 0) return false;
|
|
105
|
+
int ax = cx(a), ay = cy(a), bx = cx(b), by = cy(b);
|
|
106
|
+
int dx = bx - ax, dy = by - ay;
|
|
107
|
+
int md = abs(dx) + abs(dy);
|
|
108
|
+
if (md > 2) return false;
|
|
109
|
+
if (abs(dx) == 2 && dy == 0) return !W[cid(ax + dx / 2, ay)];
|
|
110
|
+
if (abs(dy) == 2 && dx == 0) return !W[cid(ax, ay + dy / 2)];
|
|
111
|
+
if (abs(dx) == 1 && abs(dy) == 1) return !W[cid(ax + dx, ay)] || !W[cid(ax, ay + dy)];
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ---------------- 每回合状态 ----------------
|
|
116
|
+
struct EInfo {
|
|
117
|
+
int id, team, cell, hp, flag; bool immune;
|
|
118
|
+
vector<pair<int, double>> pred; double pStay;
|
|
119
|
+
};
|
|
120
|
+
struct MU { int id, cell, hp, flag; bool alive, spawning, canAtk; };
|
|
121
|
+
struct Task { int type; int key; int target; double val; int eta; int hits; };
|
|
122
|
+
// type: 0 RETURN, 1 GET, 2 INTERCEPT, 3 ESCORT, 4 HUNT, 5 ROAM, -1 NONE
|
|
123
|
+
|
|
124
|
+
static double LAMBDA = 2.5;
|
|
125
|
+
inline int lives(int hp, int dmg) { return hp <= 0 ? 0 : (hp + dmg - 1) / dmg; }
|
|
126
|
+
|
|
127
|
+
string decide(const Game& g) {
|
|
128
|
+
if (!pre) precompute(g);
|
|
129
|
+
const int me = g.me, T = g.turn, nTeams = g.teams;
|
|
130
|
+
const int remaining = g.turns - T + 1;
|
|
131
|
+
const int centerCell = cid(N / 2, N / 2);
|
|
132
|
+
LAMBDA = (nTeams == 2) ? 3.0 : (nTeams <= 5) ? 1.5 : 0.8;
|
|
133
|
+
|
|
134
|
+
auto baseCells = [&](int team) {
|
|
135
|
+
vector<int> v; auto [bx, by] = g.bases[team];
|
|
136
|
+
for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) v.push_back(cid(bx + dx, by + dy));
|
|
137
|
+
return v;
|
|
138
|
+
};
|
|
139
|
+
vector<vector<int>> bcells(nTeams);
|
|
140
|
+
for (int t = 0; t < nTeams; t++) bcells[t] = baseCells(t);
|
|
141
|
+
auto distToBase = [&](int c, int team) {
|
|
142
|
+
int best = INF; for (int b : bcells[team]) best = min(best, D(c, b)); return best;
|
|
143
|
+
};
|
|
144
|
+
auto nearestBaseCell = [&](int c, int team) {
|
|
145
|
+
int best = INF, bc = bcells[team][4];
|
|
146
|
+
for (int b : bcells[team]) if (D(c, b) < best) { best = D(c, b); bc = b; }
|
|
147
|
+
return bc;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// 占用
|
|
151
|
+
vector<int> occ(NN, -1);
|
|
152
|
+
for (auto& u : g.units) if (u.x >= 0) occ[cid(u.x, u.y)] = u.id;
|
|
153
|
+
|
|
154
|
+
// 我方重生顺序
|
|
155
|
+
vector<int> spawnOrder = bcells[me];
|
|
156
|
+
{
|
|
157
|
+
auto [bx, by] = g.bases[me];
|
|
158
|
+
sort(spawnOrder.begin(), spawnOrder.end(), [&](int a, int b) {
|
|
159
|
+
int da = manh(a, centerCell), db = manh(b, centerCell);
|
|
160
|
+
if (da != db) return da < db;
|
|
161
|
+
int ka = abs(cx(a) - bx) + 2 * abs(cy(a) - by), kb = abs(cx(b) - bx) + 2 * abs(cy(b) - by);
|
|
162
|
+
return ka < kb;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 我方角色
|
|
167
|
+
vector<MU> M(3);
|
|
168
|
+
for (int k = 0; k < 3; k++) {
|
|
169
|
+
int uid = 3 * me + k; const Unit* u = nullptr;
|
|
170
|
+
for (auto& x : g.units) if (x.id == uid) u = &x;
|
|
171
|
+
MU m; m.id = uid; m.cell = -1; m.hp = 0; m.flag = -1; m.alive = false; m.spawning = false; m.canAtk = false;
|
|
172
|
+
if (u) {
|
|
173
|
+
if (u->x >= 0) { m.cell = cid(u->x, u->y); m.hp = u->hp; m.flag = u->flag; m.alive = true; m.canAtk = (u->flag < 0); }
|
|
174
|
+
else if (u->respawn_at == T) {
|
|
175
|
+
for (int c : spawnOrder) if (occ[c] < 0) { m.cell = c; occ[c] = uid; break; }
|
|
176
|
+
if (m.cell >= 0) { m.alive = true; m.spawning = true; m.hp = g.hp; m.canAtk = false; }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
M[k] = m;
|
|
180
|
+
}
|
|
181
|
+
int myCarrierIdx = -1;
|
|
182
|
+
for (int k = 0; k < 3; k++) if (M[k].alive && M[k].flag >= 0) myCarrierIdx = k;
|
|
183
|
+
|
|
184
|
+
// 敌人
|
|
185
|
+
vector<EInfo> E;
|
|
186
|
+
for (auto& u : g.units) {
|
|
187
|
+
if (u.team == me) continue;
|
|
188
|
+
EInfo e; e.id = u.id; e.team = u.team; e.hp = u.hp; e.flag = u.flag; e.immune = false; e.pStay = 1;
|
|
189
|
+
if (u.x >= 0) e.cell = cid(u.x, u.y);
|
|
190
|
+
else if (u.respawn_at == T) { e.cell = bcells[u.team][4]; e.immune = true; e.hp = g.hp; }
|
|
191
|
+
else continue;
|
|
192
|
+
E.push_back(e);
|
|
193
|
+
}
|
|
194
|
+
// 可用旗子
|
|
195
|
+
vector<int> flagCell(g.flags.size(), -1);
|
|
196
|
+
vector<char> flagAvail(g.flags.size(), 0);
|
|
197
|
+
for (size_t i = 0; i < g.flags.size(); i++) {
|
|
198
|
+
auto& f = g.flags[i];
|
|
199
|
+
if ((f.status == "home" || f.status == "dropped") && f.x >= 0) { flagCell[i] = cid(f.x, f.y); flagAvail[i] = 1; }
|
|
200
|
+
}
|
|
201
|
+
vector<int> myCells;
|
|
202
|
+
for (auto& m : M) if (m.alive) myCells.push_back(m.cell);
|
|
203
|
+
|
|
204
|
+
// 威胁图
|
|
205
|
+
vector<int> thr(NN, 0);
|
|
206
|
+
for (auto& e : E) {
|
|
207
|
+
if (e.immune || e.flag >= 0) continue;
|
|
208
|
+
int ex = cx(e.cell), ey = cy(e.cell);
|
|
209
|
+
for (int dy = -3; dy <= 3; dy++) for (int dx = -3; dx <= 3; dx++) {
|
|
210
|
+
if (abs(dx) + abs(dy) > 3) continue;
|
|
211
|
+
int x = ex + dx, y = ey + dy;
|
|
212
|
+
if (x < 0 || y < 0 || x >= N || y >= N) continue;
|
|
213
|
+
thr[cid(x, y)]++;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 敌人下一步预测
|
|
218
|
+
for (auto& e : E) {
|
|
219
|
+
e.pred.clear();
|
|
220
|
+
if (e.immune) { e.pred.push_back({e.cell, 1.0}); e.pStay = 1.0; continue; }
|
|
221
|
+
vector<pair<int, double>> cand;
|
|
222
|
+
int x = cx(e.cell), y = cy(e.cell);
|
|
223
|
+
int goal = -1, curG = INF;
|
|
224
|
+
int myNear = -1, curM = INF;
|
|
225
|
+
if (e.flag >= 0) {
|
|
226
|
+
goal = nearestBaseCell(e.cell, e.team); curG = D(e.cell, goal);
|
|
227
|
+
} else {
|
|
228
|
+
for (size_t i = 0; i < g.flags.size(); i++) if (flagAvail[i]) { int d = D(e.cell, flagCell[i]); if (d < curG) { curG = d; goal = flagCell[i]; } }
|
|
229
|
+
for (int c : myCells) { int d = D(e.cell, c); if (d < curM) { curM = d; myNear = c; } }
|
|
230
|
+
}
|
|
231
|
+
double tot = 0;
|
|
232
|
+
for (int k = 0; k < 5; k++) {
|
|
233
|
+
int nx = x + DX[k], ny = y + DY[k];
|
|
234
|
+
if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
|
|
235
|
+
int nc = cid(nx, ny);
|
|
236
|
+
if (W[nc]) continue;
|
|
237
|
+
double w;
|
|
238
|
+
if (e.flag >= 0) {
|
|
239
|
+
w = (k == 0) ? 0.5 : ((D(nc, goal) < curG) ? 5.0 : 0.4);
|
|
240
|
+
} else {
|
|
241
|
+
w = (k == 0) ? 1.2 : 1.0;
|
|
242
|
+
if (goal >= 0 && k != 0 && D(nc, goal) < curG) w += 2.0;
|
|
243
|
+
if (myNear >= 0 && curM <= 4 && k != 0 && D(nc, myNear) < curM) w += 1.5;
|
|
244
|
+
if (k != 0 && occ[nc] >= 0) w *= 0.3; // 有人占着,进不去
|
|
245
|
+
}
|
|
246
|
+
cand.push_back({nc, w}); tot += w;
|
|
247
|
+
}
|
|
248
|
+
e.pStay = 0;
|
|
249
|
+
for (auto& c : cand) { c.second /= tot; if (c.first == e.cell) e.pStay = c.second; }
|
|
250
|
+
e.pred = cand;
|
|
251
|
+
}
|
|
252
|
+
auto pRange = [&](int c, const EInfo& e) {
|
|
253
|
+
double p = 0; for (auto& q : e.pred) if (canAtk(c, q.first)) p += q.second; return p;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// 带危险权重的 Dijkstra(多源,返回到目标集合的代价,单位 10 = 一步)
|
|
257
|
+
auto ctgTo = [&](const vector<int>& targets, int K10) {
|
|
258
|
+
vector<int> cost(NN, INT_MAX);
|
|
259
|
+
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
|
|
260
|
+
for (int t : targets) if (t >= 0 && !W[t]) { cost[t] = 0; pq.push({0, t}); }
|
|
261
|
+
while (!pq.empty()) {
|
|
262
|
+
auto [d, c] = pq.top(); pq.pop();
|
|
263
|
+
if (d > cost[c]) continue;
|
|
264
|
+
int x = cx(c), y = cy(c);
|
|
265
|
+
for (int k = 1; k < 5; k++) {
|
|
266
|
+
int nx = x + DX[k], ny = y + DY[k];
|
|
267
|
+
if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
|
|
268
|
+
int nc = cid(nx, ny);
|
|
269
|
+
if (W[nc]) continue;
|
|
270
|
+
int step = 10 + K10 * thr[nc];
|
|
271
|
+
if (occ[nc] >= 0 && occ[nc] / 3 != me) step += 25;
|
|
272
|
+
int nd = d + step;
|
|
273
|
+
if (nd < cost[nc]) { cost[nc] = nd; pq.push({nd, nc}); }
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return cost;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// ---------------- 任务生成 ----------------
|
|
280
|
+
vector<vector<Task>> tasks(3);
|
|
281
|
+
// 敌方携旗者回家路径
|
|
282
|
+
map<int, vector<int>> epath; // enemy id -> path cells (excluding current)
|
|
283
|
+
for (auto& e : E) {
|
|
284
|
+
if (e.flag < 0 || e.immune) continue;
|
|
285
|
+
int tb = nearestBaseCell(e.cell, e.team);
|
|
286
|
+
vector<int> path; int c = e.cell; int guard = 0;
|
|
287
|
+
while (c != tb && guard++ < 200) {
|
|
288
|
+
int x = cx(c), y = cy(c); int nxt = -1;
|
|
289
|
+
for (int k = 1; k < 5; k++) {
|
|
290
|
+
int nx = x + DX[k], ny = y + DY[k];
|
|
291
|
+
if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
|
|
292
|
+
int nc = cid(nx, ny);
|
|
293
|
+
if (W[nc]) continue;
|
|
294
|
+
if (D(nc, tb) == D(c, tb) - 1) { nxt = nc; break; }
|
|
295
|
+
}
|
|
296
|
+
if (nxt < 0) break;
|
|
297
|
+
c = nxt; path.push_back(c);
|
|
298
|
+
}
|
|
299
|
+
epath[e.id] = path;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (int k = 0; k < 3; k++) {
|
|
303
|
+
auto& m = M[k];
|
|
304
|
+
if (!m.alive) { tasks[k].push_back({-1, 0, -1, 0, 0, 0}); continue; }
|
|
305
|
+
if (m.flag >= 0) { tasks[k].push_back({0, 0, -1, 1000, 0, 0}); continue; }
|
|
306
|
+
// GET
|
|
307
|
+
for (size_t i = 0; i < g.flags.size(); i++) {
|
|
308
|
+
if (!flagAvail[i]) continue;
|
|
309
|
+
int fc = flagCell[i];
|
|
310
|
+
int eta = D(m.cell, fc); if (eta >= INF) continue;
|
|
311
|
+
if (g.flags[i].status == "dropped" && g.flags[i].return_at >= 0 && eta > g.flags[i].return_at - T) continue;
|
|
312
|
+
int ret = distToBase(fc, me); if (ret >= INF) continue;
|
|
313
|
+
if (eta + ret > remaining) continue;
|
|
314
|
+
int eEta = INF, nearEnemies = 0;
|
|
315
|
+
for (auto& e : E) {
|
|
316
|
+
if (e.flag >= 0) continue;
|
|
317
|
+
int d = D(e.cell, fc) + (e.immune ? 1 : 0);
|
|
318
|
+
eEta = min(eEta, d);
|
|
319
|
+
if (!e.immune && d <= 5) nearEnemies++;
|
|
320
|
+
}
|
|
321
|
+
double pget;
|
|
322
|
+
if (eta + 2 < eEta) pget = 0.97; else if (eta < eEta) pget = 0.85; else if (eta == eEta) pget = 0.45;
|
|
323
|
+
else if (eta == eEta + 1) pget = 0.25; else pget = 0.1;
|
|
324
|
+
if (nTeams >= 3) pget = max(pget, eta < eEta ? 0.9 : eta == eEta ? 0.55 : eta <= eEta + 2 ? 0.35 : 0.2);
|
|
325
|
+
int corridor = 0;
|
|
326
|
+
for (auto& e : E) if (!e.immune && e.flag < 0 && D(e.cell, fc) + distToBase(e.cell, me) <= ret + 4) corridor++;
|
|
327
|
+
double pret = 0.95 - 0.12 * min(3, nearEnemies) - 0.08 * min(4, corridor);
|
|
328
|
+
double val = 100.0 * pget * pret - LAMBDA * (eta + ret);
|
|
329
|
+
val += 6.0 * (lives(m.hp, g.damage) - 1);
|
|
330
|
+
if (lives(m.hp, g.damage) == 1) {
|
|
331
|
+
bool healthyNear = false;
|
|
332
|
+
for (int j = 0; j < 3; j++) if (j != k && M[j].alive && M[j].flag < 0 && lives(M[j].hp, g.damage) >= 2 && D(M[j].cell, fc) <= eta + 2) healthyNear = true;
|
|
333
|
+
if (healthyNear) val -= 60;
|
|
334
|
+
}
|
|
335
|
+
bool contested = (eEta <= eta + 3);
|
|
336
|
+
tasks[k].push_back({1, (int)i, fc, val, eta, contested ? 1 : 0});
|
|
337
|
+
}
|
|
338
|
+
// INTERCEPT
|
|
339
|
+
for (auto& e : E) {
|
|
340
|
+
if (e.flag < 0 || e.immune) continue;
|
|
341
|
+
auto& path = epath[e.id];
|
|
342
|
+
int L = (int)path.size();
|
|
343
|
+
if (L == 0) continue;
|
|
344
|
+
int tfirst = -1;
|
|
345
|
+
for (int t = 1; t <= L; t++) {
|
|
346
|
+
int q = path[t - 1]; int qx = cx(q), qy = cy(q); bool ok = false;
|
|
347
|
+
for (int dy = -2; dy <= 2 && !ok; dy++) for (int dx = -2; dx <= 2 && !ok; dx++) {
|
|
348
|
+
if (abs(dx) + abs(dy) > 2 || (dx == 0 && dy == 0)) continue;
|
|
349
|
+
int x = qx + dx, y = qy + dy;
|
|
350
|
+
if (x < 0 || y < 0 || x >= N || y >= N) continue;
|
|
351
|
+
int qq = cid(x, y);
|
|
352
|
+
if (W[qq]) continue;
|
|
353
|
+
if (!canAtk(qq, q)) continue;
|
|
354
|
+
if (D(m.cell, qq) <= t) ok = true;
|
|
355
|
+
}
|
|
356
|
+
if (ok) { tfirst = t; break; }
|
|
357
|
+
}
|
|
358
|
+
if (tfirst < 0) continue;
|
|
359
|
+
if (nTeams >= 6 && tfirst > 6) continue;
|
|
360
|
+
if (nTeams >= 3 && nTeams < 6 && tfirst > 12) continue;
|
|
361
|
+
int hits = L - tfirst + 1;
|
|
362
|
+
int target = (tfirst <= 1) ? e.cell : path[tfirst - 1];
|
|
363
|
+
tasks[k].push_back({2, e.id, target, 0, tfirst, hits});
|
|
364
|
+
}
|
|
365
|
+
// ESCORT
|
|
366
|
+
if (myCarrierIdx >= 0 && myCarrierIdx != k) {
|
|
367
|
+
auto& c = M[myCarrierIdx];
|
|
368
|
+
int threats = 0;
|
|
369
|
+
for (auto& e : E) if (!e.immune && e.flag < 0 && D(e.cell, c.cell) <= 5) threats++;
|
|
370
|
+
int d = D(m.cell, c.cell);
|
|
371
|
+
double val = 12 + 22 * min(3, threats) - LAMBDA * 0.5 * d;
|
|
372
|
+
if (threats == 0 && d > 6) val = 2;
|
|
373
|
+
if (nTeams >= 3) val = 40 + 22 * min(3, threats) - LAMBDA * 0.5 * d;
|
|
374
|
+
tasks[k].push_back({3, myCarrierIdx, c.cell, val, d, 0});
|
|
375
|
+
}
|
|
376
|
+
// HUNT
|
|
377
|
+
for (auto& e : E) {
|
|
378
|
+
if (e.immune || e.flag >= 0) continue;
|
|
379
|
+
int d = D(m.cell, e.cell);
|
|
380
|
+
if (d > 7) continue;
|
|
381
|
+
int support = 0, mysup = 0;
|
|
382
|
+
for (auto& e2 : E) if (e2.id != e.id && !e2.immune && e2.flag < 0 && D(e2.cell, e.cell) <= 3) support++;
|
|
383
|
+
for (int j = 0; j < 3; j++) if (j != k && M[j].alive && M[j].canAtk && D(M[j].cell, e.cell) <= 4) mysup++;
|
|
384
|
+
double val = (nTeams == 2 ? 30 : 8) - LAMBDA * d + (e.hp <= 68 ? 12 : 0) + (e.hp <= 34 ? 12 : 0) - 18 * support + 12 * mysup;
|
|
385
|
+
if (nTeams > 2 && d > 4) continue;
|
|
386
|
+
if (nTeams >= 6 && !(d <= 2 && lives(e.hp, g.damage) <= 2)) continue;
|
|
387
|
+
if (lives(m.hp, g.damage) == 1 && lives(e.hp, g.damage) >= 2 && mysup == 0) continue;
|
|
388
|
+
if (lives(m.hp, g.damage) < lives(e.hp, g.damage) && mysup == 0) val -= 15;
|
|
389
|
+
if (val <= 0) continue;
|
|
390
|
+
tasks[k].push_back({4, e.id, e.cell, val, d, 0});
|
|
391
|
+
}
|
|
392
|
+
// ROAM:去空旗点等旗(优先自家旗点、中心)
|
|
393
|
+
{
|
|
394
|
+
int bestSpot = -1; double bestV = -1e9;
|
|
395
|
+
vector<pair<double, int>> roams;
|
|
396
|
+
for (size_t i = 0; i < g.spots.size(); i++) {
|
|
397
|
+
int sc = cid(g.spots[i].first, g.spots[i].second);
|
|
398
|
+
bool taken = false;
|
|
399
|
+
for (size_t f = 0; f < g.flags.size(); f++) if (flagAvail[f] && flagCell[f] == sc) taken = true;
|
|
400
|
+
if (taken) continue;
|
|
401
|
+
int d = D(m.cell, sc); if (d >= INF) continue;
|
|
402
|
+
double v = 6 - 0.35 * d;
|
|
403
|
+
for (auto& f : g.flags) if (f.status == "cooldown" && f.return_at >= 0) {
|
|
404
|
+
int wait = max(d, f.return_at - T);
|
|
405
|
+
v += max(0.0, 0.25 * (30.0 - LAMBDA * (wait + D(sc, bcells[me][4]))));
|
|
406
|
+
}
|
|
407
|
+
if ((int)i == me) v += (nTeams >= 6 ? 7 : 3);
|
|
408
|
+
if (sc == centerCell) v += (nTeams >= 3 && nTeams <= 5) ? 5.0 : 2.5;
|
|
409
|
+
v -= 1.5 * thr[sc];
|
|
410
|
+
roams.push_back({v, sc});
|
|
411
|
+
if (v > bestV) { bestV = v; bestSpot = sc; }
|
|
412
|
+
}
|
|
413
|
+
sort(roams.rbegin(), roams.rend());
|
|
414
|
+
for (size_t i = 0; i < roams.size() && i < 3; i++) tasks[k].push_back({5, roams[i].second, roams[i].second, max(1.0, roams[i].first), 0, 0});
|
|
415
|
+
if (roams.empty()) tasks[k].push_back({5, bcells[me][4], bcells[me][4], 1.0, 0, 0});
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// ---------------- 任务组合枚举 ----------------
|
|
420
|
+
auto evalCombo = [&](const array<int, 3>& idx) {
|
|
421
|
+
double total = 0;
|
|
422
|
+
// GET 同旗
|
|
423
|
+
vector<pair<int, int>> gets; // (eta, k)
|
|
424
|
+
for (int k = 0; k < 3; k++) { auto& t = tasks[k][idx[k]]; if (t.type == 1) gets.push_back({t.eta, k}); }
|
|
425
|
+
sort(gets.begin(), gets.end());
|
|
426
|
+
map<int, int> cnt;
|
|
427
|
+
for (auto& [eta, k] : gets) {
|
|
428
|
+
auto& t = tasks[k][idx[k]];
|
|
429
|
+
int c = cnt[t.key]++;
|
|
430
|
+
double f = 1.0;
|
|
431
|
+
if (c == 1) f = t.hits ? 0.6 : (nTeams >= 3 ? 0.55 : 0.15);
|
|
432
|
+
if (c >= 2) f = t.hits ? 0.35 : (nTeams >= 3 ? 0.4 : 0.03);
|
|
433
|
+
total += t.val * f;
|
|
434
|
+
}
|
|
435
|
+
// INTERCEPT
|
|
436
|
+
map<int, vector<int>> inter;
|
|
437
|
+
for (int k = 0; k < 3; k++) { auto& t = tasks[k][idx[k]]; if (t.type == 2) inter[t.key].push_back(k); }
|
|
438
|
+
for (auto& [eid, ks] : inter) {
|
|
439
|
+
const EInfo* e = nullptr; for (auto& x : E) if (x.id == eid) e = &x;
|
|
440
|
+
int hits = 0, tfirst = INF; double tcost = 0;
|
|
441
|
+
for (int k : ks) { auto& t = tasks[k][idx[k]]; hits += t.hits; tfirst = min(tfirst, t.eta); tcost += LAMBDA * t.eta; }
|
|
442
|
+
int needed = (e->hp + g.damage - 1) / g.damage;
|
|
443
|
+
double deny = (nTeams == 2) ? 0.9 : 0.55;
|
|
444
|
+
if (hits >= needed) total += 100.0 * (deny + 0.45) * 0.85 - tcost;
|
|
445
|
+
else total += 15.0 * hits / needed - tcost;
|
|
446
|
+
}
|
|
447
|
+
// ESCORT
|
|
448
|
+
int esc = 0;
|
|
449
|
+
for (int k = 0; k < 3; k++) { auto& t = tasks[k][idx[k]]; if (t.type == 3) { total += t.val * (esc == 0 ? 1.0 : 0.4); esc++; } }
|
|
450
|
+
// HUNT
|
|
451
|
+
map<int, int> hcnt;
|
|
452
|
+
for (int k = 0; k < 3; k++) { auto& t = tasks[k][idx[k]]; if (t.type == 4) { int c = hcnt[t.key]++; total += t.val * (c == 0 ? 1.0 : c == 1 ? 0.8 : 0.5); } }
|
|
453
|
+
// ROAM
|
|
454
|
+
map<int, int> rcnt;
|
|
455
|
+
for (int k = 0; k < 3; k++) { auto& t = tasks[k][idx[k]]; if (t.type == 5) { int c = rcnt[t.key]++; total += t.val * (c == 0 ? 1.0 : 0.2); } }
|
|
456
|
+
for (int k = 0; k < 3; k++) { auto& t = tasks[k][idx[k]]; if (t.type == 0) total += t.val; }
|
|
457
|
+
return total;
|
|
458
|
+
};
|
|
459
|
+
array<int, 3> best = {0, 0, 0}; double bestV = -1e18;
|
|
460
|
+
for (int a = 0; a < (int)tasks[0].size(); a++)
|
|
461
|
+
for (int b = 0; b < (int)tasks[1].size(); b++)
|
|
462
|
+
for (int c = 0; c < (int)tasks[2].size(); c++) {
|
|
463
|
+
array<int, 3> idx = {a, b, c};
|
|
464
|
+
double v = evalCombo(idx);
|
|
465
|
+
if (v > bestV) { bestV = v; best = idx; }
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// ---------------- 移动选择 ----------------
|
|
469
|
+
// 一命的角色站在旗上、而血多的队友就在旁边:让位(走开、不拾旗)
|
|
470
|
+
vector<char> yieldK(3, 0);
|
|
471
|
+
for (int k = 0; k < 3; k++) {
|
|
472
|
+
auto& m = M[k];
|
|
473
|
+
if (!m.alive || m.flag >= 0 || lives(m.hp, g.damage) != 1 || remaining <= 30) continue;
|
|
474
|
+
bool onFlag = false;
|
|
475
|
+
for (size_t i = 0; i < g.flags.size(); i++) if (flagAvail[i] && flagCell[i] == m.cell) onFlag = true;
|
|
476
|
+
if (!onFlag) continue;
|
|
477
|
+
for (int j = 0; j < 3; j++) if (j != k && M[j].alive && !M[j].spawning && M[j].flag < 0 && lives(M[j].hp, g.damage) >= 2 && D(M[j].cell, m.cell) <= 2) yieldK[k] = 1;
|
|
478
|
+
}
|
|
479
|
+
vector<int> order; // 携旗者优先,其次让位者
|
|
480
|
+
for (int k = 0; k < 3; k++) if (M[k].alive && M[k].flag >= 0) order.push_back(k);
|
|
481
|
+
for (int k = 0; k < 3; k++) if (M[k].alive && M[k].flag < 0 && yieldK[k]) order.push_back(k);
|
|
482
|
+
for (int k = 0; k < 3; k++) if (M[k].alive && M[k].flag < 0 && !yieldK[k]) order.push_back(k);
|
|
483
|
+
vector<int> chosenCell(3, -1), chosenMove(3, 0);
|
|
484
|
+
vector<char> reserved(NN, 0);
|
|
485
|
+
vector<char> leaving(3, 0);
|
|
486
|
+
vector<int> forced(3, -1); // 被队友要求换位:必须走到该格
|
|
487
|
+
vector<int> carrierNext(3, -1); // 携旗者选定的下一格
|
|
488
|
+
for (int k : order) {
|
|
489
|
+
auto& m = M[k]; auto& t = tasks[k][best[k]];
|
|
490
|
+
if (forced[k] >= 0) {
|
|
491
|
+
int fc = forced[k]; int mv = 0;
|
|
492
|
+
for (int q = 1; q < 5; q++) if (cx(m.cell) + DX[q] == cx(fc) && cy(m.cell) + DY[q] == cy(fc)) mv = q;
|
|
493
|
+
chosenMove[k] = mv; chosenCell[k] = fc; reserved[fc] = 1; leaving[k] = 1;
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
vector<int> targets;
|
|
497
|
+
if (t.type == 0) targets = bcells[me];
|
|
498
|
+
else if (t.type == 3) {
|
|
499
|
+
// 护送:走到携旗者前方(沿其回家路线再往前一格)
|
|
500
|
+
int ci = t.key; int cc = (chosenCell[ci] >= 0) ? chosenCell[ci] : M[ci].cell;
|
|
501
|
+
auto cg = ctgTo(bcells[me], 5);
|
|
502
|
+
int ahead = cc; int bestc = cg[cc];
|
|
503
|
+
for (int q = 1; q < 5; q++) { int nx = cx(cc) + DX[q], ny = cy(cc) + DY[q]; if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue; int nc = cid(nx, ny); if (W[nc]) continue; if (cg[nc] < bestc) { bestc = cg[nc]; ahead = nc; } }
|
|
504
|
+
targets = {ahead};
|
|
505
|
+
}
|
|
506
|
+
else if (t.type >= 0) targets = {t.target};
|
|
507
|
+
else targets = {m.cell};
|
|
508
|
+
bool chased = false;
|
|
509
|
+
for (auto& e : E) if (!e.immune && e.flag < 0 && manh(e.cell, m.cell) <= 2) chased = true;
|
|
510
|
+
int K10 = (m.flag >= 0) ? (chased ? 3 : (nTeams >= 6 ? 4 : 15)) : 5;
|
|
511
|
+
if (m.hp <= 34 && !chased && m.flag < 0) K10 += 15;
|
|
512
|
+
int curBaseD = (m.flag >= 0) ? distToBase(m.cell, me) : 0;
|
|
513
|
+
auto ctg = ctgTo(targets, K10);
|
|
514
|
+
double hitVal = 2.5 + (m.flag >= 0 ? 1.0 : 0) + (m.hp <= 34 ? 3.0 : m.hp <= 68 ? 1.0 : 0);
|
|
515
|
+
if (nTeams >= 6) hitVal *= 1.3;
|
|
516
|
+
if (m.spawning) hitVal = 0;
|
|
517
|
+
int x = cx(m.cell), y = cy(m.cell);
|
|
518
|
+
double bestS = -1e18; int bestK = 0, bestC = m.cell, bestSwap = -1;
|
|
519
|
+
for (int mv = 0; mv < 5; mv++) {
|
|
520
|
+
int nx = x + DX[mv], ny = y + DY[mv];
|
|
521
|
+
if (nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
|
|
522
|
+
int nc = cid(nx, ny);
|
|
523
|
+
if (W[nc]) continue;
|
|
524
|
+
if (reserved[nc]) continue;
|
|
525
|
+
// 队友当前格:队友已决定离开可进;携旗者可与尚未决定的队友换位
|
|
526
|
+
bool teammateHere = false; int swapWith = -1;
|
|
527
|
+
for (int j = 0; j < 3; j++) if (j != k && M[j].alive && M[j].cell == nc && !(leaving[j])) {
|
|
528
|
+
if (m.flag >= 0 && chosenCell[j] < 0 && forced[j] < 0 && M[j].flag < 0 && !M[j].spawning) swapWith = j; else teammateHere = true;
|
|
529
|
+
}
|
|
530
|
+
if (teammateHere) continue;
|
|
531
|
+
if (m.flag >= 0 && distToBase(nc, me) > curBaseD) continue; // 携旗不后退
|
|
532
|
+
if (yieldK[k] && mv == 0) continue; // 让位:必须走开
|
|
533
|
+
double s = 0;
|
|
534
|
+
if (ctg[nc] >= INT_MAX) s -= 1e6; else s -= ctg[nc] / 10.0;
|
|
535
|
+
// 攻击期望
|
|
536
|
+
double atk = 0;
|
|
537
|
+
if (m.canAtk && !m.spawning) {
|
|
538
|
+
for (auto& e : E) {
|
|
539
|
+
if (e.immune) continue;
|
|
540
|
+
double p = pRange(nc, e); if (p <= 0) continue;
|
|
541
|
+
double v = 2.5 + (e.flag >= 0 ? 2.5 : 0) + (e.hp <= 34 ? 3.0 : e.hp <= 68 ? 1.0 : 0);
|
|
542
|
+
if (myCarrierIdx >= 0 && D(e.cell, M[myCarrierIdx].cell) <= 3) v += 1.0;
|
|
543
|
+
atk = max(atk, p * v);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
s += (nTeams >= 6 ? 0.5 : 1.0) * atk;
|
|
547
|
+
// 风险
|
|
548
|
+
double risk = 0;
|
|
549
|
+
if (!m.spawning) for (auto& e : E) { if (e.immune || e.flag >= 0) continue; risk += pRange(nc, e) * hitVal; }
|
|
550
|
+
s -= risk;
|
|
551
|
+
// 敌人占着的格子
|
|
552
|
+
if (mv != 0 && occ[nc] >= 0 && occ[nc] / 3 != me) {
|
|
553
|
+
const EInfo* e = nullptr; for (auto& x2 : E) if (x2.id == occ[nc]) e = &x2;
|
|
554
|
+
if (e) s -= 1.0 + 6.0 * e->pStay;
|
|
555
|
+
}
|
|
556
|
+
if (getenv("BOTDBG") && m.flag >= 0) cerr << "T" << T << " u" << m.id << " mv" << mv << " nc(" << cx(nc) << "," << cy(nc) << ") ctg=" << ctg[nc] << " atk=" << atk << " risk=" << risk << " s=" << s << " task=" << t.type << endl;
|
|
557
|
+
if (swapWith >= 0) s -= 0.3;
|
|
558
|
+
if (s > bestS) { bestS = s; bestK = mv; bestC = nc; bestSwap = swapWith; }
|
|
559
|
+
}
|
|
560
|
+
if (bestSwap >= 0) { forced[bestSwap] = m.cell; reserved[m.cell] = 1; }
|
|
561
|
+
chosenMove[k] = bestK; chosenCell[k] = bestC; reserved[bestC] = 1;
|
|
562
|
+
if (bestC != m.cell) leaving[k] = 1;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// ---------------- 攻击目标 / 拾旗 / 丢旗 ----------------
|
|
566
|
+
vector<string> act(3, "-");
|
|
567
|
+
map<int, int> dmgOn; // 目标 -> 已分配的命中次数
|
|
568
|
+
auto threatAt = [&](int c) {
|
|
569
|
+
double best = 0; int cnt = 0;
|
|
570
|
+
for (auto& e : E) { if (e.immune || e.flag >= 0) continue; double p = pRange(c, e); best = max(best, p); if (p >= 0.45) cnt++; }
|
|
571
|
+
return make_pair(best, cnt);
|
|
572
|
+
};
|
|
573
|
+
for (int k : order) {
|
|
574
|
+
auto& m = M[k]; int c = chosenCell[k];
|
|
575
|
+
// 携旗被追:距离基地还远、命够,就把旗放在脚下(继续站着)并转为反击
|
|
576
|
+
if (m.flag >= 0 && !m.spawning) {
|
|
577
|
+
auto [pt, cnt] = threatAt(c);
|
|
578
|
+
int dist = distToBase(c, me);
|
|
579
|
+
int escorts = 0;
|
|
580
|
+
for (int j = 0; j < 3; j++) if (j != k && M[j].alive && M[j].canAtk && !M[j].spawning && manh(M[j].cell, c) <= 3) escorts++;
|
|
581
|
+
if (nTeams <= 5 && cnt == 1 && dist > lives(m.hp, g.damage) + 1 && lives(m.hp, g.damage) >= 2 && escorts <= 1 && remaining > dist + 6) {
|
|
582
|
+
act[k] = "X";
|
|
583
|
+
}
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
// 拾旗:脚下有旗。若有敌人在射程内且自己命够,先开火守旗(旗在脚下别人拿不走)
|
|
587
|
+
if (m.flag < 0) {
|
|
588
|
+
int onFlag = -1;
|
|
589
|
+
for (size_t i = 0; i < g.flags.size(); i++) if (flagAvail[i] && flagCell[i] == c) onFlag = (int)i;
|
|
590
|
+
if (onFlag >= 0) {
|
|
591
|
+
bool yield = yieldK[k] && c == m.cell;
|
|
592
|
+
if (yield) { /* 让血多的队友来拿 */ }
|
|
593
|
+
else {
|
|
594
|
+
auto [pt, cnt] = threatAt(c);
|
|
595
|
+
bool timerOk = !(g.flags[onFlag].status == "dropped" && g.flags[onFlag].return_at >= 0 && g.flags[onFlag].return_at - T <= 2);
|
|
596
|
+
bool guard = (pt >= 0.45) && lives(m.hp, g.damage) >= 2 && timerOk && m.canAtk && !m.spawning && remaining > distToBase(c, me) + 4;
|
|
597
|
+
if (!guard) { act[k] = "P"; continue; }
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (!m.canAtk || m.spawning) continue;
|
|
602
|
+
double bestE = 0; int bestId = -1;
|
|
603
|
+
for (auto& e : E) {
|
|
604
|
+
if (e.immune) continue;
|
|
605
|
+
double p = pRange(c, e); if (p <= 0.001) continue;
|
|
606
|
+
double v = 2.5 + (e.flag >= 0 ? 2.5 : 0) + (e.hp <= 34 ? 3.0 : e.hp <= 68 ? 1.0 : 0);
|
|
607
|
+
if (myCarrierIdx >= 0 && D(e.cell, M[myCarrierIdx].cell) <= 3) v += 1.0;
|
|
608
|
+
int needed = (e.hp + g.damage - 1) / g.damage;
|
|
609
|
+
int already = dmgOn.count(e.id) ? dmgOn[e.id] : 0;
|
|
610
|
+
if (already + 1 >= needed) v += 3.0; // 集火可击杀
|
|
611
|
+
else if (already > 0) v += 0.8;
|
|
612
|
+
if (p * v > bestE) { bestE = p * v; bestId = e.id; }
|
|
613
|
+
}
|
|
614
|
+
if (bestId >= 0) { act[k] = to_string(bestId); dmgOn[bestId]++; }
|
|
615
|
+
else if (m.flag < 0) {
|
|
616
|
+
for (auto& sp : g.spots) if (cid(sp.first, sp.second) == c) act[k] = "P";
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
string out = to_string(T);
|
|
621
|
+
for (int k = 0; k < 3; k++) {
|
|
622
|
+
if (!M[k].alive) { out += " S -"; continue; }
|
|
623
|
+
out += ' '; out += MVC[chosenMove[k]]; out += ' '; out += act[k];
|
|
624
|
+
}
|
|
625
|
+
return out;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
int main() {
|
|
629
|
+
ios::sync_with_stdio(false);
|
|
630
|
+
Game g;
|
|
631
|
+
while (read_turn(g)) {
|
|
632
|
+
cout << decide(g) << endl;
|
|
633
|
+
}
|
|
634
|
+
}
|