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,689 @@
|
|
|
1
|
+
// 多阵营夺旗 bot(支持 2–15 方)
|
|
2
|
+
//
|
|
3
|
+
// 双模式架构(按人数切换,均经本地对战验证):
|
|
4
|
+
// · 2–3 方「战术模式」:每回合为 3 个角色分配任务(携旗回家 / 抢旗 / 清剿基地 /
|
|
5
|
+
// 支援抢旗 / 护送 / 拦截敌方携旗手 / 守旗点),用危险加权的 Dijkstra 规划移动
|
|
6
|
+
// (敌方射程、局部兵力差、敌方基地禁区都计入代价),动作阶段做集火目标选择。
|
|
7
|
+
// · ≥4 方「抱团模式」:实测人多混战里简单纪律胜过复杂门禁——三个单位抱团奔
|
|
8
|
+
// 往"往返时间最短"的旗,拾旗后携旗手沿危险加权路线绕开火线回家,射程内
|
|
9
|
+
// 优先攻击敌方携旗手。死亡很便宜(10 回合满血重生),以量取胜。
|
|
10
|
+
//
|
|
11
|
+
// 关键机制:死亡重生预测(重生当回合即可移动/拾旗)、自家旗点专职看守、
|
|
12
|
+
// 携旗必派护卫(护卫就位于携旗手阵亡点旁可接棒)、残血不拾贴身旗、
|
|
13
|
+
// 队友在场减危、内部移动冲突消解。
|
|
14
|
+
#include <bits/stdc++.h>
|
|
15
|
+
using namespace std;
|
|
16
|
+
|
|
17
|
+
struct Unit { int id, team, x, y, hp, flag, respawn_at; };
|
|
18
|
+
struct FlagT { int id; string status; int x, y, holder, return_at; };
|
|
19
|
+
struct EventT { string type; vector<int> args; };
|
|
20
|
+
|
|
21
|
+
struct Game {
|
|
22
|
+
int teams = 0, me = 0, size = 0, totalTurns = 0, maxhp = 0, dmg = 0, respT = 0, flagRet = 0, flagCd = 0;
|
|
23
|
+
vector<string> grid;
|
|
24
|
+
vector<pair<int,int>> bases, spots;
|
|
25
|
+
int turn = 0;
|
|
26
|
+
vector<int> score;
|
|
27
|
+
vector<Unit> units;
|
|
28
|
+
vector<FlagT> flags;
|
|
29
|
+
vector<EventT> events;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
bool read_turn(Game& g) {
|
|
33
|
+
string w;
|
|
34
|
+
while (cin >> w) {
|
|
35
|
+
if (w == "INIT") { cin >> g.teams >> g.me >> g.size >> g.totalTurns >> g.maxhp >> g.dmg >> g.respT >> g.flagRet >> g.flagCd; }
|
|
36
|
+
else if (w == "MAP") { g.grid.assign(g.size, string()); for (auto& r : g.grid) cin >> r; }
|
|
37
|
+
else if (w == "BASES") { int k; cin >> k; g.bases.resize(k); for (auto& b : g.bases) cin >> b.first >> b.second; }
|
|
38
|
+
else if (w == "SPOTS") { int k; cin >> k; g.spots.resize(k); for (auto& s : g.spots) cin >> s.first >> s.second; }
|
|
39
|
+
else if (w == "TURN") { cin >> g.turn; }
|
|
40
|
+
else if (w == "SCORE") { g.score.resize(g.teams); for (auto& s : g.score) cin >> s; }
|
|
41
|
+
else if (w == "UNITS") { int k; cin >> k; g.units.resize(k); for (auto& u : g.units) { string tag; cin >> tag >> u.id >> u.team >> u.x >> u.y >> u.hp >> u.flag >> u.respawn_at; } }
|
|
42
|
+
else if (w == "FLAGS") { int k; cin >> k; g.flags.resize(k); for (auto& f : g.flags) { string tag; cin >> tag >> f.id >> f.status >> f.x >> f.y >> f.holder >> f.return_at; } }
|
|
43
|
+
else if (w == "EVENTS") { int k; cin >> k; g.events.assign(k, {}); string line; getline(cin, line); for (auto& e : g.events) { getline(cin, line); istringstream in(line); string tag; in >> tag >> e.type; for (int v; in >> v;) e.args.push_back(v); } }
|
|
44
|
+
else if (w == "END") return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ---------------- 全局 ----------------
|
|
50
|
+
int S, N, ME, MAXHP, DMG, TOTALTURNS;
|
|
51
|
+
vector<string> G;
|
|
52
|
+
vector<vector<int>> dB; // dB[team][cell] = 到该阵营基地(3x3)的 BFS 距离
|
|
53
|
+
vector<float> baseDanger; // 敌方基地附近静态危险
|
|
54
|
+
vector<pair<int,int>> spotsG, myBase9, mySpawnOrder;
|
|
55
|
+
pair<int,int> C0;
|
|
56
|
+
bool inited = false;
|
|
57
|
+
|
|
58
|
+
inline int ID(int x, int y) { return y * S + x; }
|
|
59
|
+
inline bool openc(int x, int y) { return x >= 0 && x < S && y >= 0 && y < S && G[y][x] == '.'; }
|
|
60
|
+
inline int md(int ax, int ay, int bx, int by) { return abs(ax - bx) + abs(ay - by); }
|
|
61
|
+
|
|
62
|
+
bool canAtk(int ax, int ay, int bx, int by) {
|
|
63
|
+
int dx = bx - ax, dy = by - ay;
|
|
64
|
+
if (abs(dx) + abs(dy) > 2) return false;
|
|
65
|
+
if (abs(dx) == 2 && dy == 0) return openc(ax + dx / 2, ay);
|
|
66
|
+
if (abs(dy) == 2 && dx == 0) return openc(ax, ay + dy / 2);
|
|
67
|
+
if (abs(dx) == 1 && abs(dy) == 1) return openc(ax + dx, ay) || openc(ax, ay + dy);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
vector<int> bfsCells(const vector<pair<int,int>>& src) {
|
|
72
|
+
vector<int> d(S * S, INT_MAX);
|
|
73
|
+
deque<int> q;
|
|
74
|
+
for (auto& p : src) if (openc(p.first, p.second) && d[ID(p.first, p.second)] == INT_MAX) { d[ID(p.first, p.second)] = 0; q.push_back(ID(p.first, p.second)); }
|
|
75
|
+
const int DX[4] = {1,-1,0,0}, DY[4] = {0,0,1,-1};
|
|
76
|
+
while (!q.empty()) {
|
|
77
|
+
int c = q.front(); q.pop_front();
|
|
78
|
+
int x = c % S, y = c / S, dc = d[c] + 1;
|
|
79
|
+
for (int i = 0; i < 4; i++) {
|
|
80
|
+
int nx = x + DX[i], ny = y + DY[i];
|
|
81
|
+
if (openc(nx, ny)) { int nc = ID(nx, ny); if (d[nc] > dc) { d[nc] = dc; q.push_back(nc); } }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return d;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void doInit(Game& g) {
|
|
88
|
+
S = g.size; N = g.teams; ME = g.me; MAXHP = g.maxhp; DMG = g.dmg; TOTALTURNS = g.totalTurns; G = g.grid;
|
|
89
|
+
C0 = {S / 2, S / 2};
|
|
90
|
+
baseDanger.assign(S * S, 0.f);
|
|
91
|
+
for (int k = 0; k < N; k++) {
|
|
92
|
+
int bx = g.bases[k].first, by = g.bases[k].second;
|
|
93
|
+
vector<pair<int,int>> cells;
|
|
94
|
+
for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) cells.push_back({bx + dx, by + dy});
|
|
95
|
+
dB.push_back(bfsCells(cells));
|
|
96
|
+
if (k == ME) myBase9 = cells;
|
|
97
|
+
else for (int c = 0; c < S * S; c++) {
|
|
98
|
+
int dd = dB[k][c];
|
|
99
|
+
baseDanger[c] += dd == 0 ? 0.8f : dd == 1 ? 0.35f : dd == 2 ? 0.12f : 0.f;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
int bcx = g.bases[ME].first, bcy = g.bases[ME].second;
|
|
103
|
+
mySpawnOrder = myBase9;
|
|
104
|
+
sort(mySpawnOrder.begin(), mySpawnOrder.end(), [&](const pair<int,int>& a, const pair<int,int>& b) {
|
|
105
|
+
int da = md(a.first, a.second, C0.first, C0.second), db = md(b.first, b.second, C0.first, C0.second);
|
|
106
|
+
if (da != db) return da < db;
|
|
107
|
+
return abs(a.first - bcx) + 2 * abs(a.second - bcy) < abs(b.first - bcx) + 2 * abs(b.second - bcy);
|
|
108
|
+
});
|
|
109
|
+
spotsG = g.spots;
|
|
110
|
+
inited = true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 角色
|
|
114
|
+
enum { R_CARRY = 0, R_FETCH, R_CLEAR, R_SUPPORT, R_ESCORT, R_HUNT, R_CAMP, R_IDLE, R_DEAD };
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
// 简单模式(对照实验/备用):携旗回家,否则奔最近可抢的旗,射程内选最优目标攻击
|
|
118
|
+
string decideSimple(Game& g) {
|
|
119
|
+
int T = g.turn;
|
|
120
|
+
const int DX[4] = {1,-1,0,0}, DY[4] = {0,0,1,-1};
|
|
121
|
+
Unit raw[3] = {};
|
|
122
|
+
for (auto& u : g.units) if (u.team == ME) raw[u.id - 3 * ME] = u;
|
|
123
|
+
set<int> occ;
|
|
124
|
+
for (auto& u : g.units) if (u.x >= 0) occ.insert(ID(u.x, u.y));
|
|
125
|
+
int ux[3], uy[3], uhp[3], uflag[3]; bool alive[3], respNow[3];
|
|
126
|
+
for (int k = 0; k < 3; k++) {
|
|
127
|
+
ux[k] = raw[k].x; uy[k] = raw[k].y; uhp[k] = raw[k].hp; uflag[k] = raw[k].flag;
|
|
128
|
+
alive[k] = ux[k] >= 0; respNow[k] = false;
|
|
129
|
+
if (!alive[k] && raw[k].respawn_at == T)
|
|
130
|
+
for (auto& p : mySpawnOrder) { int c = ID(p.first, p.second);
|
|
131
|
+
if (!occ.count(c)) { ux[k] = p.first; uy[k] = p.second; uhp[k] = MAXHP; uflag[k] = -1; alive[k] = true; respNow[k] = true; occ.insert(c); break; } }
|
|
132
|
+
}
|
|
133
|
+
vector<Unit> en;
|
|
134
|
+
for (auto& u : g.units) if (u.team != ME && u.x >= 0) en.push_back(u);
|
|
135
|
+
// 危险图(敌方非携旗单位的射程)
|
|
136
|
+
vector<float> danger(S * S, 0.f);
|
|
137
|
+
for (auto& e : en) {
|
|
138
|
+
if (e.flag >= 0) continue;
|
|
139
|
+
for (int dy = -4; dy <= 4; dy++) for (int dx = -4; dx <= 4; dx++) {
|
|
140
|
+
int d = abs(dx) + abs(dy); if (d == 0 || d > 4) continue;
|
|
141
|
+
int x = e.x + dx, y = e.y + dy;
|
|
142
|
+
if (!openc(x, y)) continue;
|
|
143
|
+
float w = 0;
|
|
144
|
+
if (d <= 2) w = canAtk(e.x, e.y, x, y) ? 1.f : 0.3f;
|
|
145
|
+
else if (d == 3) w = 0.45f; else w = 0.12f;
|
|
146
|
+
danger[ID(x, y)] += w;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (int k = 0; k < 3; k++) if (alive[k]) {
|
|
150
|
+
for (int dy = -2; dy <= 2; dy++) for (int dx = -2; dx <= 2; dx++) {
|
|
151
|
+
if (abs(dx) + abs(dy) == 0) continue;
|
|
152
|
+
int x = ux[k] + dx, y = uy[k] + dy;
|
|
153
|
+
if (openc(x, y)) danger[ID(x, y)] -= 0.25f;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (int c = 0; c < S * S; c++) if (danger[c] < 0.f) danger[c] = 0.f;
|
|
157
|
+
// 可见旗子
|
|
158
|
+
vector<pair<int,int>> afv;
|
|
159
|
+
for (auto& f : g.flags) if ((f.status == "home" || f.status == "dropped") && f.return_at != T) afv.push_back({f.x, f.y});
|
|
160
|
+
string out = to_string(T);
|
|
161
|
+
set<int> of;
|
|
162
|
+
for (int k = 0; k < 3; k++) if (alive[k]) of.insert(ID(ux[k], uy[k]));
|
|
163
|
+
for (int k = 0; k < 3; k++) {
|
|
164
|
+
string mv = "S", act = "-";
|
|
165
|
+
if (alive[k]) {
|
|
166
|
+
vector<pair<int,int>> targs;
|
|
167
|
+
if (uflag[k] >= 0) targs = myBase9;
|
|
168
|
+
else {
|
|
169
|
+
int bd = INT_MAX; pair<int,int> best{-1,-1};
|
|
170
|
+
for (auto& p : afv) {
|
|
171
|
+
int d = md(ux[k], uy[k], p.first, p.second) + dB[ME][ID(p.first, p.second)];
|
|
172
|
+
if (d < bd) { bd = d; best = p; }
|
|
173
|
+
}
|
|
174
|
+
if (best.first >= 0) targs = {best};
|
|
175
|
+
}
|
|
176
|
+
// BFS 找一步
|
|
177
|
+
int nxk = ux[k], nyk = uy[k];
|
|
178
|
+
if (!targs.empty()) {
|
|
179
|
+
float wD = (uflag[k] >= 0) ? 1.5f : 0.6f; // 携旗手绕开火线
|
|
180
|
+
vector<float> D(S * S, 1e18f);
|
|
181
|
+
priority_queue<pair<float,int>, vector<pair<float,int>>, greater<pair<float,int>>> pq;
|
|
182
|
+
for (auto& p : targs) { int c = ID(p.first, p.second); if (openc(p.first, p.second) && D[c] > 0) { D[c] = 0.f; pq.push({0.f, c}); } }
|
|
183
|
+
while (!pq.empty()) {
|
|
184
|
+
pair<float,int> pr = pq.top(); pq.pop();
|
|
185
|
+
float dd = pr.first; int c = pr.second;
|
|
186
|
+
if (dd > D[c] + 1e-6f) continue;
|
|
187
|
+
int x = c % S, y = c / S;
|
|
188
|
+
for (int i = 0; i < 4; i++) {
|
|
189
|
+
int ax = x + DX[i], ay = y + DY[i];
|
|
190
|
+
if (!openc(ax, ay)) continue;
|
|
191
|
+
int ac = ID(ax, ay);
|
|
192
|
+
float cost = 1.f + wD * danger[ac];
|
|
193
|
+
if (dd + cost < D[ac] - 1e-6f) { D[ac] = dd + cost; pq.push({D[ac], ac}); }
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
int cur = ID(ux[k], uy[k]);
|
|
197
|
+
if (D[cur] > 0.f && D[cur] < 1e17f) {
|
|
198
|
+
float bc = 1e18f; int bs = -1;
|
|
199
|
+
for (int i = 0; i < 4; i++) {
|
|
200
|
+
int ax = ux[k] + DX[i], ay = uy[k] + DY[i];
|
|
201
|
+
if (!openc(ax, ay)) continue;
|
|
202
|
+
int ac = ID(ax, ay);
|
|
203
|
+
if (of.count(ac)) continue;
|
|
204
|
+
bool enemyOn = false;
|
|
205
|
+
for (auto& e : en) if (e.x == ax && e.y == ay) enemyOn = true;
|
|
206
|
+
if (enemyOn) continue;
|
|
207
|
+
float v = 1.f + wD * danger[ac] + D[ac];
|
|
208
|
+
if (v < bc) { bc = v; bs = ac; }
|
|
209
|
+
}
|
|
210
|
+
if (bs >= 0) { of.erase(cur); of.insert(bs); nxk = bs % S; nyk = bs / S; }
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
int ddx = nxk - ux[k], ddy = nyk - uy[k];
|
|
214
|
+
if (ddx == 1) mv = "R"; else if (ddx == -1) mv = "L"; else if (ddy == 1) mv = "D"; else if (ddy == -1) mv = "U";
|
|
215
|
+
if (uflag[k] < 0) {
|
|
216
|
+
bool onF = false;
|
|
217
|
+
for (auto& f : g.flags) if ((f.status == "home" || f.status == "dropped") && f.return_at != T && f.x == nxk && f.y == nyk) onF = true;
|
|
218
|
+
if (onF) act = "P";
|
|
219
|
+
else if (!respNow[k]) {
|
|
220
|
+
int bestT = -1; float bs2 = -1e9;
|
|
221
|
+
for (auto& e : en) {
|
|
222
|
+
if (!canAtk(nxk, nyk, e.x, e.y)) continue;
|
|
223
|
+
float s2 = (e.flag >= 0 ? 100.f : 0.f) + (MAXHP - e.hp) * 0.3f;
|
|
224
|
+
if (s2 > bs2) { bs2 = s2; bestT = e.id; }
|
|
225
|
+
}
|
|
226
|
+
if (bestT >= 0) act = to_string(bestT);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
out += " " + mv + " " + act;
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
string decide(Game& g) {
|
|
236
|
+
if (!inited) doInit(g);
|
|
237
|
+
int T = g.turn, total = TOTALTURNS;
|
|
238
|
+
if (N >= 4) return decideSimple(g); // 4 人以上:抱团抢旗的简单模式胜过复杂门禁
|
|
239
|
+
const int DX[4] = {1,-1,0,0}, DY[4] = {0,0,1,-1};
|
|
240
|
+
|
|
241
|
+
// ---- 我的角色(含本回合重生的预测位置)
|
|
242
|
+
Unit raw[3] = {};
|
|
243
|
+
for (auto& u : g.units) if (u.team == ME) raw[u.id - 3 * ME] = u;
|
|
244
|
+
int ux[3], uy[3], uhp[3], uflag[3]; bool alive[3], respNow[3];
|
|
245
|
+
set<int> occ;
|
|
246
|
+
for (auto& u : g.units) if (u.x >= 0) occ.insert(ID(u.x, u.y));
|
|
247
|
+
for (int k = 0; k < 3; k++) {
|
|
248
|
+
ux[k] = raw[k].x; uy[k] = raw[k].y; uhp[k] = raw[k].hp; uflag[k] = raw[k].flag;
|
|
249
|
+
alive[k] = ux[k] >= 0; respNow[k] = false;
|
|
250
|
+
if (!alive[k] && raw[k].respawn_at == T) {
|
|
251
|
+
for (auto& p : mySpawnOrder) {
|
|
252
|
+
int c = ID(p.first, p.second);
|
|
253
|
+
if (occ.find(c) == occ.end()) { ux[k] = p.first; uy[k] = p.second; uhp[k] = MAXHP; uflag[k] = -1; alive[k] = true; respNow[k] = true; occ.insert(c); break; }
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
vector<Unit> en;
|
|
258
|
+
for (auto& u : g.units) if (u.team != ME && u.x >= 0) en.push_back(u);
|
|
259
|
+
|
|
260
|
+
// ---- 危险图
|
|
261
|
+
vector<float> danger(S * S, 0.f);
|
|
262
|
+
for (auto& e : en) {
|
|
263
|
+
if (e.flag >= 0) continue; // 携旗者不能攻击
|
|
264
|
+
for (int dy = -4; dy <= 4; dy++) for (int dx = -4; dx <= 4; dx++) {
|
|
265
|
+
int d = abs(dx) + abs(dy); if (d == 0 || d > 4) continue;
|
|
266
|
+
int x = e.x + dx, y = e.y + dy;
|
|
267
|
+
if (!openc(x, y)) continue;
|
|
268
|
+
float w = 0;
|
|
269
|
+
if (d <= 2) w = canAtk(e.x, e.y, x, y) ? 1.f : 0.3f;
|
|
270
|
+
else if (d == 3) w = 0.45f; else w = 0.12f;
|
|
271
|
+
danger[ID(x, y)] += w;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
for (int c = 0; c < S * S; c++) danger[c] += baseDanger[c];
|
|
275
|
+
// 盟友减危:附近有队友时更敢打(护送/结伴作战)
|
|
276
|
+
for (int k = 0; k < 3; k++) if (alive[k]) {
|
|
277
|
+
for (int dy = -2; dy <= 2; dy++) for (int dx = -2; dx <= 2; dx++) {
|
|
278
|
+
int d = abs(dx) + abs(dy); if (d == 0) continue;
|
|
279
|
+
int x = ux[k] + dx, y = uy[k] + dy;
|
|
280
|
+
if (!openc(x, y)) continue;
|
|
281
|
+
danger[ID(x, y)] -= 0.25f;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
for (int c = 0; c < S * S; c++) if (danger[c] < 0.f) danger[c] = 0.f;
|
|
285
|
+
|
|
286
|
+
// 局部兵力:敌人(非携旗)与队友在 3 步内的数量,用于避免落单送死
|
|
287
|
+
vector<int> enN(S * S, 0), allySplash(S * S, 0);
|
|
288
|
+
for (auto& e : en) {
|
|
289
|
+
if (e.flag >= 0) continue;
|
|
290
|
+
for (int dy = -3; dy <= 3; dy++) for (int dx = -3; dx <= 3; dx++) {
|
|
291
|
+
if (abs(dx) + abs(dy) > 3) continue;
|
|
292
|
+
int x = e.x + dx, y = e.y + dy;
|
|
293
|
+
if (openc(x, y)) enN[ID(x, y)]++;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
for (int k = 0; k < 3; k++) if (alive[k]) {
|
|
297
|
+
for (int dy = -3; dy <= 3; dy++) for (int dx = -3; dx <= 3; dx++) {
|
|
298
|
+
if (abs(dx) + abs(dy) > 3) continue;
|
|
299
|
+
int x = ux[k] + dx, y = uy[k] + dy;
|
|
300
|
+
if (openc(x, y)) allySplash[ID(x, y)]++;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ---- 可见旗子
|
|
305
|
+
struct AF { int x, y, id, dh; };
|
|
306
|
+
vector<AF> af; vector<vector<int>> fdist;
|
|
307
|
+
for (auto& f : g.flags) if ((f.status == "home" || f.status == "dropped") && f.return_at != T) {
|
|
308
|
+
af.push_back({f.x, f.y, f.id, dB[ME][ID(f.x, f.y)]});
|
|
309
|
+
fdist.push_back(bfsCells({{f.x, f.y}}));
|
|
310
|
+
}
|
|
311
|
+
int naf = af.size();
|
|
312
|
+
|
|
313
|
+
// ---- 角色分配
|
|
314
|
+
int role[3], parm[3], parm2[3];
|
|
315
|
+
for (int k = 0; k < 3; k++) { role[k] = alive[k] ? R_IDLE : R_DEAD; parm[k] = parm2[k] = -1; }
|
|
316
|
+
for (int k = 0; k < 3; k++) if (alive[k] && uflag[k] >= 0) role[k] = R_CARRY;
|
|
317
|
+
|
|
318
|
+
// 抢旗:代价 = 我的往返时间 - 竞争优势
|
|
319
|
+
struct PR { float cost; int u, f, margin; };
|
|
320
|
+
vector<PR> prs;
|
|
321
|
+
int centerD = dB[ME][ID(C0.first, C0.second)];
|
|
322
|
+
vector<int> enNear(naf, INT_MAX); // 敌方到旗的最短距离
|
|
323
|
+
for (int i = 0; i < naf; i++) for (auto& e : en) {
|
|
324
|
+
int d2 = fdist[i][ID(e.x, e.y)];
|
|
325
|
+
if (d2 < enNear[i]) enNear[i] = d2;
|
|
326
|
+
}
|
|
327
|
+
for (int k = 0; k < 3; k++) if (alive[k] && role[k] == R_IDLE) {
|
|
328
|
+
for (int i = 0; i < naf; i++) {
|
|
329
|
+
int d1 = fdist[i][ID(ux[k], uy[k])]; if (d1 == INT_MAX) continue;
|
|
330
|
+
int myT = d1 + af[i].dh;
|
|
331
|
+
if (T + myT + 2 > total) continue;
|
|
332
|
+
int enT = INT_MAX;
|
|
333
|
+
for (auto& e : en) {
|
|
334
|
+
int d2 = fdist[i][ID(e.x, e.y)]; if (d2 == INT_MAX) continue;
|
|
335
|
+
int v = d2 + dB[e.team][ID(af[i].x, af[i].y)];
|
|
336
|
+
if (v < enT) enT = v;
|
|
337
|
+
}
|
|
338
|
+
if (uhp[k] <= 34 && enNear[i] <= 4) continue; // 残血且敌人贴身:不拾旗
|
|
339
|
+
if (uhp[k] <= 34 && af[i].dh > centerD * 2 / 3 && enNear[i] <= 6) continue; // 残血只跑家门口
|
|
340
|
+
int margin = (enT == INT_MAX) ? 8 : enT - myT;
|
|
341
|
+
// 多人局:比我更近的敌方单位不超过 1 个、或旗离家近、或总时间不吃亏,就去抢
|
|
342
|
+
int closerLim = max(1, N / 3); // 人多时排进最近几名就有机会
|
|
343
|
+
int closer = 0;
|
|
344
|
+
for (auto& e : en) if (e.flag < 0 && fdist[i][ID(e.x, e.y)] < d1) closer++;
|
|
345
|
+
bool homeZone = af[i].dh <= centerD * 2 / 3;
|
|
346
|
+
if (N >= 5 && af[i].dh > centerD * 3 / 4) continue; // 大图:太远的旗运不回来
|
|
347
|
+
if (margin < -8 && !(homeZone || (N >= 3 && closer <= closerLim))) continue;
|
|
348
|
+
prs.push_back({(float)(myT - 0.6 * max(min(margin, 8), -8) - (homeZone ? 3 : 0)) + (MAXHP - uhp[k]) * 0.3f, k, i, margin});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
sort(prs.begin(), prs.end(), [](const PR& a, const PR& b) { return a.cost < b.cost; });
|
|
352
|
+
vector<char> fTaken(naf, 0);
|
|
353
|
+
int fMargin[3]; bool supported[3];
|
|
354
|
+
for (int k = 0; k < 3; k++) { fMargin[k] = 1000; supported[k] = false; }
|
|
355
|
+
for (auto& p : prs) if (role[p.u] == R_IDLE && !fTaken[p.f]) { role[p.u] = R_FETCH; parm[p.u] = p.f; fTaken[p.f] = 1; fMargin[p.u] = p.margin; }
|
|
356
|
+
|
|
357
|
+
vector<int> left;
|
|
358
|
+
for (int k = 0; k < 3; k++) if (alive[k] && role[k] == R_IDLE) left.push_back(k);
|
|
359
|
+
|
|
360
|
+
// 专职旗点看守(多人局):最近的空闲单位站上我的旗点,旗一刷新立刻拾取
|
|
361
|
+
if (!left.empty() && N >= 3) {
|
|
362
|
+
int mySpotIdx = 0, bd0 = INT_MAX;
|
|
363
|
+
for (int j = 0; j < (int)spotsG.size(); j++) {
|
|
364
|
+
int d = dB[ME][ID(spotsG[j].first, spotsG[j].second)];
|
|
365
|
+
if (d < bd0) { bd0 = d; mySpotIdx = j; }
|
|
366
|
+
}
|
|
367
|
+
bool fetcherThere = false;
|
|
368
|
+
for (int i = 0; i < naf; i++)
|
|
369
|
+
if (fTaken[i] && af[i].x == spotsG[mySpotIdx].first && af[i].y == spotsG[mySpotIdx].second) fetcherThere = true;
|
|
370
|
+
int bi = 0, bdu = INT_MAX;
|
|
371
|
+
for (int i = 0; i < (int)left.size(); i++) {
|
|
372
|
+
int d = md(ux[left[i]], uy[left[i]], spotsG[mySpotIdx].first, spotsG[mySpotIdx].second);
|
|
373
|
+
if (d < bdu) { bdu = d; bi = i; }
|
|
374
|
+
}
|
|
375
|
+
// 旗点已有抢旗队友时改守中心(第二近的刷新点)
|
|
376
|
+
int sitIdx = mySpotIdx;
|
|
377
|
+
if (fetcherThere) {
|
|
378
|
+
int bc2 = -1, bdc = INT_MAX;
|
|
379
|
+
for (int j = 0; j < (int)spotsG.size(); j++) {
|
|
380
|
+
int d = dB[ME][ID(spotsG[j].first, spotsG[j].second)];
|
|
381
|
+
if (d < bdc && d > bd0) { bdc = d; bc2 = j; }
|
|
382
|
+
}
|
|
383
|
+
if (bc2 >= 0) sitIdx = bc2;
|
|
384
|
+
}
|
|
385
|
+
role[left[bi]] = R_CAMP; parm[left[bi]] = sitIdx; left.erase(left.begin() + bi);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// 清理基地附近的敌人(不清掉会打断交旗)
|
|
389
|
+
{
|
|
390
|
+
vector<int> campers;
|
|
391
|
+
for (auto& e : en) if (dB[ME][ID(e.x, e.y)] <= 2) campers.push_back(e.id);
|
|
392
|
+
vector<char> camTaken(campers.size(), 0);
|
|
393
|
+
while (!left.empty()) {
|
|
394
|
+
int bi = -1, bj = -1, bd = INT_MAX;
|
|
395
|
+
for (int i = 0; i < (int)left.size(); i++) for (int j = 0; j < (int)campers.size(); j++) {
|
|
396
|
+
if (camTaken[j]) continue;
|
|
397
|
+
int d = md(ux[left[i]], uy[left[i]], g.units[campers[j]].x, g.units[campers[j]].y);
|
|
398
|
+
if (d < bd) { bd = d; bi = i; bj = j; }
|
|
399
|
+
}
|
|
400
|
+
if (bi < 0) break;
|
|
401
|
+
role[left[bi]] = R_CLEAR; parm[left[bi]] = campers[bj]; camTaken[bj] = 1;
|
|
402
|
+
left.erase(left.begin() + bi);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// 护送优先于低价值抢旗:没空闲单位时,抽调代价最高的抢旗手来护送
|
|
407
|
+
for (int cs = 0; cs < 3 && left.empty() && N >= 3; cs++) if (alive[cs] && uflag[cs] >= 0) {
|
|
408
|
+
int bk = -1; float bcost = -1e9;
|
|
409
|
+
for (int k = 0; k < 3; k++) if (role[k] == R_FETCH) {
|
|
410
|
+
float c = (float)fMargin[k] + af[parm[k]].dh * 0.3f; // 优势越小、旗越远越优先被抽
|
|
411
|
+
if (c > bcost) { bcost = c; bk = k; }
|
|
412
|
+
}
|
|
413
|
+
if (bk >= 0) { left.push_back(bk); role[bk] = R_IDLE; fTaken[parm[bk]] = 0; }
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// 护送携旗队友:大图一律双护卫(护卫跟在携旗手旁,被打死时就地接棒),
|
|
417
|
+
// 空闲单位不够就从最不划算的抢旗任务里抽调
|
|
418
|
+
auto stealFetcher = [&]() -> bool {
|
|
419
|
+
int bk = -1; float bcost = -1e9;
|
|
420
|
+
for (int k = 0; k < 3; k++) if (role[k] == R_FETCH) {
|
|
421
|
+
float c = (float)fMargin[k] + af[parm[k]].dh * 0.3f;
|
|
422
|
+
if (c > bcost) { bcost = c; bk = k; }
|
|
423
|
+
}
|
|
424
|
+
if (bk >= 0) { left.push_back(bk); role[bk] = R_IDLE; fTaken[parm[bk]] = 0; return true; }
|
|
425
|
+
return false;
|
|
426
|
+
};
|
|
427
|
+
for (int cs = 0; cs < 3; cs++) if (alive[cs] && uflag[cs] >= 0) {
|
|
428
|
+
int nearE = INT_MAX, threat = 0;
|
|
429
|
+
for (auto& e : en) {
|
|
430
|
+
int d = md(e.x, e.y, ux[cs], uy[cs]);
|
|
431
|
+
if (d < nearE) nearE = d;
|
|
432
|
+
if (d <= 4) threat++;
|
|
433
|
+
}
|
|
434
|
+
if (nearE > (N <= 2 ? 8 : 12)) continue;
|
|
435
|
+
int need = (N >= 5) ? 2 : (threat >= 2 ? 2 : 1);
|
|
436
|
+
int got = 0;
|
|
437
|
+
while (got < need && (!left.empty() || (N >= 3 && stealFetcher()))) {
|
|
438
|
+
int bi = 0, bd = INT_MAX;
|
|
439
|
+
for (int i = 0; i < (int)left.size(); i++) { int d = md(ux[left[i]], uy[left[i]], ux[cs], uy[cs]); if (d < bd) { bd = d; bi = i; } }
|
|
440
|
+
role[left[bi]] = R_ESCORT; parm[left[bi]] = cs; left.erase(left.begin() + bi);
|
|
441
|
+
got++;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// 支援被争夺的抢旗队友(敌人比队友晚到不足 6 步就算有争夺)
|
|
446
|
+
while (!left.empty()) {
|
|
447
|
+
int bk = -1; int bestc = INT_MAX;
|
|
448
|
+
for (int k = 0; k < 3; k++) if (role[k] == R_FETCH && !supported[k]) {
|
|
449
|
+
int d1 = fdist[parm[k]][ID(ux[k], uy[k])];
|
|
450
|
+
int contest = (enNear[parm[k]] == INT_MAX) ? INT_MAX : enNear[parm[k]] - d1;
|
|
451
|
+
if (contest < bestc && contest < 6) { bestc = contest; bk = k; }
|
|
452
|
+
}
|
|
453
|
+
if (bk < 0) break;
|
|
454
|
+
supported[bk] = 1;
|
|
455
|
+
int bi = 0, bd = INT_MAX;
|
|
456
|
+
for (int i = 0; i < (int)left.size(); i++) { int d = md(ux[left[i]], uy[left[i]], ux[bk], uy[bk]); if (d < bd) { bd = d; bi = i; } }
|
|
457
|
+
// 支援者跟到旗附近待命,帮抢也帮护
|
|
458
|
+
role[left[bi]] = R_SUPPORT; parm[left[bi]] = bk; parm2[left[bi]] = parm[bk]; left.erase(left.begin() + bi);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// 拦截敌方携旗手:在其回家路径上找能提前到位的伏击点(仅少人局)
|
|
462
|
+
for (int li = 0; li < (int)left.size(); ) {
|
|
463
|
+
int k = left[li];
|
|
464
|
+
int bestPrey = -1, bestCell = -1; float bestAdv = 1e9f;
|
|
465
|
+
if (N > 6) { li++; continue; }
|
|
466
|
+
for (auto& e : en) {
|
|
467
|
+
if (e.flag < 0) continue;
|
|
468
|
+
int home = dB[e.team][ID(e.x, e.y)]; if (home < 3) continue;
|
|
469
|
+
int allies = 0;
|
|
470
|
+
for (auto& a : en) if (a.id != e.id && a.team == e.team && a.flag < 0 && md(a.x, a.y, e.x, e.y) <= 2) allies++;
|
|
471
|
+
if (allies >= 2) continue;
|
|
472
|
+
vector<int> myD = bfsCells({{ux[k], uy[k]}});
|
|
473
|
+
for (int c = 0; c < S * S; c++) {
|
|
474
|
+
if (myD[c] == INT_MAX) continue;
|
|
475
|
+
int dp = dB[e.team][c]; if (dp < 2 || dp >= home) continue;
|
|
476
|
+
float adv = (float)myD[c] + dp - home;
|
|
477
|
+
if (adv < bestAdv) { bestAdv = adv; bestPrey = e.id; bestCell = c; }
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (bestPrey >= 0 && bestAdv <= -1.f) { role[k] = R_HUNT; parm[k] = bestPrey; parm2[k] = bestCell; left.erase(left.begin() + li); }
|
|
481
|
+
else li++;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// 守旗点(站上去就能第一时间拾取)。之后的空闲单位在大图做机会型抢旗
|
|
485
|
+
if (!left.empty()) {
|
|
486
|
+
vector<char> spotTaken(spotsG.size(), 0);
|
|
487
|
+
int nCamp = 0;
|
|
488
|
+
for (int li = 0; li < (int)left.size(); li++) {
|
|
489
|
+
int k = left[li];
|
|
490
|
+
if (nCamp >= 1 && N >= 5) {
|
|
491
|
+
int bi = -1, bc = INT_MAX;
|
|
492
|
+
for (int i = 0; i < naf; i++) {
|
|
493
|
+
if (fTaken[i] || af[i].dh > centerD * 3 / 4) continue;
|
|
494
|
+
int d1 = fdist[i][ID(ux[k], uy[k])];
|
|
495
|
+
if (d1 == INT_MAX || T + d1 + af[i].dh + 2 > total) continue;
|
|
496
|
+
if (d1 + af[i].dh < bc) { bc = d1 + af[i].dh; bi = i; }
|
|
497
|
+
}
|
|
498
|
+
if (bi >= 0) { role[k] = R_FETCH; parm[k] = bi; parm2[k] = bi; fTaken[bi] = 1; fMargin[k] = 0; supported[k] = true; continue; }
|
|
499
|
+
}
|
|
500
|
+
int bj = -1, bs = INT_MAX;
|
|
501
|
+
for (int j = 0; j < (int)spotsG.size(); j++) {
|
|
502
|
+
if (spotTaken[j]) continue;
|
|
503
|
+
int dhome = dB[ME][ID(spotsG[j].first, spotsG[j].second)];
|
|
504
|
+
if (dhome > centerD + 2) continue; // 不守太远的旗点
|
|
505
|
+
bool fetcherGoing = false;
|
|
506
|
+
for (int i = 0; i < naf; i++) if (fTaken[i] && af[i].x == spotsG[j].first && af[i].y == spotsG[j].second) fetcherGoing = true;
|
|
507
|
+
if (fetcherGoing) continue;
|
|
508
|
+
int sc = 2 * dhome + md(ux[k], uy[k], spotsG[j].first, spotsG[j].second);
|
|
509
|
+
if (sc < bs) { bs = sc; bj = j; }
|
|
510
|
+
}
|
|
511
|
+
if (bj >= 0) { role[k] = R_CAMP; parm[k] = bj; spotTaken[bj] = 1; nCamp++; }
|
|
512
|
+
else if (dB[ME][ID(ux[k], uy[k])] > 3) { role[k] = R_CAMP; parm[k] = -1; }
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// 近距离追杀敌方携旗手:3 步内的携旗敌人直接追(它跑不掉,保持 2 格距离就能每回合命中)
|
|
517
|
+
for (int k = 0; k < 3; k++) {
|
|
518
|
+
if (!alive[k] || uflag[k] >= 0 || role[k] == R_CARRY || role[k] == R_CLEAR || N > 6) continue;
|
|
519
|
+
int bc = -1, bdd = 4;
|
|
520
|
+
for (auto& e : en) if (e.flag >= 0) {
|
|
521
|
+
int d = md(ux[k], uy[k], e.x, e.y);
|
|
522
|
+
if (d < bdd) { bdd = d; bc = ID(e.x, e.y); }
|
|
523
|
+
}
|
|
524
|
+
if (bc >= 0) {
|
|
525
|
+
bool onFlag = false;
|
|
526
|
+
for (auto& f : g.flags) if ((f.status == "home" || f.status == "dropped") && f.return_at != T && f.x == ux[k] && f.y == uy[k]) onFlag = true;
|
|
527
|
+
if (!onFlag) { role[k] = R_HUNT; parm[k] = -1; parm2[k] = bc; }
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ---- 移动规划(按角色优先级)
|
|
532
|
+
int order3[3] = {-1, -1, -1}; int oi = 0;
|
|
533
|
+
for (int r = R_CARRY; r <= R_IDLE; r++) for (int k = 0; k < 3; k++) if (role[k] == r) order3[oi++] = k;
|
|
534
|
+
set<int> of;
|
|
535
|
+
for (int k = 0; k < 3; k++) if (alive[k]) of.insert(ID(ux[k], uy[k]));
|
|
536
|
+
int nx[3], ny[3];
|
|
537
|
+
for (int k = 0; k < 3; k++) { nx[k] = ux[k]; ny[k] = uy[k]; }
|
|
538
|
+
|
|
539
|
+
vector<float> D;
|
|
540
|
+
for (int o = 0; o < 3; o++) {
|
|
541
|
+
int k = order3[o];
|
|
542
|
+
if (k < 0 || !alive[k] || role[k] == R_IDLE || role[k] == R_DEAD) continue;
|
|
543
|
+
vector<pair<int,int>> targs; float wD; int allow = -1;
|
|
544
|
+
switch (role[k]) {
|
|
545
|
+
case R_CARRY: targs = myBase9; wD = 2.2f; break;
|
|
546
|
+
case R_FETCH: {
|
|
547
|
+
int fx = af[parm[k]].x, fy = af[parm[k]].y;
|
|
548
|
+
int enF = 0, alF = 0;
|
|
549
|
+
for (auto& e : en) if (md(e.x, e.y, fx, fy) <= 3) enF++;
|
|
550
|
+
for (int j = 0; j < 3; j++) if (alive[j] && j != k && md(ux[j], uy[j], fx, fy) <= 3) alF++;
|
|
551
|
+
if (enF >= alF + 2) {
|
|
552
|
+
// 敌众我寡明显:不冲上去送死,占 2 格火力位射击靠近者
|
|
553
|
+
for (int dy = -2; dy <= 2; dy++) for (int dx = -2; dx <= 2; dx++) {
|
|
554
|
+
int d = abs(dx) + abs(dy);
|
|
555
|
+
if (d == 0 || d > 2) continue;
|
|
556
|
+
int x = fx + dx, y = fy + dy;
|
|
557
|
+
if (openc(x, y) && canAtk(x, y, fx, fy)) targs.push_back({x, y});
|
|
558
|
+
}
|
|
559
|
+
if (targs.empty()) targs.push_back({fx, fy});
|
|
560
|
+
} else {
|
|
561
|
+
targs = {{fx, fy}};
|
|
562
|
+
allow = ID(fx, fy);
|
|
563
|
+
}
|
|
564
|
+
wD = 1.1f; break;
|
|
565
|
+
}
|
|
566
|
+
case R_CLEAR: {
|
|
567
|
+
Unit& e = g.units[parm[k]];
|
|
568
|
+
for (int dy = -2; dy <= 2; dy++) for (int dx = -2; dx <= 2; dx++) {
|
|
569
|
+
int x = e.x + dx, y = e.y + dy;
|
|
570
|
+
if (openc(x, y) && canAtk(x, y, e.x, e.y)) targs.push_back({x, y});
|
|
571
|
+
}
|
|
572
|
+
wD = 0.8f; break;
|
|
573
|
+
}
|
|
574
|
+
case R_SUPPORT: {
|
|
575
|
+
int p = parm[k];
|
|
576
|
+
if (md(ux[k], uy[k], ux[p], uy[p]) <= 1) targs.push_back({ux[k], uy[k]});
|
|
577
|
+
for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) {
|
|
578
|
+
if (abs(dx) + abs(dy) != 1) continue;
|
|
579
|
+
int x = ux[p] + dx, y = uy[p] + dy;
|
|
580
|
+
if (openc(x, y)) targs.push_back({x, y});
|
|
581
|
+
}
|
|
582
|
+
wD = 1.0f; break;
|
|
583
|
+
}
|
|
584
|
+
case R_ESCORT: {
|
|
585
|
+
int p = parm[k];
|
|
586
|
+
if (md(ux[k], uy[k], ux[p], uy[p]) <= 1) targs.push_back({ux[k], uy[k]});
|
|
587
|
+
for (int dy = -1; dy <= 1; dy++) for (int dx = -1; dx <= 1; dx++) {
|
|
588
|
+
if (abs(dx) + abs(dy) != 1) continue;
|
|
589
|
+
int x = ux[p] + dx, y = uy[p] + dy;
|
|
590
|
+
if (openc(x, y)) targs.push_back({x, y});
|
|
591
|
+
}
|
|
592
|
+
wD = role[k] == R_SUPPORT ? 1.0f : 0.8f; break;
|
|
593
|
+
}
|
|
594
|
+
case R_HUNT: targs = {{parm2[k] % S, parm2[k] / S}}; wD = 0.7f; break;
|
|
595
|
+
case R_CAMP:
|
|
596
|
+
if (parm[k] >= 0) targs = {spotsG[parm[k]]};
|
|
597
|
+
else targs = myBase9;
|
|
598
|
+
wD = 1.3f; break;
|
|
599
|
+
default: continue;
|
|
600
|
+
}
|
|
601
|
+
if (targs.empty()) continue;
|
|
602
|
+
// 残血也照常作战(死亡很便宜,10 回合满血重生);携旗者才惜命
|
|
603
|
+
float thr = (role[k] == R_CARRY) ? 0.45f * uhp[k] : max(0.85f * uhp[k], 0.6f * MAXHP);
|
|
604
|
+
float imbW = (role[k] == R_CARRY) ? 1.0f : (role[k] == R_FETCH || role[k] == R_CAMP) ? 0.7f : 0.25f;
|
|
605
|
+
auto ldanger = [&](int c) -> float {
|
|
606
|
+
float imb = (float)enN[c] - ((float)allySplash[c] - (md(ux[k], uy[k], c % S, c / S) <= 3 ? 1.f : 0.f));
|
|
607
|
+
return danger[c] + imbW * min(max(imb, 0.f), 2.f);
|
|
608
|
+
};
|
|
609
|
+
D.assign(S * S, 1e18f);
|
|
610
|
+
priority_queue<pair<float,int>, vector<pair<float,int>>, greater<pair<float,int>>> pq;
|
|
611
|
+
for (auto& p : targs) { int c = ID(p.first, p.second); if (openc(p.first, p.second) && D[c] > 0) { D[c] = 0.f; pq.push({0.f, c}); } }
|
|
612
|
+
auto pen = [&](int c) -> bool { return 34.f * ldanger(c) >= thr; };
|
|
613
|
+
while (!pq.empty()) {
|
|
614
|
+
pair<float,int> pr = pq.top(); pq.pop();
|
|
615
|
+
float d = pr.first; int c = pr.second;
|
|
616
|
+
if (d > D[c] + 1e-6f) continue;
|
|
617
|
+
int x = c % S, y = c / S;
|
|
618
|
+
for (int i = 0; i < 4; i++) {
|
|
619
|
+
int ax = x + DX[i], ay = y + DY[i];
|
|
620
|
+
if (!openc(ax, ay)) continue;
|
|
621
|
+
int ac = ID(ax, ay);
|
|
622
|
+
float cost = 1.f + wD * ldanger(ac) + ((pen(ac) && ac != allow) ? 30.f : 0.f);
|
|
623
|
+
if (d + cost < D[ac] - 1e-6f) { D[ac] = d + cost; pq.push({D[ac], ac}); }
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
int cur = ID(ux[k], uy[k]);
|
|
627
|
+
if (D[cur] <= 0.f || D[cur] > 1e17f) continue; // 已在目标 / 不可达:原地
|
|
628
|
+
int best = -1; float bestv = 1e18f;
|
|
629
|
+
for (int i = 0; i < 4; i++) {
|
|
630
|
+
int ax = ux[k] + DX[i], ay = uy[k] + DY[i];
|
|
631
|
+
if (!openc(ax, ay)) continue;
|
|
632
|
+
int ac = ID(ax, ay);
|
|
633
|
+
if (of.count(ac)) continue; // 被队友占用/认领
|
|
634
|
+
bool enemyOn = false;
|
|
635
|
+
for (auto& e : en) if (e.x == ax && e.y == ay) { enemyOn = true; break; }
|
|
636
|
+
if (enemyOn) continue;
|
|
637
|
+
float v = 1.f + wD * ldanger(ac) + ((pen(ac) && ac != allow) ? 30.f : 0.f) + D[ac];
|
|
638
|
+
if (v < bestv) { bestv = v; best = ac; }
|
|
639
|
+
}
|
|
640
|
+
if (best < 0) continue;
|
|
641
|
+
if (pen(best) && !pen(cur) && ldanger(cur) < ldanger(best)) continue; // 不踏进致命格,先等一步
|
|
642
|
+
of.erase(cur); of.insert(best);
|
|
643
|
+
nx[k] = best % S; ny[k] = best / S;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// ---- 动作
|
|
647
|
+
string out = to_string(T);
|
|
648
|
+
for (int k = 0; k < 3; k++) {
|
|
649
|
+
string mv = "S", act = "-";
|
|
650
|
+
if (alive[k]) {
|
|
651
|
+
int ddx = nx[k] - ux[k], ddy = ny[k] - uy[k];
|
|
652
|
+
if (ddx == 1) mv = "R"; else if (ddx == -1) mv = "L"; else if (ddy == 1) mv = "D"; else if (ddy == -1) mv = "U";
|
|
653
|
+
if (uflag[k] < 0) {
|
|
654
|
+
bool onF = false;
|
|
655
|
+
for (auto& f : g.flags) if ((f.status == "home" || f.status == "dropped") && f.return_at != T && f.x == nx[k] && f.y == ny[k]) onF = true;
|
|
656
|
+
if (onF) act = "P";
|
|
657
|
+
else if (!respNow[k]) {
|
|
658
|
+
int bestT = -1; float bs = -1e9;
|
|
659
|
+
for (auto& e : en) {
|
|
660
|
+
if (!canAtk(nx[k], ny[k], e.x, e.y)) continue;
|
|
661
|
+
float s = 0;
|
|
662
|
+
if (e.flag >= 0) s += 100; // 敌方携旗手
|
|
663
|
+
if (dB[ME][ID(e.x, e.y)] <= 2) s += 80; // 在我基地附近
|
|
664
|
+
for (auto& f : g.flags) if ((f.status == "home" || f.status == "dropped") && f.return_at != T && f.x == e.x && f.y == e.y) s += 90; // 站在旗上
|
|
665
|
+
for (int j = 0; j < 3; j++) if (alive[j] && uflag[j] >= 0 && md(e.x, e.y, nx[j], ny[j]) <= 3) s += 50;
|
|
666
|
+
int hits = 0;
|
|
667
|
+
for (int j = 0; j < 3; j++) if (alive[j] && uflag[j] < 0 && !respNow[j] && canAtk(nx[j], ny[j], e.x, e.y)) hits++;
|
|
668
|
+
if (e.hp <= hits * DMG) s += 55; // 集火可击杀
|
|
669
|
+
s += (MAXHP - e.hp) * 0.25f;
|
|
670
|
+
if (s > bs) { bs = s; bestT = e.id; }
|
|
671
|
+
}
|
|
672
|
+
if (bestT >= 0) act = to_string(bestT);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
out += " " + mv + " " + act;
|
|
677
|
+
}
|
|
678
|
+
static const char* rname[9] = {"cy","fe","cl","su","es","hu","ca","id","xx"};
|
|
679
|
+
string note = "#";
|
|
680
|
+
for (int k = 0; k < 3; k++) { if (k) note += ";"; note += rname[role[k] < 9 ? role[k] : 8]; }
|
|
681
|
+
out += " " + note;
|
|
682
|
+
return out;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
int main() {
|
|
686
|
+
ios::sync_with_stdio(false);
|
|
687
|
+
Game g;
|
|
688
|
+
while (read_turn(g)) cout << decide(g) << endl;
|
|
689
|
+
}
|