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,367 @@
|
|
|
1
|
+
// bot.cpp —— 坦克大战 bot
|
|
2
|
+
//
|
|
3
|
+
// 结构:
|
|
4
|
+
// 1) 评估函数:基地血量差为主,加上坦克血量/等级、击毁、吃星、以及两个势场——
|
|
5
|
+
// "我方最快那辆车还要几个动作才能打到对方基地"(进攻)和"敌方最靠近我基地的那辆车
|
|
6
|
+
// 还要几个动作"(防守),再加追击项(逼近威胁我基地的敌车)和暴露度。
|
|
7
|
+
// 2) 搜索:用真实引擎 step 前推。先做几轮 best-response 迭代得到基准计划,
|
|
8
|
+
// 再枚举我方每辆车的前 K 条命令组成候选,对每个候选算对手的最佳应对,
|
|
9
|
+
// 取"最坏情况最好"的那个(一层 minimax)。
|
|
10
|
+
#include "tank.hpp"
|
|
11
|
+
|
|
12
|
+
#include <algorithm>
|
|
13
|
+
#include <cmath>
|
|
14
|
+
#include <cstring>
|
|
15
|
+
|
|
16
|
+
using namespace tank;
|
|
17
|
+
|
|
18
|
+
static const int INF = 1 << 20;
|
|
19
|
+
|
|
20
|
+
// ==================== 权重 ====================
|
|
21
|
+
static double W_BASE = 250.0; // 每点基地血量差
|
|
22
|
+
static double W_DMG = 90; // 预期未来伤害(基地血量单位)
|
|
23
|
+
static double W_HP = 120.0; // 每点坦克血量
|
|
24
|
+
static double W_LVL = 100.0; // 每级
|
|
25
|
+
static double W_DEAD = 200.0; // 一辆车不在场的固定惩罚
|
|
26
|
+
static double W_RESPAWN = 35.0; // 每多等一回合
|
|
27
|
+
static double W_KILL = 120.0; // 每次击毁
|
|
28
|
+
static double W_STAR = 180.0; // 每颗吃到的星
|
|
29
|
+
static double W_POT = 14.0; // 每"半回合"的势能(进攻主车 / 防守)
|
|
30
|
+
static double W_POT2 = 5.0; // 其余车的进攻势能
|
|
31
|
+
static double W_CHASE = 60; // 追击威胁我基地的敌车
|
|
32
|
+
static double W_EXP = 10; // 每辆敌人有清晰炮线指着我
|
|
33
|
+
static double W_STARP = 6.0; // 靠近星星
|
|
34
|
+
|
|
35
|
+
// ==================== 全局 ====================
|
|
36
|
+
static int g_me = 0;
|
|
37
|
+
static int g_opp = 1;
|
|
38
|
+
|
|
39
|
+
// g_potTo[b][c]:一辆坦克在格子 c,要开始对基地 b 造成伤害还需要多少"半回合"
|
|
40
|
+
static int g_potTo[2][CELLS];
|
|
41
|
+
static uint64_t g_potHash = 0;
|
|
42
|
+
static bool g_potValid = false;
|
|
43
|
+
|
|
44
|
+
// 到最近一颗星星的走位代价
|
|
45
|
+
static int g_starDist[CELLS];
|
|
46
|
+
static uint64_t g_starHash = 0;
|
|
47
|
+
static uint8_t g_starMask = 0;
|
|
48
|
+
static bool g_starValid = false;
|
|
49
|
+
|
|
50
|
+
static bool passable(uint8_t g) { return g == EMPTY || g == BRICK; }
|
|
51
|
+
|
|
52
|
+
// 从 cell 沿直线看 base:返回中间砖墙数;有钢墙/别的挡路(非基地)则不可用。
|
|
53
|
+
static int lineBricksTo(const State& s, int cell, int base) {
|
|
54
|
+
const int x0 = cell_x(cell), y0 = cell_y(cell);
|
|
55
|
+
const int x1 = cell_x(base), y1 = cell_y(base);
|
|
56
|
+
if (x0 != x1 && y0 != y1) return INF;
|
|
57
|
+
if (x0 == x1 && y0 == y1) return INF;
|
|
58
|
+
int step;
|
|
59
|
+
if (y0 == y1) step = (x1 > x0) ? 1 : -1;
|
|
60
|
+
else step = (y1 > y0) ? STRIDE : -STRIDE;
|
|
61
|
+
int bricks = 0;
|
|
62
|
+
for (int c = cell + step; c != base; c += step) {
|
|
63
|
+
const uint8_t g = s.grid[c];
|
|
64
|
+
if (g == BRICK) ++bricks;
|
|
65
|
+
else if (g == STEEL) return INF;
|
|
66
|
+
else if (g != EMPTY && g != WATER) return INF;
|
|
67
|
+
}
|
|
68
|
+
return bricks;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static void computePot(const State& s, int base, int* out) {
|
|
72
|
+
for (int c = 0; c < CELLS; ++c) out[c] = INF;
|
|
73
|
+
static int head[1024];
|
|
74
|
+
static int nxt[CELLS];
|
|
75
|
+
for (int i = 0; i < 1024; ++i) head[i] = -1;
|
|
76
|
+
int maxc = 0;
|
|
77
|
+
auto push = [&](int c, int cost) {
|
|
78
|
+
if (cost < 0 || cost >= 1024) return;
|
|
79
|
+
nxt[c] = head[cost];
|
|
80
|
+
head[cost] = c;
|
|
81
|
+
if (cost > maxc) maxc = cost;
|
|
82
|
+
};
|
|
83
|
+
const int xb = cell_x(base), yb = cell_y(base);
|
|
84
|
+
for (int c = 0; c < CELLS; ++c) {
|
|
85
|
+
const int x = cell_x(c), y = cell_y(c);
|
|
86
|
+
if (x < 0 || y < 0 || x >= s.P.size || y >= s.P.size) continue;
|
|
87
|
+
if (x != xb && y != yb) continue;
|
|
88
|
+
if (c == base) continue;
|
|
89
|
+
const uint8_t g = s.grid[c];
|
|
90
|
+
if (!passable(g)) continue;
|
|
91
|
+
const int lb = lineBricksTo(s, c, base);
|
|
92
|
+
if (lb >= INF) continue;
|
|
93
|
+
const int L = std::abs(x - xb) + std::abs(y - yb);
|
|
94
|
+
// 单位是"半回合":子弹每回合飞 2 格,第一发要 L/2 回合;每多一堵砖墙多打一发。
|
|
95
|
+
int cost = (lb + 1) * L;
|
|
96
|
+
if (g == BRICK) cost += 4;
|
|
97
|
+
if (cost < out[c]) { out[c] = cost; push(c, cost); }
|
|
98
|
+
}
|
|
99
|
+
for (int d = 0; d <= maxc; ++d) {
|
|
100
|
+
for (int c = head[d]; c != -1; c = nxt[c]) {
|
|
101
|
+
if (out[c] != d) continue;
|
|
102
|
+
const int ec = (s.grid[c] == BRICK) ? 4 : 2;
|
|
103
|
+
for (int k = 0; k < 4; ++k) {
|
|
104
|
+
const int n = c + DIR_DELTA[k];
|
|
105
|
+
if (!passable(s.grid[n])) continue;
|
|
106
|
+
if (out[c] + ec < out[n]) { out[n] = out[c] + ec; push(n, out[n]); }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static void ensurePot(const State& s) {
|
|
113
|
+
if (g_potValid && g_potHash == s.wall_hash) return;
|
|
114
|
+
computePot(s, s.base_pos[0], g_potTo[0]);
|
|
115
|
+
computePot(s, s.base_pos[1], g_potTo[1]);
|
|
116
|
+
g_potHash = s.wall_hash;
|
|
117
|
+
g_potValid = true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static void ensureStar(const State& s) {
|
|
121
|
+
if (g_starValid && g_starHash == s.wall_hash && g_starMask == s.star_mask) return;
|
|
122
|
+
g_starMask = s.star_mask;
|
|
123
|
+
for (int c = 0; c < CELLS; ++c) g_starDist[c] = INF;
|
|
124
|
+
if (s.star_mask) {
|
|
125
|
+
static int head[1024];
|
|
126
|
+
static int nxt[CELLS];
|
|
127
|
+
for (int i = 0; i < 1024; ++i) head[i] = -1;
|
|
128
|
+
int maxc = 0;
|
|
129
|
+
auto push = [&](int c, int cost) {
|
|
130
|
+
if (cost < 0 || cost >= 1024) return;
|
|
131
|
+
nxt[c] = head[cost];
|
|
132
|
+
head[cost] = c;
|
|
133
|
+
if (cost > maxc) maxc = cost;
|
|
134
|
+
};
|
|
135
|
+
for (int k = 0; k < s.n_supply; ++k) {
|
|
136
|
+
if (!((s.star_mask >> k) & 1)) continue;
|
|
137
|
+
const int c = s.supply[k];
|
|
138
|
+
if (g_starDist[c] > 0) { g_starDist[c] = 0; push(c, 0); }
|
|
139
|
+
}
|
|
140
|
+
for (int d = 0; d <= maxc; ++d) {
|
|
141
|
+
for (int c = head[d]; c != -1; c = nxt[c]) {
|
|
142
|
+
if (g_starDist[c] != d) continue;
|
|
143
|
+
const int ec = (s.grid[c] == BRICK) ? 4 : 2;
|
|
144
|
+
for (int k = 0; k < 4; ++k) {
|
|
145
|
+
const int n = c + DIR_DELTA[k];
|
|
146
|
+
if (!passable(s.grid[n])) continue;
|
|
147
|
+
if (g_starDist[c] + ec < g_starDist[n]) { g_starDist[n] = g_starDist[c] + ec; push(n, g_starDist[n]); }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
g_starHash = s.wall_hash;
|
|
153
|
+
g_starValid = true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static bool clearShot(const State& s, int from, int to) {
|
|
157
|
+
if (from == to) return false;
|
|
158
|
+
const int x0 = cell_x(from), y0 = cell_y(from);
|
|
159
|
+
const int x1 = cell_x(to), y1 = cell_y(to);
|
|
160
|
+
if (x0 != x1 && y0 != y1) return false;
|
|
161
|
+
int step;
|
|
162
|
+
if (y0 == y1) step = (x1 > x0) ? 1 : -1;
|
|
163
|
+
else step = (y1 > y0) ? STRIDE : -STRIDE;
|
|
164
|
+
for (int c = from + step; c != to; c += step) {
|
|
165
|
+
const uint8_t g = s.grid[c];
|
|
166
|
+
if (g == BRICK || g == STEEL || g == BASE0 || g == BASE1 || g == OUTSIDE) return false;
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ==================== 评估 ====================
|
|
172
|
+
static double evalState(const State& s, int seat) {
|
|
173
|
+
if (s.done) return s.winner == seat ? 1e9 : (s.winner < 0 ? 0.0 : -1e9);
|
|
174
|
+
const int opp = 1 - seat;
|
|
175
|
+
ensurePot(s);
|
|
176
|
+
double v = 0.0;
|
|
177
|
+
v += W_BASE * double(s.base_hp[seat] - s.base_hp[opp]);
|
|
178
|
+
for (int i = 0; i < 6; ++i) {
|
|
179
|
+
double m;
|
|
180
|
+
if (s.tank[i].alive) m = W_HP * s.tank[i].hp + W_LVL * s.tank[i].level;
|
|
181
|
+
else m = -(W_DEAD + W_RESPAWN * respawn_in(s, i));
|
|
182
|
+
v += (seat_of(i) == seat) ? m : -m;
|
|
183
|
+
}
|
|
184
|
+
v += W_KILL * double(s.kills[seat] - s.kills[opp]);
|
|
185
|
+
v += W_STAR * double(s.stars_eaten[seat] - s.stars_eaten[opp]);
|
|
186
|
+
|
|
187
|
+
const int* potToEnemy = g_potTo[opp]; // 我方坦克用
|
|
188
|
+
const int* potToMine = g_potTo[seat]; // 敌方坦克用
|
|
189
|
+
|
|
190
|
+
// 预期还能对基地打出多少伤害:越早到位、射速越高越好。
|
|
191
|
+
// 0 级的快速型/装甲型开炮后要装填,射速只有火力型的一半——所以火力型才是主攻手。
|
|
192
|
+
const double T = double(std::max(0, s.P.max_turns - s.turn));
|
|
193
|
+
double offMe = 0.0, offOpp = 0.0;
|
|
194
|
+
{
|
|
195
|
+
double b1 = 0.0, b2 = 0.0;
|
|
196
|
+
for (int i = 0; i < 6; ++i) {
|
|
197
|
+
if (seat_of(i) != seat || !s.tank[i].alive) continue;
|
|
198
|
+
const double setup = std::min(potToEnemy[s.tank[i].pos], 160) / 2.0;
|
|
199
|
+
const double rate = 1.0 / (1.0 + double(reload_turns(s, i)));
|
|
200
|
+
const double val = std::max(0.0, T - setup) * rate;
|
|
201
|
+
if (val > b1) { b2 = b1; b1 = val; }
|
|
202
|
+
else if (val > b2) b2 = val;
|
|
203
|
+
}
|
|
204
|
+
offMe = b1 + 0.25 * b2;
|
|
205
|
+
}
|
|
206
|
+
{
|
|
207
|
+
double b1 = 0.0, b2 = 0.0;
|
|
208
|
+
for (int i = 0; i < 6; ++i) {
|
|
209
|
+
if (seat_of(i) == seat || !s.tank[i].alive) continue;
|
|
210
|
+
const double setup = std::min(potToMine[s.tank[i].pos], 160) / 2.0;
|
|
211
|
+
const double rate = 1.0 / (1.0 + double(reload_turns(s, i)));
|
|
212
|
+
const double val = std::max(0.0, T - setup) * rate;
|
|
213
|
+
if (val > b1) { b2 = b1; b1 = val; }
|
|
214
|
+
else if (val > b2) b2 = val;
|
|
215
|
+
}
|
|
216
|
+
offOpp = b1 + 0.25 * b2;
|
|
217
|
+
}
|
|
218
|
+
v += W_DMG * (offMe - offOpp);
|
|
219
|
+
|
|
220
|
+
// 追击:逼近那些威胁我基地的敌车
|
|
221
|
+
for (int j = 0; j < 6; ++j) {
|
|
222
|
+
if (seat_of(j) == seat || !s.tank[j].alive) continue;
|
|
223
|
+
const int pj = potToMine[s.tank[j].pos];
|
|
224
|
+
if (pj >= 40) continue;
|
|
225
|
+
int dmin = 99;
|
|
226
|
+
for (int i = 0; i < 6; ++i) {
|
|
227
|
+
if (seat_of(i) != seat || !s.tank[i].alive) continue;
|
|
228
|
+
const int d = std::abs(cell_x(s.tank[i].pos) - cell_x(s.tank[j].pos)) +
|
|
229
|
+
std::abs(cell_y(s.tank[i].pos) - cell_y(s.tank[j].pos));
|
|
230
|
+
dmin = std::min(dmin, d);
|
|
231
|
+
}
|
|
232
|
+
v -= W_CHASE * double(40 - pj) / 40.0 * double(std::min(dmin, 15));
|
|
233
|
+
}
|
|
234
|
+
// 暴露度
|
|
235
|
+
for (int i = 0; i < 6; ++i) {
|
|
236
|
+
if (seat_of(i) != seat || !s.tank[i].alive) continue;
|
|
237
|
+
int cnt = 0;
|
|
238
|
+
for (int j = 0; j < 6; ++j) {
|
|
239
|
+
if (seat_of(j) == seat || !s.tank[j].alive) continue;
|
|
240
|
+
if (clearShot(s, s.tank[j].pos, s.tank[i].pos)) ++cnt;
|
|
241
|
+
}
|
|
242
|
+
v -= W_EXP * double(cnt);
|
|
243
|
+
}
|
|
244
|
+
// 星星
|
|
245
|
+
if (s.star_mask) {
|
|
246
|
+
ensureStar(s);
|
|
247
|
+
for (int i = 0; i < 6; ++i) {
|
|
248
|
+
if (!s.tank[i].alive) continue;
|
|
249
|
+
const int d = std::min(g_starDist[s.tank[i].pos], 40);
|
|
250
|
+
if (seat_of(i) == seat) v -= W_STARP * double(d);
|
|
251
|
+
else v += W_STARP * double(d);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return v;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ==================== 搜索 ====================
|
|
258
|
+
static double planEval(const State& root, int seat, const Orders& mine, const Orders& theirs) {
|
|
259
|
+
State t = root;
|
|
260
|
+
step_as(t, seat, mine, theirs);
|
|
261
|
+
return evalState(t, seat);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
static Orders bestResponse(const State& root, int seat, const Orders& other, int rounds, Orders cur = Orders{}) {
|
|
265
|
+
for (int r = 0; r < rounds; ++r) {
|
|
266
|
+
bool changed = false;
|
|
267
|
+
for (int ty = 0; ty < 3; ++ty) {
|
|
268
|
+
const int i = tank_id(seat, ty);
|
|
269
|
+
if (!root.tank[i].alive) { cur.cmd[ty] = STAY; continue; }
|
|
270
|
+
Cmd list[N_CMDS];
|
|
271
|
+
const int n = legal_commands(root, i, list);
|
|
272
|
+
const Cmd keep = cur.cmd[ty];
|
|
273
|
+
double bestv = -1e18;
|
|
274
|
+
Cmd bestc = keep;
|
|
275
|
+
for (int k = 0; k < n; ++k) {
|
|
276
|
+
cur.cmd[ty] = list[k];
|
|
277
|
+
const double v = planEval(root, seat, cur, other);
|
|
278
|
+
if (v > bestv) { bestv = v; bestc = list[k]; }
|
|
279
|
+
}
|
|
280
|
+
cur.cmd[ty] = bestc;
|
|
281
|
+
if (bestc != keep) changed = true;
|
|
282
|
+
}
|
|
283
|
+
if (!changed) break;
|
|
284
|
+
}
|
|
285
|
+
return cur;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 每辆车按"其它车不动"的评估排序,取前 K 条
|
|
289
|
+
static void topCommands(const State& root, int seat, const Orders& other, Cmd out[3][8], int K, int cnt[3]) {
|
|
290
|
+
for (int ty = 0; ty < 3; ++ty) {
|
|
291
|
+
const int i = tank_id(seat, ty);
|
|
292
|
+
cnt[ty] = 1;
|
|
293
|
+
if (!root.tank[i].alive) { out[ty][0] = STAY; continue; }
|
|
294
|
+
Cmd list[N_CMDS];
|
|
295
|
+
const int n = legal_commands(root, i, list);
|
|
296
|
+
double sc[N_CMDS];
|
|
297
|
+
Orders probe;
|
|
298
|
+
for (int k = 0; k < n; ++k) {
|
|
299
|
+
probe.cmd[ty] = list[k];
|
|
300
|
+
sc[k] = planEval(root, seat, probe, other);
|
|
301
|
+
}
|
|
302
|
+
int idx[N_CMDS];
|
|
303
|
+
for (int k = 0; k < n; ++k) idx[k] = k;
|
|
304
|
+
const int kk = std::min(n, K);
|
|
305
|
+
for (int a = 0; a < kk; ++a) {
|
|
306
|
+
int best = a;
|
|
307
|
+
for (int b = a + 1; b < n; ++b)
|
|
308
|
+
if (sc[idx[b]] > sc[idx[best]]) best = b;
|
|
309
|
+
std::swap(idx[a], idx[best]);
|
|
310
|
+
out[ty][a] = list[idx[a]];
|
|
311
|
+
}
|
|
312
|
+
cnt[ty] = kk;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
void init(const State& s, int me) {
|
|
317
|
+
g_me = me;
|
|
318
|
+
g_opp = 1 - me;
|
|
319
|
+
g_potValid = false;
|
|
320
|
+
g_starValid = false;
|
|
321
|
+
(void)s;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
Orders decide(const State& s, int me) {
|
|
325
|
+
g_me = me;
|
|
326
|
+
g_opp = 1 - me;
|
|
327
|
+
g_potValid = false;
|
|
328
|
+
g_starValid = false;
|
|
329
|
+
ensurePot(s);
|
|
330
|
+
|
|
331
|
+
const Orders stay;
|
|
332
|
+
// 1) 基准:几轮 best-response 迭代
|
|
333
|
+
Orders opp = bestResponse(s, g_opp, stay, 2);
|
|
334
|
+
Orders mine = bestResponse(s, me, opp, 3);
|
|
335
|
+
for (int it = 0; it < 3; ++it) {
|
|
336
|
+
Orders no = bestResponse(s, g_opp, mine, 2, opp);
|
|
337
|
+
if (no == opp) break;
|
|
338
|
+
opp = no;
|
|
339
|
+
mine = bestResponse(s, me, opp, 3, mine);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// 2) 一层 minimax:枚举我方候选组合,每个都算对手的最佳应对
|
|
343
|
+
const int K = 4;
|
|
344
|
+
Cmd cand[3][8];
|
|
345
|
+
int cnt[3];
|
|
346
|
+
topCommands(s, me, opp, cand, K, cnt);
|
|
347
|
+
const int n0 = cnt[0], n1 = cnt[1], n2 = cnt[2];
|
|
348
|
+
|
|
349
|
+
double bestv = -1e18;
|
|
350
|
+
Orders best = mine;
|
|
351
|
+
int evals = 0;
|
|
352
|
+
bool stop = false;
|
|
353
|
+
for (int a = 0; a < n0 && !stop; ++a)
|
|
354
|
+
for (int b = 0; b < n1 && !stop; ++b)
|
|
355
|
+
for (int c = 0; c < n2; ++c) {
|
|
356
|
+
Orders M;
|
|
357
|
+
M.cmd[0] = cand[0][a];
|
|
358
|
+
M.cmd[1] = cand[1][b];
|
|
359
|
+
M.cmd[2] = cand[2][c];
|
|
360
|
+
Orders R = bestResponse(s, g_opp, M, 1, opp);
|
|
361
|
+
const double v = planEval(s, me, M, R);
|
|
362
|
+
++evals;
|
|
363
|
+
if (v > bestv) { bestv = v; best = M; }
|
|
364
|
+
if ((evals & 7) == 0 && tank::budget_left() < 6.0) { stop = true; break; }
|
|
365
|
+
}
|
|
366
|
+
return best;
|
|
367
|
+
}
|