|
1 | 1 | # AGENTS.md — 给 Coding Agent 的仓库入口 |
2 | 2 |
|
3 | | -> 这是 `数值对战实验室`(Numerical Battle Lab)的工作指引。进入本仓库后,请先读这里。 |
| 3 | +> 这是 `数值卡牌 · 自动 PK`(numerical-battle-lab)的工作指引。 |
4 | 4 |
|
5 | 5 | ## 项目是什么 |
6 | 6 |
|
7 | | -完全离线、纯单机、确定性的多实体回合制数值战斗系统。网页用“卡片”展示实体,但卡牌只是 |
8 | | -Presentation;核心只处理 `CombatEntity + Skill + Formula + Modifier + Effect + Condition + |
9 | | -Target + Event + Status + Resource`。产品形态是「本地创造沙盒 + AI 自动观战」。 |
| 7 | +一个**多数值自动卡牌 PK 游戏**:选两张卡 → 调等级(1–100)→ 开始战斗 → 看谁赢。 |
| 8 | +不做生成器、不做技能系统、不做多队伍、不做沙盒编辑。旧版本全部在 Git 历史里,当前产品树只维护这一个版本。 |
10 | 9 |
|
11 | | -## Numerical System Source of Truth(必须先读) |
| 10 | +## 三套核心实力系统 |
12 | 11 |
|
13 | | -**在改动任何卡牌生成、平衡、AI 评估、BattlePower、战斗公式、预设、高级编辑器之前,先读:** |
| 12 | +1. **Level** — 第一维度,超指数成长:`g(L) = exp(0.02143L + 0.0002253L²)` |
| 13 | +2. **Rarity** — 第二维度,12 档(C…XS Collector),纯指数:`rarityMul(t) = exp(ln6/11·t)`,C→XS Collector = 6 倍 |
| 14 | +3. **Battle Power** — 只读最终属性的透明线性加权,**不参与战斗**,只是给玩家的综合实力数字 |
14 | 15 |
|
15 | | -1. **Canonical Numerical Knowledge Registry** — `src/numerical-knowledge.js` |
16 | | - (+ 底层注册表 `src/components.js` 的 `PARAMETER_CATALOG` / EFFECT / CONDITION / TARGET / |
17 | | - EVENT / MODIFIER_OPERATIONS)。这是所有参数/效果/条件/事件/公式变量的**唯一真源**: |
18 | | - `NCB.NUMERICAL_KNOWLEDGE()` 返回完整 registry;`NCB.knowledgeSearch()` / |
19 | | - `NCB.knowledgeLookup()` 提供查询。 |
20 | | -2. **自动生成的参考文档** — `docs/CARD-NUMERICAL-REFERENCE.md` |
21 | | - (**GENERATED FROM CANONICAL — DO NOT HAND EDIT**,由 `npm run numerical-reference` 重新生成)。 |
22 | | -3. **相关引擎测试** — `tests/*.test.js`,尤其是 `tests/numerical-knowledge.test.js` |
23 | | - (覆盖 registry、搜索、60 预设零缺口、扰动验证)。 |
| 16 | +最终属性 = 基准 × 卡牌形状 × `g(L)×rarityMul(稀有度)`。 |
24 | 17 |
|
25 | | -**不要凭变量名字猜语义。** 每个参数都应能从 registry 找到:它是什么、谁读取它、调高/调低 |
26 | | -会怎样、和什么交互、AI/BattlePower 如何理解、用户提什么需求时改它(tuningGuidance / |
27 | | -userIntentExamples)。 |
| 18 | +## 关键设计约定(改动前必读) |
28 | 19 |
|
29 | | -## 常见需求 → 应改什么(来自 registry 的 tuningGuidance) |
| 20 | +- **卡牌只读**:`src/cards.js` 固定 24 张卡(12 档 × 2 张),玩家不生成/导入/编辑卡。 |
| 21 | +- **形状归一化**:每张卡的“战斗强度” `hp·atk²/(atk+def)` 与百分比属性都收窄在窄带内, |
| 22 | + 稀有度差距**只由 rarityMul 表达**。因此: |
| 23 | + - 同级 C vs XS Collector = 6 倍 → 压倒性; |
| 24 | + - Lv70 XS Collector vs Lv100 C(p 相等 ≈81.1)→ 悬念; |
| 25 | + - 同档对抗互有胜负。 |
| 26 | + 调平衡时改某张卡的 base/百分比即可,**不要**改曲线或加系统。 |
| 27 | +- **确定性**:战斗内所有随机必须走 `src/battle.js` 的 Mulberry32 PRNG。禁止 `Math.random()`。 |
| 28 | + 同 Match Seed → 完全相同的对局。 |
| 29 | +- **先模拟后播放**:`simulate()` 生成完整事件列表,UI 只按 慢/快/瞬 的延迟回放。 |
| 30 | + 播放速度绝不能改变回合/命中/暴击/伤害/胜者。 |
| 31 | +- **1v1 only**:没有队伍、没有多目标。 |
30 | 32 |
|
31 | | -| 用户说 | 应检查 | 不要首先改 | |
32 | | -|---|---|---| |
33 | | -| “卡牌后期成长还不明显” | `RAMP_START` / `RAMP_RATE` / `RAMP_CAP` / `ROUND` / Battle Wear | 基础 `ATK` 或 rarity budget | |
34 | | -| “高波动卡还是太稳定” | `VOLATILITY` / `LUCK` / `varianceMin` / `varianceMax` / canonical PRNG | 全局伤害倍率 | |
35 | | -| “治疗卡拖得太久” | `HEAL_POWER` / `HEAL_TAKEN` / `ENDURANCE` / `FATIGUE` / Battle Wear / AI heal utility | 设计新的全局伤害机制 | |
36 | | -| “爆发卡后期仍然太强” | `FATIGUE_START` / `FATIGUE_RATE` / `FATIGUE_CAP` | 全局改基础数值 | |
37 | | -| “所有卡后期都突然崩溃” | Battle Wear 与生成分布 | 简单提高 `FATIGUE_RATE` | |
38 | | -| “资源循环从不形成有效结果” | resource consumer / `CONVERT_RATIO` / `RESOURCE_GAIN_MOD` | 直接加资源 | |
| 33 | +## 数值公式(src/power.js 与 src/battle.js) |
39 | 34 |
|
40 | | -## 关键约束(改动前必读) |
41 | | - |
42 | | -- **确定性**:战斗内所有随机必须走 canonical PRNG(`Gen5PRNG`,`kernel.js`)。禁止 `Math.random()`。 |
43 | | - 同 `battle seed + card seed + actions + battle state` 必须精确复现。 |
44 | | -- **公式安全**:`src/formula.js` 用随包固定的 Acorn 解析 + 严格白名单解释层,**禁止 `eval` / `new Function`**。 |
45 | | -- **v1/v2/v3 legacy**:`generateCardByVersion(1|2|3)` 必须逐字节复现历史版本;不要破坏 |
46 | | - Replay 兼容、deterministic reproduction、validator、Advanced Lab。 |
47 | | -- **Generator v4 无职业**:v4 不接受 `archetype` 输入;identity 不得含职业词汇。Behavior |
48 | | - Analyzer(`src/behavior.js`)是**事后**分析,纯 Presentation,**AI 与引擎不得读取 tags**。 |
49 | | -- **BattlePower 唯一真源**:展示/诊断用 `battlePowerV2(card).power`(v4 卡);引擎**不得**读取 |
50 | | - `.power`。系统预设的 `presentation.power` 必须等于 canonical(60/60 一致性测试保护)。 |
51 | | -- **预设无专属引擎代码**:系统预设(`content/presets-v4.json`)只能由统一 Card Schema 表达; |
52 | | - 禁止 `if (card.id === ...) damage *= 2`。 |
53 | | -- **数值知识强制**:任何新增/修改的 Generator 字段、Effect、Condition、Event、Formula 符号, |
54 | | - 都必须在 `src/numerical-knowledge.js` 有完整解释,否则 `scripts/audit-numerical-coverage.js` |
55 | | - 会 FAIL(`undocumentedActiveFields = 0` 是硬要求)。 |
| 35 | +- 命中率 = clamp(0.90 + (ACC−EVA)×0.004, 0.45, 0.99) |
| 36 | +- 基础伤害 = ATK² / (ATK + DEF×(1−PEN)),再 × 波动(±volatility) × 暴击(×critDmg) |
| 37 | +- Battle Power 权重见 `src/power.js::battlePower`,调权重要同时跑 `npm test` 看排序测试。 |
56 | 38 |
|
57 | 39 | ## 常用命令 |
58 | 40 |
|
59 | 41 | ```bash |
60 | | -npm test # 全量 Node 行为测试(含 v1-v7、预设、数值知识、随机/先手) |
61 | | -npm run verify # catalog + 全量测试 + 静态架构/清单门禁 |
62 | | -npm run verify:release # verify + gate:v7-product + diversity(V7 产品门禁) |
63 | | -npm run gate:v7-product # V7 轻量确定性 CI 回归门(几何/solver/产品 smoke/多轴/BP/legacy/命名/多样性) |
64 | | -npm run reality:v7 # 完整 Reality 链:37,440 场构图 → EmpiricalTheta → 校准 → dispersion → 产品门 → 多轴 → BPv4 |
65 | | -npm run audit:v7-geometry # V7 几何审计 → qa/v7-strength-geometry.json |
66 | | -npm run audit:v7-product # 产品最高纲领 A–F 大样本审计 → qa/v7-product-strength.json |
67 | | -npm run audit:v7-seed-dispersion # p95-p5 seed dispersion + matchup residuals → qa/v7-seed-dispersion.json |
68 | | -npm run audit:v7-sensitivity # 多轴敏感度审计 → qa/v7-stat-sensitivity.json + qa/v7-axis-sensitivity.json |
69 | | -npm run audit:v7-battlepower # BattlePower v4 校准 + holdout reality → qa/v7-battlepower-reality.json |
70 | | -npm run audit:v7-presets # 预设实战矩阵 + 3v3 smoke → qa/v7-preset-matrix.json |
71 | | -npm run benchmark:v7 # 1000 卡生成性能 → qa/v7-performance.json |
72 | | -npm run migrate:presets-v7 # 从 presets-v6 生成 content/presets-v7.{json,js}(Naming V3 冻结) |
73 | | -npm run diversity:v4 # 10000 张 v4 卡多样性审计 → qa/diversity-v4.json |
74 | | -npm run calibration:v4 # BattlePower v2 经验校准 → qa/power-v4-calibration.json |
75 | | -npm run migrate:presets-v5 # 从 presets-v4 迁移生成 content/presets-v5.{json,js} |
76 | | -npm run audit:power-envelope # v5 强度审计:包络/等级/稀有度/跨稀有度 Monte Carlo → qa/power-envelope-v5.json |
77 | | -npm run audit:presets-v5 # v5 预设审计:包络表/唯一名/结构一致性 → qa/presets-v5-audit.json |
78 | | -npm run audit:naming # Name Generator v3 审计(10k 唯一率/生僻字/禁用后缀/长度分布)→ qa/naming-v3-audit.json |
79 | | -npm run audit:empirical-strength # BP/稀有度 vs 真实胜率的大样本实证审计 → qa/empirical-strength.json |
80 | | -npm run numerical-reference # 从 canonical registry 重新生成 docs/CARD-NUMERICAL-REFERENCE.md |
81 | | -node scripts/audit-v4-battles.js 3000 # 3000 场长局统计 → qa/v4-long-battles.json |
82 | | -node scripts/audit-v4-presets.js # 60 预设实战审计 → qa/v4-preset-audit.json + docs/V4-PRESET-TABLE.md |
83 | | -node scripts/audit-numerical-coverage.js # 数值知识覆盖审计(缺口=0,含 v4+v5 样本) |
84 | | -node scripts/audit-numerical-semantics.js # 参数扰动验证(文档描述 == 引擎行为) |
85 | | -node qa/browser-v4.js # 真实 Chromium 移动/桌面 QA(需 playwright + 127.0.0.1:8774 静态服务) |
86 | | -node qa/browser-knowledge.js # 数值百科 UI QA(同上) |
87 | | -node qa/browser-multi.js # 多人显式编队 + 新种子/重开语义 QA(同上) |
88 | | -npm run diagnostics:legacy # V6 gate + 旧 v1.2.x 诊断(gate:v6-strength 已从 verify:release 移到这里) |
89 | | -npm run manifest # 重新生成 RELEASE-MANIFEST.json(提交新文件后必须) |
| 42 | +npm test # node:test 全量测试(零依赖) |
| 43 | +npm run verify # 静态检查(文件集合=期望清单)+ 全量测试 + 产品实战验收 |
| 44 | +npm run serve # 本地静态服务器 http://127.0.0.1:8774 |
90 | 45 | ``` |
91 | 46 |
|
92 | | -提交新文件/修改后:先 `git add`,再 `npm run manifest`,暂存清单并 `npm run verify`。 |
93 | | - |
94 | | -## 架构地图(最短路径) |
95 | | - |
96 | | -- `src/kernel.js` — Gen5PRNG + EventKernel + 行动排序(Priority → 随机先手 Initiative → 确定性兜底) |
97 | | -- `src/components.js` — 参数/效果/条件/目标/事件/修饰操作注册表(canonical 底层) |
98 | | -- `src/engine.js` — BattleEngine(伤害管线/资源/旧难度 AI/模拟/replay/Battle Wear/presentation frames) |
99 | | -- `src/ai.js` — 当前 canonical AI:`planAI(engine, team, "canonical")`;默认观战用它。非 canonical 难度显式保留旧 planner。不要仅修改 engine.js 内的 legacy skillScore。 |
100 | | -- `src/formula.js` — Acorn + 白名单表达式解释层 |
101 | | -- `src/gen-v4.js` — Generator v4(legacy:classless、连续预算、个体变量、时间机制) |
102 | | -- `src/gen-v5.js` — **Generator v5(legacy)**:结构先于强度;同 seed 结构跨等级/稀有度不变; |
103 | | - 先生成结构 → 算 LevelScale → 算 Rarity PowerEnvelope → targetPower → battlepower-v3 有界校准 |
104 | | -- `src/budget-v6.js` — **Budget v6**:TotalStrengthBudget = ExpectedStrength(level,rarity) |
105 | | - = 1000×LevelScale×RarityStrengthScale(C=1.0…XS_COLLECTOR=12.0);Seed 只能再分配固定总额 |
106 | | -- `src/budget-price.js` — **budget-price**:生成期因果机制定价(独立于 battlepower-v3) |
107 | | -- `src/gen-v6.js` — **Generator v6(当前默认)**:Level×Rarity 决定总预算,Seed 生成受界 allocation profile;主面板与机制都消费预算,同档位面板真实多样;确定性价格调和不调用 BattlePower、AI、参考对手或战斗引擎。 |
108 | | -- `src/strength-audit-v6.js` — 逐场镜像计分与 Wilson 95% CI 的唯一共享实现。 |
109 | | -- `scripts/gate-v6-strength.js` — v6 强度回归门(verify:release 内小样本确定性检查) |
110 | | -- `scripts/audit-v6-strength.js` — v6 大样本实证审计(稀有度/等级差距 + 同档位 USI)→ qa/v6-strength-audit.json |
111 | | -- `src/power-v5.js` — **Power Envelope v1**:LevelScale + 12 稀有度包络(min/target/max)+ 质量百分位 |
112 | | -- `src/battlepower-v2.js` — BattlePower v2(legacy v4 估算器) |
113 | | -- `src/battlepower-v3.js` — **BattlePower v3(v5 canonical)**:只读真实数值、绝不读稀有度/等级/clamp |
114 | | -- `src/name-generator-v2.js` — **Name Generator v2(legacy)**:旧物种命名语法(保留兼容) |
115 | | -- `src/name-generator-v3.js` — **Name Generator v3(默认)**:可读音节语素命名;6 个纯语音家族 |
116 | | - (ROUND/AGILE/HEAVY/SLEEK/WILD/ANCIENT),2/3/4 字 = 10/70/20,5 字禁止;名字只由 |
117 | | - `seed` 决定(不看稀有度/等级/BP/机制指纹);官方 60 预设为人工定稿名称(apply-preset-names-v3) |
118 | | -- `src/behavior.js` — Behavior Analyzer(事后 tags/summary,Presentation only) |
119 | | -- `src/numerical-knowledge.js` — **Canonical Numerical Knowledge Registry**(本文件) |
120 | | -- `src/card-browser.js` / `src/card-ui.js` / `src/app.js` — 卡牌浏览/详情/玩家 UI(多人显式编队 selectedTeams;普通对局新 seed;重开=新局) |
121 | | -- `content/presets-v4.json`(+`.js`) — 60 张 v4 冻结预设(legacy 兼容 fixture) |
122 | | -- `content/presets-v5.json`(+`.js`) — **60 张 v5 官方预设**(新名字 + 全部落入 Level×Rarity 包络,mechanicFingerprint 保留) |
123 | | -- `scripts/migrate-presets-v5.js` — v4→v5 预设迁移(重命名 + 数值重校准,结构不变) |
124 | | -- `scripts/audit-v5-strength.js` / `audit-presets-v5.js` / `audit-naming-v3.js` / `apply-preset-names-v3.js` — v5 强度/预设/命名审计 |
125 | | -- `scripts/audit-*.js` — 多样性/长局/预设/数值知识/语义审计 |
126 | | -- `docs/GENERATOR-V4*.md` / `docs/CARD-NUMERICAL-REFERENCE.md` / `docs/V4-PRESET-*.md` — 文档 |
127 | | - |
128 | | -## 审计证据的边界 |
| 47 | +## 修改卡牌/数值后的检查清单 |
129 | 48 |
|
130 | | -- 数值 coverage 零缺口只证明字段可查,不能证明所有参数都有扰动测试;当前语义审计覆盖 ATK、LIFESTEAL、VOLATILITY、RAMP、FATIGUE、HEAL_POWER 六条。 |
131 | | -- AI 的当前状态效用不是多回合搜索。长局、条件链、资源与伤害 EV 的近似局限见 `docs/FINAL-VISION-AUDIT.md`。 |
132 | | -- 卡面缓存由 `cardPresentationSignature` 统一失效;修改 schema / 战力权重后,验证 metadata 与 canonical 计算一致。 |
| 49 | +1. `npm test`(BP 排序、确定性、验收匹配全部要绿) |
| 50 | +2. `npm run verify` |
| 51 | +3. 如果改了 `index.html` 的 script 标签或新增/删除文件,同步更新 `scripts/static-check.js` 的期望清单 |
0 commit comments