dsh-eval-guard 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -13
- package/assets/bomberman/workspace.zip +0 -0
- package/assets/commit0/instance.json +30 -0
- package/assets/commit0/workspace.zip +0 -0
- package/assets/ctf/workspace.zip +0 -0
- package/assets/featurebench/hidden/test_regression.py +690 -0
- package/assets/featurebench/instance.json +16 -0
- package/assets/featurebench/workspace.zip +0 -0
- package/assets/swe-bench-pro/hidden/test.patch +36 -0
- package/assets/swe-bench-pro/instance.json +10 -0
- package/assets/swe-bench-pro/workspace.zip +0 -0
- package/assets/tank/workspace.zip +0 -0
- package/eval/README.md +18 -0
- package/eval/arena/arena/README.md +21 -0
- package/eval/arena/arena/bt.py +104 -0
- package/eval/arena/arena/clock.py +15 -0
- package/eval/arena/arena/core.py +265 -0
- package/eval/arena/arena/run.cmd +24 -0
- package/eval/arena/arena/run.sh +11 -0
- package/eval/arena/arena/schedule.py +79 -0
- package/eval/arena/arena/tournament.py +183 -0
- package/eval/arena/bomberman/bots/README.md +16 -0
- package/eval/arena/bomberman/bots/deepseek-v4.1-flash.cpp +447 -0
- package/eval/arena/bomberman/bots/doubao-seed-2.1.cpp +542 -0
- package/eval/arena/bomberman/bots/glm-5.3.cpp +406 -0
- package/eval/arena/bomberman/bots/gpt-6-astra.cpp +768 -0
- package/eval/arena/bomberman/bots/gpt-6-sol.cpp +444 -0
- package/eval/arena/bomberman/bots/kimi-k3.cpp +432 -0
- package/eval/arena/bomberman/bots/mimo-v2.6-pro.cpp +529 -0
- package/eval/arena/bomberman/bots/opus-5.5.cpp +548 -0
- package/eval/arena/bomberman/bots/qwen-3.8-max.cpp +836 -0
- package/eval/arena/bomberman/tournament/README.md +11 -0
- package/eval/arena/bomberman/tournament/bt.py +56 -0
- package/eval/arena/bomberman/tournament/evaluate.py +199 -0
- package/eval/arena/bomberman/tournament/run.py +79 -0
- package/eval/arena/bomberman/tournament/schedule-2to10.json.gz +0 -0
- package/eval/arena/bomberman/workspace/MANIFEST.json +13 -0
- package/eval/arena/bomberman/workspace/README.md +29 -0
- package/eval/arena/bomberman/workspace/RULES.md +100 -0
- package/eval/arena/bomberman/workspace/baseline.cpp +240 -0
- package/eval/arena/bomberman/workspace/clock.py +25 -0
- package/eval/arena/bomberman/workspace/engine/arena.py +198 -0
- package/eval/arena/bomberman/workspace/engine/build.py +35 -0
- package/eval/arena/bomberman/workspace/engine/engine.py +256 -0
- package/eval/arena/bomberman/workspace/engine/verify_replay.py +24 -0
- package/eval/arena/bomberman/workspace/run.cmd +28 -0
- package/eval/arena/bomberman/workspace/run.sh +16 -0
- package/eval/arena/bomberman/workspace/viewer/index.html +42 -0
- package/eval/arena/ctf/bots/README.md +18 -0
- package/eval/arena/ctf/bots/deepseek-v4.1-flash.cpp +601 -0
- package/eval/arena/ctf/bots/doubao-seed-2.1-turbo.cpp +320 -0
- package/eval/arena/ctf/bots/fable-5.1.cpp +634 -0
- package/eval/arena/ctf/bots/glm-5.3.cpp +689 -0
- package/eval/arena/ctf/bots/gpt-6-astra.cpp +657 -0
- package/eval/arena/ctf/bots/gpt-6.1-sol.cpp +725 -0
- package/eval/arena/ctf/bots/kimi-k3.cpp +667 -0
- package/eval/arena/ctf/bots/mimo-v2.6-pro.cpp +533 -0
- package/eval/arena/ctf/bots/opus-5.5.cpp +645 -0
- package/eval/arena/ctf/bots/qwen-3.8-max.cpp +726 -0
- package/eval/arena/ctf/bots/sonnet-5.5.cpp +569 -0
- package/eval/arena/ctf/tournament/README.md +15 -0
- package/eval/arena/ctf/tournament/formal-2to8.json +31 -0
- package/eval/arena/ctf/tournament/formal-9to15.json +31 -0
- package/eval/arena/ctf/workspace/README.md +41 -0
- package/eval/arena/ctf/workspace/RULES.md +119 -0
- package/eval/arena/ctf/workspace/arena.py +186 -0
- package/eval/arena/ctf/workspace/baseline.cpp +257 -0
- package/eval/arena/ctf/workspace/clock.py +15 -0
- package/eval/arena/ctf/workspace/core.py +265 -0
- package/eval/arena/ctf/workspace/engine.py +389 -0
- package/eval/arena/ctf/workspace/run.cmd +24 -0
- package/eval/arena/ctf/workspace/run.sh +11 -0
- package/eval/arena/ctf/workspace/viewer.html +71 -0
- package/eval/arena/land/bots/README.md +17 -0
- package/eval/arena/land/bots/deepseek-4.1f@workbuddy#1/bot.cpp +608 -0
- package/eval/arena/land/bots/glm-5.3@workbuddy#1/bot.cpp +521 -0
- package/eval/arena/land/bots/gpt-6-astra@codex#1/bot.cpp +373 -0
- package/eval/arena/land/bots/gpt-6-sol@codex#1/bot.cpp +341 -0
- package/eval/arena/land/bots/kimi-k3@workbuddy#1/bot.cpp +492 -0
- package/eval/arena/land/bots/mimo-2.6-pro@zcode#1/bot.cpp +652 -0
- package/eval/arena/land/bots/mystery-model@zcode#1/bot.cpp +466 -0
- package/eval/arena/land/bots/opus-5.5@claude-code#1/bot.cpp +630 -0
- package/eval/arena/land/bots/sonnet-5@claude-code#1/bot.cpp +619 -0
- package/eval/arena/land/tournament/make_replay_page.py +17 -0
- package/eval/arena/land/tournament/rate.py +290 -0
- package/eval/arena/land/tournament/round_robin.py +172 -0
- package/eval/arena/land/tournament/sparring.cpp +356 -0
- package/eval/arena/land/workspace/RULES.md +114 -0
- package/eval/arena/land/workspace/TASK.md +46 -0
- package/eval/arena/land/workspace/anchors/.build/greedy_f2e6d2dea5ca +0 -0
- package/eval/arena/land/workspace/anchors/greedy.cpp +194 -0
- package/eval/arena/land/workspace/anchors/random.cpp +80 -0
- package/eval/arena/land/workspace/clock.py +64 -0
- package/eval/arena/land/workspace/engine/build.py +33 -0
- package/eval/arena/land/workspace/engine/game.py +273 -0
- package/eval/arena/land/workspace/engine/referee.py +308 -0
- package/eval/arena/land/workspace/starter/.build/bot_be32b45b4699 +0 -0
- package/eval/arena/land/workspace/starter/bot.cpp +82 -0
- package/eval/arena/land/workspace/viewer/viewer.html +210 -0
- package/eval/arena/tank/bots/README.md +24 -0
- package/eval/arena/tank/bots/half1/deepseek-v4.1-flash.cpp +367 -0
- package/eval/arena/tank/bots/half1/doubao-seed-evolving.cpp +402 -0
- package/eval/arena/tank/bots/half1/gemini-4-argon.cpp +1132 -0
- package/eval/arena/tank/bots/half1/glm-5.3.cpp +551 -0
- package/eval/arena/tank/bots/half1/gpt-6-astra.cpp +233 -0
- package/eval/arena/tank/bots/half1/gpt-6.1-sol-ultrafast.cpp +350 -0
- package/eval/arena/tank/bots/half1/gpt-6.1-sol.cpp +78 -0
- package/eval/arena/tank/bots/half1/grok-4.7.cpp +1099 -0
- package/eval/arena/tank/bots/half1/haiku-5.5.cpp +210 -0
- package/eval/arena/tank/bots/half1/kimi-k3.cpp +353 -0
- package/eval/arena/tank/bots/half1/mimo-v2.6-pro.cpp +336 -0
- package/eval/arena/tank/bots/half1/muse-wonder-full.cpp +560 -0
- package/eval/arena/tank/bots/half1/opus-5.5.cpp +435 -0
- package/eval/arena/tank/bots/half1/qwen-3.8-max.cpp +537 -0
- package/eval/arena/tank/bots/half2/deepseek-v4.1-flash.cpp +425 -0
- package/eval/arena/tank/bots/half2/doubao-seed-evolving.cpp +308 -0
- package/eval/arena/tank/bots/half2/gemini-4-argon.cpp +1390 -0
- package/eval/arena/tank/bots/half2/glm-5.3.cpp +651 -0
- package/eval/arena/tank/bots/half2/gpt-6-astra.cpp +241 -0
- package/eval/arena/tank/bots/half2/gpt-6.1-sol-ultrafast.cpp +356 -0
- package/eval/arena/tank/bots/half2/gpt-6.1-sol.cpp +87 -0
- package/eval/arena/tank/bots/half2/grok-4.7.cpp +1205 -0
- package/eval/arena/tank/bots/half2/haiku-5.5.cpp +210 -0
- package/eval/arena/tank/bots/half2/kimi-k3.cpp +487 -0
- package/eval/arena/tank/bots/half2/mimo-v2.6-pro.cpp +336 -0
- package/eval/arena/tank/bots/half2/muse-wonder-full.cpp +560 -0
- package/eval/arena/tank/bots/half2/opus-5.5.cpp +476 -0
- package/eval/arena/tank/bots/half2/qwen-3.8-max.cpp +392 -0
- package/eval/arena/tank/tournament/README.md +24 -0
- package/eval/arena/tank/tournament/bt.py +218 -0
- package/eval/arena/tank/tournament/final.json +202 -0
- package/eval/arena/tank/tournament/halftime.json +146 -0
- package/eval/arena/tank/tournament/progress.json +911 -0
- package/eval/arena/tank/tournament/schedule.py +100 -0
- package/eval/arena/tank/tournament/sparring.cpp +928 -0
- package/eval/arena/tank/tournament/tournament.py +1426 -0
- package/eval/arena/tank/workspace/README.md +169 -0
- package/eval/arena/tank/workspace/RULES.md +443 -0
- package/eval/arena/tank/workspace/arena.py +862 -0
- package/eval/arena/tank/workspace/baseline.cpp +259 -0
- package/eval/arena/tank/workspace/clock.py +103 -0
- package/eval/arena/tank/workspace/core.py +712 -0
- package/eval/arena/tank/workspace/engine.py +573 -0
- package/eval/arena/tank/workspace/history/.lock +0 -0
- package/eval/arena/tank/workspace/history/20261017-193610-08715287f91f-bot.cpp +109 -0
- package/eval/arena/tank/workspace/history/20261017-193619-f00b2d5635fa-gpt-6-astra.cpp +241 -0
- package/eval/arena/tank/workspace/history/20261017-193643-63319e0a2b1a-gpt-6_1-sol-ultrafast.cpp +356 -0
- package/eval/arena/tank/workspace/history/20261017-193647-41c1341d0a8a-gemini-4-argon.cpp +1390 -0
- package/eval/arena/tank/workspace/history/20261017-193652-e34c0f45539a-gpt-6_1-sol.cpp +87 -0
- package/eval/arena/tank/workspace/history/20261017-193654-c026348ce96e-opus-5_5.cpp +476 -0
- package/eval/arena/tank/workspace/history/20261017-193655-4a21366e94d1-muse-wonder-full.cpp +560 -0
- package/eval/arena/tank/workspace/history/20261017-193657-dbc4e9969c52-mimo-v2_6-pro.cpp +336 -0
- package/eval/arena/tank/workspace/history/20261017-193703-723cd036eb31-grok-4_7.cpp +1205 -0
- package/eval/arena/tank/workspace/history/20261017-193707-1ebbb227be68-deepseek-v4_1-flash.cpp +425 -0
- package/eval/arena/tank/workspace/history/20261017-193709-aeb0e7202ad5-doubao-seed-evolving.cpp +308 -0
- package/eval/arena/tank/workspace/history/20261017-193710-b21ebeb9bc76-kimi-k3.cpp +487 -0
- package/eval/arena/tank/workspace/history/20261017-193712-54cd86531905-haiku-5_5.cpp +210 -0
- package/eval/arena/tank/workspace/history/20261017-193714-efdb8e35c0bf-qwen-3_8-max.cpp +392 -0
- package/eval/arena/tank/workspace/history/20261017-193715-681423c23fdb-glm-5_3.cpp +651 -0
- package/eval/arena/tank/workspace/history/20261017-193717-1a8b3c75181d-sparring.cpp +928 -0
- package/eval/arena/tank/workspace/history/20261017-193720-1e0803a541e8-baseline.cpp +259 -0
- package/eval/arena/tank/workspace/history/log.jsonl +103 -0
- package/eval/arena/tank/workspace/judge/cycles.hpp +53 -0
- package/eval/arena/tank/workspace/judge/fast.cpp +337 -0
- package/eval/arena/tank/workspace/judge/referee.cpp +125 -0
- package/eval/arena/tank/workspace/judge/speed.cpp +99 -0
- package/eval/arena/tank/workspace/run.cmd +31 -0
- package/eval/arena/tank/workspace/run.sh +23 -0
- package/eval/arena/tank/workspace/tank.hpp +1762 -0
- package/eval/arena/tank/workspace/tank_main.cpp +215 -0
- package/eval/arena/tank/workspace/viewer.html +1150 -0
- package/eval/arena/warehouse/workspace/SPEC.md +130 -0
- package/eval/arena/warehouse/workspace/TASK.md +71 -0
- package/eval/arena/warehouse/workspace/baseline/common.h +88 -0
- package/eval/arena/warehouse/workspace/baseline/main.cpp +27 -0
- package/eval/arena/warehouse/workspace/baseline/old_stuff.cpp +87 -0
- package/eval/arena/warehouse/workspace/baseline/sim.cpp +427 -0
- package/eval/arena/warehouse/workspace/baseline/util.cpp +220 -0
- package/eval/arena/warehouse/workspace/clock.py +42 -0
- package/eval/arena/warehouse/workspace/src/common.h +88 -0
- package/eval/arena/warehouse/workspace/src/main.cpp +27 -0
- package/eval/arena/warehouse/workspace/src/old_stuff.cpp +87 -0
- package/eval/arena/warehouse/workspace/src/sim.cpp +427 -0
- package/eval/arena/warehouse/workspace/src/util.cpp +220 -0
- package/eval/arena/warehouse/workspace/tools/bench.py +119 -0
- package/eval/arena/warehouse/workspace/tools/check_input.py +161 -0
- package/eval/arena/warehouse/workspace/tools/gen.py +132 -0
- package/eval/arena/warehouse/workspace/tools/measure.py +107 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.in +1420 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_crowded.out +9162 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.in +1465 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_dynamic.out +3439 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_flood.in +2757 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_flood.out +3126 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_small.in +731 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_small.out +2578 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_wide.in +528 -0
- package/eval/arena/warehouse/workspace/workloads/public/pub_wide.out +2026 -0
- package/eval/bomberman.py +20 -0
- package/eval/commit0.py +21 -0
- package/eval/common.py +61 -0
- package/eval/ctf.py +20 -0
- package/eval/featurebench.py +25 -0
- package/eval/land.py +20 -0
- package/eval/legacy/bomberman-prices.json +4 -0
- package/eval/legacy/bomberman.py +161 -0
- package/eval/legacy/commit0.py +91 -0
- package/eval/legacy/ctf-prices.json +4 -0
- package/eval/legacy/ctf.py +178 -0
- package/eval/legacy/featurebench.py +103 -0
- package/eval/legacy/land-prices.json +4 -0
- package/eval/legacy/land.py +177 -0
- package/eval/legacy/swe_bench_pro.py +116 -0
- package/eval/legacy/tank-prices.json +3 -0
- package/eval/legacy/tank.py +408 -0
- package/eval/legacy/warehouse-prices.json +4 -0
- package/eval/legacy/warehouse.py +365 -0
- package/eval/swe-bench-pro.py +25 -0
- package/eval/tank.py +20 -0
- package/eval/warehouse.py +20 -0
- package/lib/client/index.js +376 -63
- package/lib/client/index.js.map +1 -1
- package/lib/index.js +684 -27
- package/package.json +2 -1
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// baseline.cpp —— 基准(正式比赛的 0 分线)。
|
|
2
|
+
//
|
|
3
|
+
// 规则型,思路常规,完全确定(不看时间,不用随机数):
|
|
4
|
+
// 分工:火力型主攻,走一条侧路;快速型有星星先抢星,然后走另一条侧路进攻;
|
|
5
|
+
// 装甲型走正面,但有敌车闯到家门口而自己离得不远时回防去打它。刚复活的车也先打家门口的敌车。
|
|
6
|
+
// 每辆车把自己的每条合法命令都用引擎前推一回合(假设对方不动、子弹照飞),
|
|
7
|
+
// 看会不会挨打、会不会误伤,再加上"离目标近了多少""这一炮打得到什么"的规则分,取最高的。
|
|
8
|
+
// 这样自然就会躲已经在飞的子弹;另外单独处理"近处有敌车能开炮正对着我"的情况。
|
|
9
|
+
// 装填:开不了炮时合法命令里没有开炮,自然会去走位;贴脸又开不了炮时会让开炮线。
|
|
10
|
+
// 最多前推一回合,没有搜索。
|
|
11
|
+
#include "tank.hpp"
|
|
12
|
+
|
|
13
|
+
using namespace tank;
|
|
14
|
+
|
|
15
|
+
static const int FAR = 9999;
|
|
16
|
+
#ifndef BL_GUARD
|
|
17
|
+
#define BL_GUARD 0 // 1 = 装甲型专职守家:没有敌车闯进来时站在基地正前方第 3 格,不去进攻
|
|
18
|
+
#endif
|
|
19
|
+
#ifndef BL_ALLSTAR
|
|
20
|
+
#define BL_ALLSTAR 0 // 1 = 三辆车都先吃星(升级值钱的规则下用)
|
|
21
|
+
#endif
|
|
22
|
+
#ifndef BL_NOSTAR
|
|
23
|
+
#define BL_NOSTAR 0 // 1 = 快速型不绕路吃星
|
|
24
|
+
#endif
|
|
25
|
+
#ifndef GUARD_REACH
|
|
26
|
+
#define GUARD_REACH 10 // 装甲型离闯入的敌车不超过这么多格就回防
|
|
27
|
+
#endif
|
|
28
|
+
static int my_seat;
|
|
29
|
+
static int last_pos[3], last_cmd[3], stuck[3]; // 上一回合的位置和命令:同一步连着走不成就降权,免得卡死
|
|
30
|
+
static int lane_of[3]; // 每辆车进攻走哪条炮线(方向位掩码),开局定好
|
|
31
|
+
static int far_shots[3], kills_then[3], bored_until[3]; // 朝敌车连开几炮都没打掉(多半是互相抵消):先不打了,绕路
|
|
32
|
+
|
|
33
|
+
// 带权最短路。dist 里事先填好起点代价(其余 FAR);空地一步 1,砖墙 brick_cost(要先打掉),其他不可走。
|
|
34
|
+
static bool crowded[CELLS]; // 队友占着的格子:寻路时加代价,免得排队堵在一条道上
|
|
35
|
+
static void flood(const State& s, int* dist, int brick_cost) {
|
|
36
|
+
static int queue[CELLS * 8];
|
|
37
|
+
int head = 0, tail = 0;
|
|
38
|
+
for (int c = 0; c < CELLS; ++c)
|
|
39
|
+
if (dist[c] < FAR) queue[tail++] = c;
|
|
40
|
+
while (head < tail) {
|
|
41
|
+
const int c = queue[head++ % (CELLS * 8)];
|
|
42
|
+
for (int d = 0; d < 4; ++d) {
|
|
43
|
+
const int n = c + DIR_DELTA[d];
|
|
44
|
+
const uint8_t g = s.grid[n];
|
|
45
|
+
if (g != EMPTY && g != BRICK) continue;
|
|
46
|
+
const int nd = dist[c] + (g == BRICK ? brick_cost : 1) + (crowded[n] ? 4 : 0);
|
|
47
|
+
if (nd < dist[n]) { dist[n] = nd; queue[tail++ % (CELLS * 8)] = n; }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 进攻图:到"能打到对方基地的格子"的代价。基地只能沿它所在的行和列被打到,所以一共三条炮线:
|
|
53
|
+
// 正面一列、左右两条沿底边的行。lanes 是允许走的炮线(按方向的位掩码),两辆进攻的车各走一边。
|
|
54
|
+
static void attack_map(const State& s, int me, int lanes, int* dist) {
|
|
55
|
+
for (int c = 0; c < CELLS; ++c) dist[c] = FAR;
|
|
56
|
+
for (int d = 0; d < 4; ++d) {
|
|
57
|
+
if (!((lanes >> d) & 1)) continue;
|
|
58
|
+
int bricks = 0, k = 1;
|
|
59
|
+
for (int c = s.base_pos[1 - me] + DIR_DELTA[d];; c += DIR_DELTA[d], ++k) {
|
|
60
|
+
const uint8_t g = s.grid[c];
|
|
61
|
+
const int far = k <= 4 ? 0 : k - 4; // 4 格内算到位;更远的还得往前走
|
|
62
|
+
if (g == BRICK) { // 炮线上的砖:打掉之后站进去也是射击位
|
|
63
|
+
dist[c] = 2 * bricks + 3 + far; // (两侧被钢墙封住时,围墙那一格是唯一的侧面射击位)
|
|
64
|
+
++bricks;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (g == WATER) continue;
|
|
68
|
+
if (g != EMPTY) break;
|
|
69
|
+
dist[c] = 2 * bricks + far; // 中间每块砖要多打一炮
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
flood(s, dist, 3);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 到某些格子的距离图。
|
|
76
|
+
static void target_map(const State& s, const int* cells, int n, int* dist) {
|
|
77
|
+
for (int c = 0; c < CELLS; ++c) dist[c] = FAR;
|
|
78
|
+
for (int k = 0; k < n; ++k) dist[cells[k]] = 0;
|
|
79
|
+
flood(s, dist, 3);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 追击图:到"和敌车 e 在同一条畅通炮线上"的格子的距离。
|
|
83
|
+
static void hunt_map(const State& s, int e, int* dist) {
|
|
84
|
+
for (int c = 0; c < CELLS; ++c) dist[c] = FAR;
|
|
85
|
+
for (int d = 0; d < 4; ++d) {
|
|
86
|
+
int k = 1;
|
|
87
|
+
for (int c = s.tank[e].pos + DIR_DELTA[d]; s.grid[c] == EMPTY || s.grid[c] == WATER; c += DIR_DELTA[d], ++k)
|
|
88
|
+
if (s.grid[c] == EMPTY) dist[c] = k / 2;
|
|
89
|
+
}
|
|
90
|
+
flood(s, dist, 3);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static int manhattan(int a, int b) {
|
|
94
|
+
const int dx = cell_x(a) - cell_x(b), dy = cell_y(a) - cell_y(b);
|
|
95
|
+
return (dx < 0 ? -dx : dx) + (dy < 0 ? -dy : dy);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// a、b 在同一行或同一列,中间没有墙和坦克(水不挡子弹):返回距离,否则 0。
|
|
99
|
+
static int clear_line(const State& s, int a, int b) {
|
|
100
|
+
for (int d = 0; d < 4; ++d) {
|
|
101
|
+
int k = 1;
|
|
102
|
+
for (int c = a + DIR_DELTA[d]; s.grid[c] == EMPTY || s.grid[c] == WATER; c += DIR_DELTA[d], ++k) {
|
|
103
|
+
if (c == b) return k;
|
|
104
|
+
if (tank_at(s, c) >= 0) break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 朝方向 d 开一炮值多少分:看炮线上先碰到什么。
|
|
111
|
+
static int fire_value(const State& s, int me, int i, int d, bool brick_on_path, bool bored, bool* far_tank) {
|
|
112
|
+
int bricks = 0, k = 1;
|
|
113
|
+
for (int c = s.tank[i].pos + DIR_DELTA[d];; c += DIR_DELTA[d], ++k) {
|
|
114
|
+
const uint8_t g = s.grid[c];
|
|
115
|
+
if (g == WATER) continue;
|
|
116
|
+
if (g == BRICK) { ++bricks; continue; }
|
|
117
|
+
if (g == BASE0 + (1 - me)) { // 对方基地(隔着砖也值得打):比打车优先,车三回合就复活,基地血不会回
|
|
118
|
+
if (k <= 4) return 700 - 40 * bricks;
|
|
119
|
+
break; // 太远不打:子弹飞到之前不能再开炮,还容易被挡
|
|
120
|
+
}
|
|
121
|
+
if (g == BASE0 + me) return bricks ? -500 : -1000; // 自己的基地
|
|
122
|
+
if (g != EMPTY) break; // 钢墙、界外
|
|
123
|
+
if (bricks) continue; // 砖后面的车和子弹先不管
|
|
124
|
+
for (int b = 0; b < s.n_bullets; ++b) // 正对着飞来的敌方子弹:开炮能把它抵消掉
|
|
125
|
+
if (s.bullet[b].pos == c && s.bullet[b].dir == (d ^ 1) && seat_of(s.bullet[b].owner) != me && k <= 6) return 150;
|
|
126
|
+
const int v = tank_at(s, c);
|
|
127
|
+
if (v < 0) continue;
|
|
128
|
+
if (seat_of(v) == me) return -1000; // 队友
|
|
129
|
+
*far_tank = true; // 这一炮是朝敌车打的(记数用)
|
|
130
|
+
if (k <= 2 && !can_fire(s, v)) return 600; // 2 格内而且它正在装填:抵消不了,最值得打
|
|
131
|
+
if (bored) return -5; // 对着打了几炮都被抵消:先不打,绕开
|
|
132
|
+
if (k <= 2) return 500; // 2 格内:当回合就到
|
|
133
|
+
return k <= 4 ? 200 : -5; // 远一些:对方来得及躲或者开炮抵消,再远就不浪费时间了
|
|
134
|
+
}
|
|
135
|
+
return (bricks && brick_on_path) ? 120 : -5; // 挡路的砖 / 空炮
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
void init(const State& s, int me) {
|
|
139
|
+
my_seat = me;
|
|
140
|
+
// 火力型走离自己出生点近的那一侧,快速型走另一侧;正面那一列对着对方的出生点,容易被堵,不走。
|
|
141
|
+
const int fire_side = cell_x(s.spawn[tank_id(me, FIRE)]) <= cell_x(s.base_pos[me]) ? LEFT : RIGHT;
|
|
142
|
+
lane_of[FIRE] = 1 << fire_side;
|
|
143
|
+
lane_of[FAST] = 1 << (fire_side ^ 1);
|
|
144
|
+
lane_of[ARMOR] = 1 << (me == 0 ? DOWN : UP); // 装甲型走正面(从对方基地看过来的那一列)
|
|
145
|
+
for (int k = 0; k < 3; ++k) { last_pos[k] = -1; last_cmd[k] = STAY; stuck[k] = 0; far_shots[k] = 0; kills_then[k] = 0; bored_until[k] = 0; }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
Orders decide(const State& s, int me) {
|
|
149
|
+
static int goal[CELLS];
|
|
150
|
+
Orders mine, theirs;
|
|
151
|
+
const int home = s.base_pos[me];
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
for (int type = 0; type < 3; ++type) {
|
|
155
|
+
const int i = tank_id(me, type);
|
|
156
|
+
const Tank& t = s.tank[i];
|
|
157
|
+
if (!t.alive) { last_pos[type] = -1; stuck[type] = 0; continue; }
|
|
158
|
+
|
|
159
|
+
// 上一回合下了移动命令却没动:记一次,同一条命令这回合降权。
|
|
160
|
+
if (last_pos[type] == t.pos && last_cmd[type] != STAY && !is_fire(Cmd(last_cmd[type]))) stuck[type] += 1;
|
|
161
|
+
else stuck[type] = 0;
|
|
162
|
+
|
|
163
|
+
// ---- 这辆车的目标:填好 goal[] ----
|
|
164
|
+
for (int c = 0; c < CELLS; ++c) crowded[c] = false;
|
|
165
|
+
for (int j = 3 * me; j < 3 * me + 3; ++j)
|
|
166
|
+
if (j != i && s.tank[j].alive) crowded[s.tank[j].pos] = true;
|
|
167
|
+
// 闯到我方基地附近(7 格内)的敌车:装甲型离它不太远就回防去追;另外两辆只有自己还在家门口(比如刚复活)
|
|
168
|
+
// 时才先去打它,出了门就不回头,免得在半路来回摇摆。
|
|
169
|
+
int intruder = -1, intruder_dist = FAR;
|
|
170
|
+
for (int e = 3 * (1 - me); e < 3 * (1 - me) + 3; ++e) {
|
|
171
|
+
if (!s.tank[e].alive || manhattan(s.tank[e].pos, home) > 7) continue;
|
|
172
|
+
const int gap = manhattan(s.tank[e].pos, t.pos);
|
|
173
|
+
if ((type == ARMOR ? (BL_GUARD || gap <= GUARD_REACH) : manhattan(t.pos, home) <= 5) && gap < intruder_dist) { intruder = e; intruder_dist = gap; }
|
|
174
|
+
}
|
|
175
|
+
if (intruder >= 0) {
|
|
176
|
+
hunt_map(s, intruder, goal); // 去和它对上炮线
|
|
177
|
+
} else if (BL_GUARD && type == ARMOR) {
|
|
178
|
+
int post = home + 3 * DIR_DELTA[me == 0 ? UP : DOWN];
|
|
179
|
+
if (s.grid[post] != EMPTY) post = s.spawn[i];
|
|
180
|
+
target_map(s, &post, 1, goal);
|
|
181
|
+
} else {
|
|
182
|
+
attack_map(s, me, lane_of[type], goal);
|
|
183
|
+
if (goal[t.pos] >= FAR) attack_map(s, me, 15, goal); // 这条炮线被钢墙封死了:哪条都行
|
|
184
|
+
// 快速型:有星星、自己没满级、而且还没打到对方家门口(进攻图上还差 4 步以上)时,先去吃星。
|
|
185
|
+
if (!BL_NOSTAR && (type == FAST || BL_ALLSTAR) && s.star_mask && t.level < s.P.max_level && goal[t.pos] > 3) {
|
|
186
|
+
int stars[MAX_SUPPLY], n = 0;
|
|
187
|
+
for (int k = 0; k < s.n_supply; ++k)
|
|
188
|
+
if ((s.star_mask >> k) & 1) stars[n++] = s.supply[k];
|
|
189
|
+
target_map(s, stars, n, goal);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
int best_step = -1; // 朝目标最近的邻格方向(判断"挡路的砖"用)
|
|
193
|
+
for (int d = 0, best = goal[t.pos]; d < 4; ++d)
|
|
194
|
+
if (goal[t.pos + DIR_DELTA[d]] < best) { best = goal[t.pos + DIR_DELTA[d]]; best_step = d; }
|
|
195
|
+
|
|
196
|
+
// ---- 逐条命令打分 ----
|
|
197
|
+
Cmd list[N_CMDS];
|
|
198
|
+
const int n = legal_commands(s, i, list);
|
|
199
|
+
int best_score = -1000000;
|
|
200
|
+
Cmd best_cmd = STAY;
|
|
201
|
+
bool best_far = false;
|
|
202
|
+
for (int k = 0; k < n; ++k) {
|
|
203
|
+
const Cmd c = list[k];
|
|
204
|
+
Orders trial = mine; // 前面的车已经定下的命令也带上
|
|
205
|
+
trial.cmd[type] = c;
|
|
206
|
+
State next = s;
|
|
207
|
+
step_as(next, me, trial, theirs); // 前推一回合:对方不动,子弹照飞
|
|
208
|
+
|
|
209
|
+
int score = 0;
|
|
210
|
+
// 挨打、误伤、打中:直接看前推结果。
|
|
211
|
+
for (int j = 3 * me; j < 3 * me + 3; ++j)
|
|
212
|
+
if (s.tank[j].alive) score -= 1000 * (s.tank[j].hp - (next.tank[j].alive ? next.tank[j].hp : 0));
|
|
213
|
+
for (int e = 3 * (1 - me); e < 3 * (1 - me) + 3; ++e)
|
|
214
|
+
if (s.tank[e].alive) score += 400 * (s.tank[e].hp - (next.tank[e].alive ? next.tank[e].hp : 0));
|
|
215
|
+
score -= 1000 * (s.base_hp[me] - next.base_hp[me]);
|
|
216
|
+
score += 300 * (s.base_hp[1 - me] - next.base_hp[1 - me]);
|
|
217
|
+
|
|
218
|
+
const int pos = next.tank[i].alive ? next.tank[i].pos : t.pos;
|
|
219
|
+
// 近处(2 格内,子弹当回合就到)有能开炮的敌车正对着我:除非我朝它开炮(两发会抵消),否则危险。
|
|
220
|
+
for (int e = 3 * (1 - me); e < 3 * (1 - me) + 3; ++e) {
|
|
221
|
+
if (!s.tank[e].alive || !can_fire(s, e)) continue;
|
|
222
|
+
const int gap = clear_line(s, s.tank[e].pos, pos);
|
|
223
|
+
if (gap == 0 || gap > 2) continue;
|
|
224
|
+
bool answering = false;
|
|
225
|
+
if (is_fire(c)) {
|
|
226
|
+
int probe = t.pos;
|
|
227
|
+
for (int step_k = 0; step_k < gap; ++step_k) probe += DIR_DELTA[c - 5];
|
|
228
|
+
answering = probe == s.tank[e].pos;
|
|
229
|
+
}
|
|
230
|
+
if (!answering) score -= 250;
|
|
231
|
+
}
|
|
232
|
+
// 前推之后还有子弹正对着我飞来(下一回合到):尽量别待在这条线上。
|
|
233
|
+
for (int b = 0; b < next.n_bullets; ++b) {
|
|
234
|
+
int probe = next.bullet[b].pos;
|
|
235
|
+
for (int step_k = 0; step_k < 4; ++step_k) {
|
|
236
|
+
probe += DIR_DELTA[next.bullet[b].dir];
|
|
237
|
+
if (next.grid[probe] != EMPTY && next.grid[probe] != WATER) break;
|
|
238
|
+
if (probe == pos) { score -= 40; break; }
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// 规则分:开炮看打得到什么,移动看离目标近了多少。
|
|
242
|
+
bool far_tank = false;
|
|
243
|
+
if (is_fire(c))
|
|
244
|
+
score += fire_value(s, me, i, c - 5, best_step == c - 5 && s.grid[t.pos + DIR_DELTA[c - 5]] == BRICK,
|
|
245
|
+
s.turn < bored_until[type], &far_tank);
|
|
246
|
+
score -= 10 * (goal[pos] < FAR ? goal[pos] : 200);
|
|
247
|
+
if (c == STAY) score -= 1;
|
|
248
|
+
if (c == last_cmd[type]) score -= 30 * stuck[type];
|
|
249
|
+
if (score > best_score) { best_score = score; best_cmd = c; best_far = far_tank; }
|
|
250
|
+
}
|
|
251
|
+
// 朝敌车连开 3 炮没有战果(多半是面对面互相抵消):歇 8 回合,期间只打正在装填的敌车。
|
|
252
|
+
if (s.kills[me] != kills_then[type]) { kills_then[type] = s.kills[me]; far_shots[type] = 0; }
|
|
253
|
+
if (best_far && ++far_shots[type] >= 3) { far_shots[type] = 0; bored_until[type] = s.turn + 8; }
|
|
254
|
+
mine.cmd[type] = best_cmd;
|
|
255
|
+
last_pos[type] = t.pos;
|
|
256
|
+
last_cmd[type] = best_cmd;
|
|
257
|
+
}
|
|
258
|
+
return mine;
|
|
259
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""查看比赛用时。只读,不写任何文件。
|
|
2
|
+
|
|
3
|
+
上半场从解压出本文件的那一刻算起;中场包解压后(出现 halftime/START)显示下半场,
|
|
4
|
+
从解压出那个文件的那一刻算起。两个半场都是 30 分钟,最早交卷时间是第 20 分钟,45 分钟强制收卷。
|
|
5
|
+
"""
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
EARLIEST, TARGET, LIMIT = 20, 30, 45 # 分钟:最早交卷时间、本半场的时间、强制收卷
|
|
11
|
+
HERE = Path(__file__).resolve().parent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def born(path):
|
|
15
|
+
"""文件在本机被创建(也就是解压出来)的时刻。不能用修改时间:解压会把它恢复成打包时的值。"""
|
|
16
|
+
st = Path(path).stat()
|
|
17
|
+
return getattr(st, "st_birthtime", None) or st.st_ctime # Windows 为创建时间;Linux 上新建文件的 ctime 即解压时刻
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
SKIP_DIRS = {"build", "history", "replays", "submission", "judge", "opponents", "__pycache__", ".git", "node_modules"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _someone_elses(d, here):
|
|
24
|
+
"""这个目录是不是另一份比赛文件(里面有它自己的 clock.py 或 workspace.zip):是的话不进去找。"""
|
|
25
|
+
try:
|
|
26
|
+
if (d / "workspace.zip").is_file():
|
|
27
|
+
return True
|
|
28
|
+
return (d / "clock.py").is_file() and d.resolve() != here.resolve()
|
|
29
|
+
except OSError:
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _search(root, here, depth):
|
|
34
|
+
"""在 root 往下最多 depth 层目录里找 halftime/START。"""
|
|
35
|
+
found, level = [], [root]
|
|
36
|
+
for _ in range(depth + 1):
|
|
37
|
+
deeper = []
|
|
38
|
+
for d in level:
|
|
39
|
+
marker = d / "halftime" / "START"
|
|
40
|
+
if marker.is_file():
|
|
41
|
+
found.append(marker)
|
|
42
|
+
try:
|
|
43
|
+
subs = [x for x in d.iterdir() if x.is_dir() and x.name not in SKIP_DIRS]
|
|
44
|
+
except OSError:
|
|
45
|
+
continue
|
|
46
|
+
deeper += [x for x in subs if not _someone_elses(x, here)]
|
|
47
|
+
level = deeper
|
|
48
|
+
return found
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def find_marker(here=HERE):
|
|
52
|
+
"""找中场包的开赛标记。标准位置是 halftime/START。
|
|
53
|
+
|
|
54
|
+
解压时多套或少套了一层目录,或者解压到了旁边一个以压缩包命名的文件夹里(有的解压命令默认这样做),也能找到:
|
|
55
|
+
在本目录和上一层目录里往下找几层(本目录自己被多套了一层时,再往上一层)。找到几个时取最早解压出来的那个。"""
|
|
56
|
+
here = Path(here)
|
|
57
|
+
for rel in ("halftime/START", "halftime/halftime/START", "workspace/halftime/START",
|
|
58
|
+
"halftime/workspace/halftime/START", "../halftime/START"):
|
|
59
|
+
p = here / rel
|
|
60
|
+
if p.is_file():
|
|
61
|
+
return p
|
|
62
|
+
roots = [here, here.parent]
|
|
63
|
+
if here.parent.name.lower() == here.name.lower():
|
|
64
|
+
roots.append(here.parent.parent)
|
|
65
|
+
found = []
|
|
66
|
+
for root in roots:
|
|
67
|
+
try:
|
|
68
|
+
found += _search(root, here, 3)
|
|
69
|
+
except OSError:
|
|
70
|
+
pass
|
|
71
|
+
return min(found, key=born) if found else None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def message(half, used):
|
|
75
|
+
if used < EARLIEST:
|
|
76
|
+
return (f"{half} 已用 {used:.1f} 分钟。最早交卷时间是第 {EARLIEST} 分钟(还有 {EARLIEST - used:.1f} 分钟),"
|
|
77
|
+
f"{TARGET} 分钟是本半场的时间,{LIMIT} 分钟强制收卷。")
|
|
78
|
+
if used < TARGET:
|
|
79
|
+
return (f"{half} 已用 {used:.1f} 分钟。已过最早交卷时间(第 {EARLIEST} 分钟),"
|
|
80
|
+
f"距 {TARGET} 分钟还有 {TARGET - used:.1f} 分钟,{LIMIT} 分钟强制收卷。")
|
|
81
|
+
if used < LIMIT:
|
|
82
|
+
return (f"{half} 已用 {used:.1f} 分钟,已过 {TARGET} 分钟,请尽快收尾。"
|
|
83
|
+
f"{LIMIT} 分钟强制收卷,还剩 {LIMIT - used:.1f} 分钟。")
|
|
84
|
+
return f"{half} 已用 {used:.1f} 分钟,已到 {LIMIT} 分钟,强制收卷:请立即停止修改并提交。"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def status(here=HERE, clock_file=None, now=None):
|
|
88
|
+
now = time.time() if now is None else now
|
|
89
|
+
marker = find_marker(here)
|
|
90
|
+
half, start = ("下半场", born(marker)) if marker else ("上半场", born(clock_file or Path(__file__).resolve()))
|
|
91
|
+
text = message(half, max(0.0, now - start) / 60)
|
|
92
|
+
if marker and marker.resolve() != (here / "halftime" / "START").resolve():
|
|
93
|
+
text += (f"\n提示:中场包解压到了 {marker.parent},标准位置是 {here / 'halftime'}。计时不受影响;"
|
|
94
|
+
"可以把整个 halftime 文件夹移到标准位置(移动不会改变计时)。")
|
|
95
|
+
return text
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
try:
|
|
100
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
101
|
+
except (AttributeError, ValueError):
|
|
102
|
+
pass
|
|
103
|
+
print(status())
|