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,356 @@
|
|
|
1
|
+
// 陪练 bot(sparring):只以编译好的程序发给选手,源码不外发。
|
|
2
|
+
// 策略:每回合重新规划"出圈-横移-回家"路线,按引擎规则模拟圈地收益;
|
|
3
|
+
// 用所有对手到各格的最短步数估计被切断的风险;能安全切断对手时主动出击;避开撞头。
|
|
4
|
+
#include <bits/stdc++.h>
|
|
5
|
+
using namespace std;
|
|
6
|
+
|
|
7
|
+
const int DX[4] = {0, 0, -1, 1};
|
|
8
|
+
const int DY[4] = {-1, 1, 0, 0};
|
|
9
|
+
const char DC[4] = {'U', 'D', 'L', 'R'};
|
|
10
|
+
|
|
11
|
+
int W, H, MT, N, ME, MOVE_MS, INIT_MS, S;
|
|
12
|
+
struct Pl { int x, y, d, tl, area, deaths; };
|
|
13
|
+
vector<Pl> pl;
|
|
14
|
+
vector<int> own, tr, prot;
|
|
15
|
+
vector<pair<int, int>> spawn;
|
|
16
|
+
int turnNo;
|
|
17
|
+
vector<int> lastPos;
|
|
18
|
+
vector<char> outP;
|
|
19
|
+
chrono::steady_clock::time_point t0;
|
|
20
|
+
|
|
21
|
+
double elapsed() { return chrono::duration<double, milli>(chrono::steady_clock::now() - t0).count(); }
|
|
22
|
+
inline int cid(int x, int y) { return y * W + x; }
|
|
23
|
+
inline int nb(int c, int d) {
|
|
24
|
+
int x = c % W + DX[d], y = c / W + DY[d];
|
|
25
|
+
if (x < 0 || x >= W || y < 0 || y >= H) return -1;
|
|
26
|
+
return cid(x, y);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
bool readState() {
|
|
30
|
+
string tok;
|
|
31
|
+
if (!(cin >> tok)) return false;
|
|
32
|
+
cin >> turnNo;
|
|
33
|
+
pl.assign(N, {});
|
|
34
|
+
for (int i = 0; i < N; i++) {
|
|
35
|
+
int id; char d; Pl q;
|
|
36
|
+
cin >> tok >> id >> q.x >> q.y >> d >> q.tl >> q.area >> q.deaths;
|
|
37
|
+
q.d = string("UDLR").find(d);
|
|
38
|
+
pl[id] = q;
|
|
39
|
+
}
|
|
40
|
+
cin >> tok;
|
|
41
|
+
for (int y = 0; y < H; y++) {
|
|
42
|
+
string row; cin >> row;
|
|
43
|
+
for (int x = 0; x < W; x++) own[cid(x, y)] = row[x] == '.' ? -1 : row[x] - '0';
|
|
44
|
+
}
|
|
45
|
+
cin >> tok;
|
|
46
|
+
for (int y = 0; y < H; y++) {
|
|
47
|
+
string row; cin >> row;
|
|
48
|
+
for (int x = 0; x < W; x++) tr[cid(x, y)] = row[x] == '.' ? -1 : row[x] - '0';
|
|
49
|
+
}
|
|
50
|
+
cin >> tok;
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------- per-turn fields ----------
|
|
55
|
+
vector<vector<int>> edist; // edist[j][c]: steps for enemy j to reach c (ignores obstacles)
|
|
56
|
+
vector<int> threat; // min over active enemies
|
|
57
|
+
vector<int> ehome; // enemy j: steps home avoiding its own trail (INF if inside)
|
|
58
|
+
vector<char> danger; // cells an enemy head may enter next turn (or occupies now)
|
|
59
|
+
const int INF = 1e9;
|
|
60
|
+
|
|
61
|
+
void bfsFrom(int src, vector<int>& dist) {
|
|
62
|
+
dist.assign(S, INF);
|
|
63
|
+
deque<int> q; dist[src] = 0; q.push_back(src);
|
|
64
|
+
while (!q.empty()) {
|
|
65
|
+
int c = q.front(); q.pop_front();
|
|
66
|
+
for (int d = 0; d < 4; d++) {
|
|
67
|
+
int n = nb(c, d);
|
|
68
|
+
if (n >= 0 && dist[n] == INF) { dist[n] = dist[c] + 1; q.push_back(n); }
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
int homeDist(int j) {
|
|
74
|
+
int src = cid(pl[j].x, pl[j].y);
|
|
75
|
+
if (own[src] == j) return 0;
|
|
76
|
+
vector<int> dist(S, INF);
|
|
77
|
+
deque<int> q; dist[src] = 0; q.push_back(src);
|
|
78
|
+
while (!q.empty()) {
|
|
79
|
+
int c = q.front(); q.pop_front();
|
|
80
|
+
if (own[c] == j) return dist[c];
|
|
81
|
+
for (int d = 0; d < 4; d++) {
|
|
82
|
+
int n = nb(c, d);
|
|
83
|
+
if (n >= 0 && dist[n] == INF && tr[n] != j) { dist[n] = dist[c] + 1; q.push_back(n); }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return INF;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
void computeFields() {
|
|
90
|
+
edist.assign(N, {});
|
|
91
|
+
threat.assign(S, INF);
|
|
92
|
+
ehome.assign(N, INF);
|
|
93
|
+
danger.assign(S, 0);
|
|
94
|
+
for (int j = 0; j < N; j++) {
|
|
95
|
+
if (j == ME || outP[j]) continue;
|
|
96
|
+
int h = cid(pl[j].x, pl[j].y);
|
|
97
|
+
bfsFrom(h, edist[j]);
|
|
98
|
+
for (int c = 0; c < S; c++) threat[c] = min(threat[c], edist[j][c]);
|
|
99
|
+
ehome[j] = pl[j].tl > 0 ? homeDist(j) : 0;
|
|
100
|
+
danger[h] = 1;
|
|
101
|
+
for (int d = 0; d < 4; d++) {
|
|
102
|
+
if (d == (pl[j].d ^ 1)) continue;
|
|
103
|
+
int n = nb(h, d);
|
|
104
|
+
if (n >= 0) danger[n] = 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ---------- candidate evaluation ----------
|
|
110
|
+
bool isDuel() { return N == 2; }
|
|
111
|
+
double enemyW() { return isDuel() ? 2.0 : 1.35; }
|
|
112
|
+
int K() { return isDuel() ? 22 : 12; }
|
|
113
|
+
int MARGIN() { return isDuel() ? 1 : 2; }
|
|
114
|
+
|
|
115
|
+
vector<int> mark, seen;
|
|
116
|
+
int stampM = 1, stampS = 1;
|
|
117
|
+
vector<int> bq;
|
|
118
|
+
|
|
119
|
+
struct Cand {
|
|
120
|
+
vector<int> moves;
|
|
121
|
+
double score = -1e18, gain = 0;
|
|
122
|
+
int T = 0, margin = -INF;
|
|
123
|
+
bool ok = false;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Walk `moves`, then (if the loop is not closed yet) take the shortest path home.
|
|
127
|
+
Cand evaluate(vector<int> moves) {
|
|
128
|
+
Cand r;
|
|
129
|
+
int c = cid(pl[ME].x, pl[ME].y), dir = pl[ME].d;
|
|
130
|
+
stampM++;
|
|
131
|
+
vector<pair<int, int>> trail; // (cell, time placed)
|
|
132
|
+
for (int k = 0; k < S; k++) if (tr[k] == ME) { mark[k] = stampM; }
|
|
133
|
+
int existing = pl[ME].tl;
|
|
134
|
+
bool closed = false, hadTrail = existing > 0;
|
|
135
|
+
size_t used = 0;
|
|
136
|
+
double bonus = 0;
|
|
137
|
+
for (; used < moves.size(); used++) {
|
|
138
|
+
int m = moves[used];
|
|
139
|
+
if (m == (dir ^ 1)) return r;
|
|
140
|
+
int n = nb(c, m);
|
|
141
|
+
if (n < 0 || mark[n] == stampM) return r;
|
|
142
|
+
if (tr[n] >= 0 && tr[n] != ME) bonus += 6; // cutting an enemy trail
|
|
143
|
+
c = n; dir = m;
|
|
144
|
+
if (own[c] == ME) {
|
|
145
|
+
if (hadTrail) { closed = true; used++; break; }
|
|
146
|
+
} else {
|
|
147
|
+
mark[c] = stampM; trail.push_back({c, (int)used + 1}); hadTrail = true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
moves.resize(used);
|
|
151
|
+
if (!closed) {
|
|
152
|
+
if (!hadTrail) return r;
|
|
153
|
+
// BFS home avoiding marked trail; first step may not reverse `dir`
|
|
154
|
+
stampS++;
|
|
155
|
+
vector<int> par(0);
|
|
156
|
+
static vector<int> from, fdir;
|
|
157
|
+
from.assign(S, -1); fdir.assign(S, -1);
|
|
158
|
+
bq.clear();
|
|
159
|
+
seen[c] = stampS; bq.push_back(c);
|
|
160
|
+
int goal = -1;
|
|
161
|
+
for (size_t qi = 0; qi < bq.size() && goal < 0; qi++) {
|
|
162
|
+
int u = bq[qi];
|
|
163
|
+
for (int d = 0; d < 4; d++) {
|
|
164
|
+
if (u == c && d == (dir ^ 1)) continue;
|
|
165
|
+
int n = nb(u, d);
|
|
166
|
+
if (n < 0 || seen[n] == stampS || mark[n] == stampM) continue;
|
|
167
|
+
seen[n] = stampS; from[n] = u; fdir[n] = d; bq.push_back(n);
|
|
168
|
+
if (own[n] == ME) { goal = n; break; }
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (goal < 0) return r;
|
|
172
|
+
vector<int> tail;
|
|
173
|
+
for (int u = goal; u != c; u = from[u]) tail.push_back(fdir[u]);
|
|
174
|
+
reverse(tail.begin(), tail.end());
|
|
175
|
+
int t = moves.size();
|
|
176
|
+
int u = c;
|
|
177
|
+
for (int d : tail) {
|
|
178
|
+
u = nb(u, d); t++;
|
|
179
|
+
moves.push_back(d);
|
|
180
|
+
if (own[u] != ME) { mark[u] = stampM; trail.push_back({u, t}); }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
int T = moves.size();
|
|
184
|
+
if (T > MT - turnNo) return r;
|
|
185
|
+
// safety: every trail cell (existing ones too) must stay out of enemy reach until closure
|
|
186
|
+
int margin = INF;
|
|
187
|
+
for (int k = 0; k < S; k++) if (tr[k] == ME) margin = min(margin, threat[k] - T);
|
|
188
|
+
for (auto& [cell, tp] : trail) margin = min(margin, threat[cell] - T);
|
|
189
|
+
// gain: flood from the border with (my land + trail) as walls
|
|
190
|
+
stampS++;
|
|
191
|
+
bq.clear();
|
|
192
|
+
auto wall = [&](int k) { return own[k] == ME || mark[k] == stampM; };
|
|
193
|
+
for (int x = 0; x < W; x++) for (int y : {0, H - 1}) {
|
|
194
|
+
int k = cid(x, y);
|
|
195
|
+
if (!wall(k) && seen[k] != stampS) { seen[k] = stampS; bq.push_back(k); }
|
|
196
|
+
}
|
|
197
|
+
for (int y = 0; y < H; y++) for (int x : {0, W - 1}) {
|
|
198
|
+
int k = cid(x, y);
|
|
199
|
+
if (!wall(k) && seen[k] != stampS) { seen[k] = stampS; bq.push_back(k); }
|
|
200
|
+
}
|
|
201
|
+
for (size_t qi = 0; qi < bq.size(); qi++) {
|
|
202
|
+
int u = bq[qi];
|
|
203
|
+
for (int d = 0; d < 4; d++) {
|
|
204
|
+
int n = nb(u, d);
|
|
205
|
+
if (n >= 0 && !wall(n) && seen[n] != stampS) { seen[n] = stampS; bq.push_back(n); }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
double gain = 0, ew = enemyW();
|
|
209
|
+
for (int k = 0; k < S; k++) {
|
|
210
|
+
bool take = (mark[k] == stampM && own[k] != ME) || (!wall(k) && seen[k] != stampS);
|
|
211
|
+
if (!take || (prot[k] >= 0 && prot[k] != ME)) continue;
|
|
212
|
+
gain += own[k] >= 0 ? ew : 1.0;
|
|
213
|
+
}
|
|
214
|
+
r.moves = moves; r.T = T; r.margin = margin; r.gain = gain + bonus;
|
|
215
|
+
r.ok = true;
|
|
216
|
+
r.score = r.gain / (T + K());
|
|
217
|
+
return r;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
vector<int> plan;
|
|
221
|
+
|
|
222
|
+
bool better(const Cand& a, const Cand& b) { // a better than b
|
|
223
|
+
bool sa = a.margin >= MARGIN(), sb = b.margin >= MARGIN();
|
|
224
|
+
if (sa != sb) return sa;
|
|
225
|
+
if (sa) return a.score > b.score;
|
|
226
|
+
if (a.margin != b.margin) return a.margin > b.margin;
|
|
227
|
+
return a.T < b.T;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ---------- hunting ----------
|
|
231
|
+
int huntMove() {
|
|
232
|
+
int me = cid(pl[ME].x, pl[ME].y);
|
|
233
|
+
// BFS from my head avoiding my trail
|
|
234
|
+
vector<int> dist(S, INF), first(S, -1);
|
|
235
|
+
deque<int> q; dist[me] = 0; q.push_back(me);
|
|
236
|
+
while (!q.empty()) {
|
|
237
|
+
int u = q.front(); q.pop_front();
|
|
238
|
+
for (int d = 0; d < 4; d++) {
|
|
239
|
+
if (u == me && d == (pl[ME].d ^ 1)) continue;
|
|
240
|
+
int n = nb(u, d);
|
|
241
|
+
if (n < 0 || dist[n] != INF || tr[n] == ME) continue;
|
|
242
|
+
if (u == me && danger[n]) continue;
|
|
243
|
+
dist[n] = dist[u] + 1; first[n] = u == me ? d : first[u]; q.push_back(n);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
bool inside = own[me] == ME;
|
|
247
|
+
int limit = isDuel() ? (inside ? 16 : 8) : (inside ? 10 : 5);
|
|
248
|
+
int best = -1, bestD = INF;
|
|
249
|
+
for (int j = 0; j < N; j++) {
|
|
250
|
+
if (j == ME || outP[j] || pl[j].tl == 0) continue;
|
|
251
|
+
for (int c = 0; c < S; c++) {
|
|
252
|
+
if (tr[c] != j || dist[c] > limit || dist[c] > ehome[j] || dist[c] >= bestD) continue;
|
|
253
|
+
// other enemies must not be able to punish the chase
|
|
254
|
+
int other = INF;
|
|
255
|
+
for (int k = 0; k < N; k++)
|
|
256
|
+
if (k != ME && k != j && !outP[k]) other = min(other, edist[k][c]);
|
|
257
|
+
if (other <= dist[c] + 2) continue;
|
|
258
|
+
// my existing trail must survive the chase
|
|
259
|
+
bool safe = true;
|
|
260
|
+
for (int k = 0; k < S && safe; k++)
|
|
261
|
+
if (tr[k] == ME && threat[k] <= dist[c] + 3) safe = false;
|
|
262
|
+
if (!safe) continue;
|
|
263
|
+
best = first[c]; bestD = dist[c];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return best;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
int decide() {
|
|
270
|
+
t0 = chrono::steady_clock::now();
|
|
271
|
+
double budget = turnNo == 0 ? 300 : min(22.0, MOVE_MS * 0.44);
|
|
272
|
+
for (int j = 0; j < N; j++) {
|
|
273
|
+
int p = cid(pl[j].x, pl[j].y);
|
|
274
|
+
if (turnNo > 1 && p == lastPos[j] && pl[j].tl == 0 && j != ME) outP[j] = 1;
|
|
275
|
+
lastPos[j] = p;
|
|
276
|
+
}
|
|
277
|
+
computeFields();
|
|
278
|
+
int me = cid(pl[ME].x, pl[ME].y);
|
|
279
|
+
|
|
280
|
+
int h = huntMove();
|
|
281
|
+
if (h >= 0) { plan.clear(); return h; }
|
|
282
|
+
|
|
283
|
+
Cand best;
|
|
284
|
+
auto consider = [&](const vector<int>& mv) {
|
|
285
|
+
Cand c = evaluate(mv);
|
|
286
|
+
if (c.ok && (!best.ok || better(c, best))) best = c;
|
|
287
|
+
};
|
|
288
|
+
// continue the previous plan (with a small preference)
|
|
289
|
+
if (!plan.empty()) {
|
|
290
|
+
Cand c = evaluate(plan);
|
|
291
|
+
if (c.ok) { c.score *= 1.08; best = c; }
|
|
292
|
+
}
|
|
293
|
+
consider({}); // straight home when outside
|
|
294
|
+
int maxL1 = max(W, H) / 2, maxL2 = 16;
|
|
295
|
+
for (int L1 = 1; L1 <= maxL1 && elapsed() < budget; L1++) {
|
|
296
|
+
for (int d0 = 0; d0 < 4; d0++) {
|
|
297
|
+
if (d0 == (pl[ME].d ^ 1)) continue;
|
|
298
|
+
for (int s = 0; s < 2; s++) {
|
|
299
|
+
int d1 = d0 < 2 ? 2 + s : s;
|
|
300
|
+
for (int L2 = 1; L2 <= maxL2; L2++) {
|
|
301
|
+
vector<int> mv(L1, d0);
|
|
302
|
+
mv.insert(mv.end(), L2, d1);
|
|
303
|
+
consider(mv);
|
|
304
|
+
// box: come back parallel to the first leg for L1 steps, then home
|
|
305
|
+
vector<int> mv2 = mv;
|
|
306
|
+
mv2.insert(mv2.end(), L1, d0 ^ 1);
|
|
307
|
+
consider(mv2);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
int move = -1;
|
|
313
|
+
if (best.ok && !best.moves.empty()) {
|
|
314
|
+
plan.assign(best.moves.begin() + 1, best.moves.end());
|
|
315
|
+
move = best.moves[0];
|
|
316
|
+
}
|
|
317
|
+
// final safety: never hit a wall / own trail; avoid head-on cells if possible
|
|
318
|
+
auto legal = [&](int d) {
|
|
319
|
+
if (d == (pl[ME].d ^ 1)) return false;
|
|
320
|
+
int n = nb(me, d);
|
|
321
|
+
return n >= 0 && tr[n] != ME;
|
|
322
|
+
};
|
|
323
|
+
if (move < 0 || !legal(move) || danger[nb(me, move)]) {
|
|
324
|
+
int alt = -1, altScore = -INF;
|
|
325
|
+
for (int d = 0; d < 4; d++) {
|
|
326
|
+
if (!legal(d)) continue;
|
|
327
|
+
int n = nb(me, d);
|
|
328
|
+
int sc = (danger[n] ? -1000 : 0) + (own[n] == ME ? 50 : 0) + min(threat[n], 50);
|
|
329
|
+
if (move == d) sc += 30;
|
|
330
|
+
if (sc > altScore) { altScore = sc; alt = d; }
|
|
331
|
+
}
|
|
332
|
+
if (alt >= 0 && alt != move) { move = alt; plan.clear(); }
|
|
333
|
+
if (move < 0) move = pl[ME].d;
|
|
334
|
+
}
|
|
335
|
+
return move;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
int main() {
|
|
339
|
+
ios::sync_with_stdio(false);
|
|
340
|
+
cin.tie(nullptr);
|
|
341
|
+
string tok;
|
|
342
|
+
cin >> tok >> W >> H >> MT >> N >> ME >> MOVE_MS >> INIT_MS;
|
|
343
|
+
S = W * H;
|
|
344
|
+
spawn.resize(N);
|
|
345
|
+
for (int i = 0; i < N; i++) { int id, x, y; cin >> tok >> id >> x >> y; spawn[id] = {x, y}; }
|
|
346
|
+
own.assign(S, -1); tr.assign(S, -1); prot.assign(S, -1);
|
|
347
|
+
mark.assign(S, 0); seen.assign(S, 0);
|
|
348
|
+
for (int i = 0; i < N; i++)
|
|
349
|
+
for (int y = spawn[i].second - 1; y <= spawn[i].second + 1; y++)
|
|
350
|
+
for (int x = spawn[i].first - 1; x <= spawn[i].first + 1; x++) prot[cid(x, y)] = i;
|
|
351
|
+
lastPos.assign(N, -1); outP.assign(N, 0);
|
|
352
|
+
while (readState()) {
|
|
353
|
+
int d = decide();
|
|
354
|
+
cout << turnNo << ' ' << DC[d] << endl;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# 圈地对战:规则与通信协议
|
|
2
|
+
|
|
3
|
+
规则以 `engine/game.py` 为准;本文档与代码描述的是同一套行为。如有疑问,以代码为准。
|
|
4
|
+
|
|
5
|
+
## 1. 两种赛制
|
|
6
|
+
|
|
7
|
+
比赛有两种赛制,**你的同一个 bot 两种都要参加**,由开局信息里的玩家数 `N` 区分:
|
|
8
|
+
|
|
9
|
+
| 赛制 | 玩家数 N | 棋盘 | 回合数 | 出生点 |
|
|
10
|
+
|---|---|---|---|---|
|
|
11
|
+
| **单挑** | 2 | 40 × 40 | 600 | 玩家 1 = 玩家 0 绕棋盘中心旋转 180° |
|
|
12
|
+
| **混战** | 4 | 48 × 48 | 600 | 玩家 k = 玩家 0 绕棋盘中心顺时针旋转 k × 90° |
|
|
13
|
+
|
|
14
|
+
- 坐标 `(x, y)`:x 为列(向右增大),y 为行(向下增大),都从 0 开始。
|
|
15
|
+
- 玩家 0 的出生点由地图种子随机生成(单挑距边界至少 4 格,混战至少 5 格);任意两个出生点的曼哈顿距离至少 16。初始方向也按同样的旋转对应。
|
|
16
|
+
- 初始领地:以出生点为中心的 **5 × 5** 方块。
|
|
17
|
+
- 保护区:以出生点为中心的 **3 × 3** 方块。保护区永远属于该玩家,任何方式都无法占领。
|
|
18
|
+
- 两种赛制的规则完全相同,只有玩家数和棋盘大小不同。**不要假设只有一个对手**:混战里有 3 个对手,任何一个都可能切断你。
|
|
19
|
+
|
|
20
|
+
## 2. 每回合流程
|
|
21
|
+
|
|
22
|
+
所有玩家**同时**行动。每回合按以下顺序结算:
|
|
23
|
+
|
|
24
|
+
1. **确定方向**:每名玩家给出 `U`(上,y−1)、`D`(下,y+1)、`L`(左,x−1)、`R`(右,x+1)之一。
|
|
25
|
+
- 选择与当前方向**相反**的方向(掉头)视为无效,继续沿当前方向前进。
|
|
26
|
+
- 超时、输出格式错误,同样沿当前方向前进。
|
|
27
|
+
2. **撞墙**:目标格超出棋盘,该玩家阵亡。
|
|
28
|
+
3. **撞头**:两名玩家的目标格相同,或两人互换位置(A 走到 B 当前格、同时 B 走到 A 当前格),**双方都阵亡**。三人或更多人走进同一格,全部阵亡。
|
|
29
|
+
4. **切断轨迹**:若某玩家的目标格上有轨迹,**该轨迹的主人阵亡**(走进自己的轨迹则是自己阵亡)。
|
|
30
|
+
- 本步判定使用本回合移动前的轨迹。
|
|
31
|
+
- 玩家在领地外时,头部所在格也是其轨迹的一部分,所以走到对手当前头部所在格(对手在领地外时)也会切断对手。
|
|
32
|
+
- 切断者本人如果同时满足第 2、3 条,也会阵亡。
|
|
33
|
+
5. **阵亡处理**:阵亡玩家的轨迹全部清除,立即传送回出生点,方向恢复为初始方向。**领地保留。** 阵亡玩家本回合不再移动。
|
|
34
|
+
6. **移动**:存活玩家移动到目标格。
|
|
35
|
+
- 目标格**不是**自己的领地(中立格或对手领地):该格加入自己的轨迹。
|
|
36
|
+
- 目标格**是**自己的领地,且当前有轨迹:本回合圈地(见下)。
|
|
37
|
+
7. **圈地**:对每个本回合圈地的玩家 P,计算:
|
|
38
|
+
- P 的全部轨迹格变为 P 的领地;
|
|
39
|
+
- **被围区域**:把 P 的领地和轨迹看作墙,从棋盘边界向内做四连通泛洪,泛洪到达不了的非墙格,全部变为 P 的领地(可以包括中立格和对手领地)。
|
|
40
|
+
- 例外:对手的保护区永远不会改变归属。
|
|
41
|
+
- 多名玩家同一回合都圈地时,每人的结果都基于圈地前的棋盘计算,然后同时生效;同一格被两人或更多人同时围住,则保持原归属不变。
|
|
42
|
+
- 圈地后 P 的轨迹清空。
|
|
43
|
+
- 对手的轨迹格被 P 圈住时,该格归属变为 P,但对手的轨迹仍在,对手不会因此阵亡。
|
|
44
|
+
|
|
45
|
+
## 3. 胜负
|
|
46
|
+
|
|
47
|
+
- 600 回合结束后按**领地格数**排名,格数多者名次靠前,格数相同则名次并列。
|
|
48
|
+
- 单挑:领地多者胜,相同则平局。
|
|
49
|
+
- 混战:4 人排出第 1–4 名。
|
|
50
|
+
- 只看名次,**领先多少不影响结果**。
|
|
51
|
+
- 判负:
|
|
52
|
+
- 程序崩溃、退出,或无法写入;
|
|
53
|
+
- 单局内超时与格式错误累计达到 **10 次**。
|
|
54
|
+
- 单挑中判负:该局立即结束,另一方获胜(双方同时判负则平局)。
|
|
55
|
+
- 混战中判负:该玩家立即出局,排在所有未判负玩家之后(多人判负则并列)。出局玩家的轨迹清除,它停在出生点不再移动,也不会再阵亡;它的领地留在棋盘上,可以被其他玩家圈走(保护区除外)。其余玩家继续比赛。
|
|
56
|
+
|
|
57
|
+
## 4. 通信协议
|
|
58
|
+
|
|
59
|
+
bot 是一个独立进程,从 **stdin** 读取,向 **stdout** 输出。所有消息都是以 `\n` 结尾的文本行,以空白分隔。
|
|
60
|
+
|
|
61
|
+
### 4.1 开局(只发送一次)
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
INIT
|
|
65
|
+
W H MAX_TURNS N MY_ID MOVE_MS INIT_MS
|
|
66
|
+
SPAWN 0 x0 y0
|
|
67
|
+
SPAWN 1 x1 y1
|
|
68
|
+
...(共 N 行)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- 单挑:`W=40 H=40 MAX_TURNS=600 N=2`;混战:`W=48 H=48 MAX_TURNS=600 N=4`。两种赛制都是 `MOVE_MS=50 INIT_MS=2000`。
|
|
72
|
+
- `MY_ID` 是你的编号(0 到 N−1)。
|
|
73
|
+
|
|
74
|
+
### 4.2 每回合(t = 0, 1, …, MAX_TURNS−1)
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
TURN t
|
|
78
|
+
P 0 x y dir trail_len area deaths
|
|
79
|
+
...(共 N 行,玩家 0 到 N−1)
|
|
80
|
+
OWNER
|
|
81
|
+
<H 行,每行 W 个字符>
|
|
82
|
+
TRAIL
|
|
83
|
+
<H 行,每行 W 个字符>
|
|
84
|
+
END
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- `P` 行:玩家编号、头部坐标、当前方向(`U/D/L/R`)、轨迹长度、领地格数、累计阵亡次数。
|
|
88
|
+
- `OWNER` 网格:第 y 行第 x 个字符表示格 `(x, y)` 的领地归属:`.` 中立,`0`–`3` 为对应玩家。
|
|
89
|
+
- `TRAIL` 网格:`.` 无轨迹,`0`–`3` 为对应玩家的轨迹。
|
|
90
|
+
- 回合 t 的状态是第 t 次移动**之前**的局面。
|
|
91
|
+
- 混战中已出局的玩家仍然有 `P` 行:坐标是它的出生点,轨迹长度 0。
|
|
92
|
+
|
|
93
|
+
### 4.3 回应
|
|
94
|
+
|
|
95
|
+
每收到一个回合,输出一行:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
t DIR
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`t` 是该回合编号,`DIR` 是 `U`/`D`/`L`/`R`。**每次输出后必须 flush**(C++ 中 `std::endl` 或 `std::cout.flush()`)。
|
|
102
|
+
|
|
103
|
+
- 时限:第 0 回合 **2000 ms**(含程序启动),之后每回合 **50 ms**,从状态发出开始计时。裁判有少量容差,不要依赖它。
|
|
104
|
+
- 超时:本回合沿当前方向前进,记 1 次错误。迟到的回应(回合号小于当前回合)会被静默丢弃。
|
|
105
|
+
- 格式错误的行:记 1 次错误,本回合沿当前方向前进。
|
|
106
|
+
- 所有调试信息请写到 **stderr**;stdout 只能输出回应行。
|
|
107
|
+
- 注意:如果你的程序持续算得太慢,读取就会落后于裁判,后续每个回合都会超时。
|
|
108
|
+
|
|
109
|
+
## 5. 对手与地图
|
|
110
|
+
|
|
111
|
+
- 地图只由种子决定(出生点、初始方向),没有障碍物。
|
|
112
|
+
- 单挑:每对选手在同一批地图上对战,每张图交换出生位各打一局。
|
|
113
|
+
- 混战:每轮把所有参赛 bot 随机分成若干桌,每桌 4 个 bot;同一桌在同一张图上轮换座位打 4 局,每个 bot 每个座位各坐一次。
|
|
114
|
+
- 对手包括其他 AI 模型编写的 bot,以及两个基准 bot(`anchors/` 下的 random 与 greedy)。
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# 任务:编写圈地对战 bot
|
|
2
|
+
|
|
3
|
+
为"圈地对战"写一个尽可能强的 C++ bot。它会和其他 AI 模型写的 bot 进行 **1 对 1 单挑**和 **4 人混战**两种赛制的对局,两种都计分。
|
|
4
|
+
|
|
5
|
+
完整规则和通信协议见 `RULES.md`,规则以 `engine/game.py` 为准。
|
|
6
|
+
|
|
7
|
+
## 工作目录
|
|
8
|
+
|
|
9
|
+
| 路径 | 内容 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `RULES.md` | 规则与通信协议 |
|
|
12
|
+
| `clock.py` | 计时器:`python3 clock.py` 显示已用时间 |
|
|
13
|
+
| `engine/` | 规则引擎 `game.py`、本地裁判 `referee.py` |
|
|
14
|
+
| `anchors/` | 两个基准 bot(random、greedy) |
|
|
15
|
+
| `starter/bot.cpp` | 起步模板,已实现协议读写 |
|
|
16
|
+
| `viewer/viewer.html` | 回放查看器(给人看的) |
|
|
17
|
+
| `submission/` | 最终 bot 放在 `submission/bot.cpp` |
|
|
18
|
+
|
|
19
|
+
本地对战(`.cpp` 会自动编译;没有 `python3` 就用 `python`):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python3 engine/referee.py submission/bot.cpp anchors/greedy.cpp --games 10 # 单挑
|
|
23
|
+
python3 engine/referee.py submission/bot.cpp anchors/greedy.cpp anchors/greedy.cpp anchors/random.cpp --games 8 # 混战
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
其他参数见 `python3 engine/referee.py -h`。
|
|
27
|
+
|
|
28
|
+
## 提交要求
|
|
29
|
+
|
|
30
|
+
1. 单个文件 `submission/bot.cpp`,同一个程序要能打单挑和混战(根据开局的 `N` 判断)。
|
|
31
|
+
2. 编译命令 `g++ -O2 -std=c++20 bot.cpp`,只用 C++ 标准库,单线程,内存 512 MB 以内。
|
|
32
|
+
3. bot 程序不得访问网络或读写文件,不得在对局之间保存信息。
|
|
33
|
+
4. 每回合 50 ms,第 0 回合 2000 ms。崩溃或单局累计 10 次超时/格式错误判负。正式比赛会在同一台机器上同时进行多局,CPU 负载比你本地测试时高,请为每回合的计算时间留足余量。
|
|
34
|
+
5. 工作时只能读写当前 `workspace` 文件夹里的文件,不要访问这个文件夹以外的任何内容。
|
|
35
|
+
|
|
36
|
+
## 评分
|
|
37
|
+
|
|
38
|
+
单挑循环赛 + 多轮随机分桌的混战,只看名次。每种赛制用 Bradley-Terry 模型拟合实力值,greedy 基准 = 0 分、本期最强者 = 100 分;两种赛制的分数加权合成总分,单挑的权重不低于混战。
|
|
39
|
+
|
|
40
|
+
对手是其他 AI 模型写的 bot 和两个基准 bot,可能还有出题方的参考 bot。两个基准 bot 很弱,只用来确认程序能正常运行,打赢它们说明不了你的 bot 有多强;怎样检验和提高强度,由你自己决定。
|
|
41
|
+
|
|
42
|
+
## 时间
|
|
43
|
+
|
|
44
|
+
时间预算约 **60 分钟**,请自己把握进度,做完就可以结束。超过 90 分钟会被强制停止,以当时的 `submission/bot.cpp` 为准。`python3 clock.py` 可以查看从解压到现在已经过了多久。
|
|
45
|
+
|
|
46
|
+
不能联网搜索,不要向用户提问,独立完成。结束时用几句话总结你的策略。
|
|
Binary file
|