feedback1 integrate: WF smarter bots (same decision time)

# Conflicts:
#	docs/META.md
#	server/match/bot.js
This commit is contained in:
sganggs committed 2026-10-03 07:07:23 +08:00
commit 88d419b095
5 files changed
+1319 -145

No files matched your search

+44 -15
View File
@@ -185,21 +185,46 @@ The rest of this section is the legacy server-run mode
另一组队友的战场情况" → `BAD_TARGET 'other group hidden'`); eliminated / departed players spectate any field.
### 1.5 AI player (bot.js)
Buys toward a full board first (the cap is 8 from R1; leftover funds are lost), then levels on a curve
(L2 ≈ R3, L3 ≈ R5, L4 ≈ R7, L5 ≈ R10, L6 ≈ R12 — the competent curve of docs/BALANCE.md; free levels always), then
spends the rest on merge progress, bond thresholds around a focus core bond (most owned members, ties → most copies
left in the shared pool), role needs (2 blockers, anti-air when the wave flies, ≤ 2 healers), 特质 that keep adding
layers (every prep / refresh — the layer engines) and items for free carriers (突变细胞 on its least valuable single
normal operator below 6阶 — never an elite or one of a merge pair, `bot.js cellTarget`; a cell left in temp gets a hand
slot made for it, `makeHandRoom`); refreshes while a purchase stays
affordable; sells bench chess that neither make the lineup nor build toward something (a live pair, the focus bond,
an elite). The deployed set maximizes unit value + activated bond tiers (exact counting via `computeBonds`). Placement
uses the round's enemy preview: every route is traced over the own board (ground: the stage's device-aware ground
paths; flyers: through their checkpoints) and weighted by its enemies; an exposure model (time on each tile × DPS of
the units covering it, blocker hold time, anti-air only on flying routes) is maximized greedily (blockers, then
damage dealers, then healers). Boss rounds: the player's boss-field template (`Match.bossWaves`) is mapped onto the
own board (rows −7, the right player of a pair mirrored, only the routes that end on its half) and the leader counts
as 10 tough enemies with a 30 s dwell on its first tiles, so the damage dealers reach stationary leaders.
Buys toward a full board first (the cap is 8 from R1; leftover funds are lost), completes the merges it can afford,
then levels on a curve (L2 ≈ R3, L3 ≈ R5, L4 ≈ R7, L5 ≈ R10, L6 ≈ R12 — the competent curve of docs/BALANCE.md; free
levels always), then spends the rest (a band that keeps its leftover funds — 坎诺特 利滚利 — holds its interest capital
of 5 back from refreshes, full-board buys that complete nothing, items and spare level-ups). It builds around a
**focus core bond** (owned members × 10 + members the shop can still bring at its level + banked layers + 6 for last
round's focus, − 6 when it is a teammate's main core bond on that teammate's bond strip — humans included: the pool is
shared) and a **second bond** (most owned members, next threshold within reach); its keepers are the deployed
operators, the focus / second members and chess of tier ≥ shop level − 1. With a full board a purchase must be merge
progress or a lineup upgrade **and** be worth more than the refreshes its price would pay for: a refresh is worth
Σ over the held pairs of P(the refresh shows the third copy) × the value of an elite (the shop's copy-weighted odds
over the remaining pool; an elite also brings the merge's free pick of the next tier, so any pair is worth completing)
— otherwise it refreshes. Up to 4 pairs wait on the bench (6 spare units, pairs first); a third copy it cannot afford
freezes the shop for the next round (freeze is free). Purchase scores: merge progress > bond thresholds > role needs
(2 blockers, anti-air when the wave flies, ≤ 2 healers) > tier, the 特质 that keep adding layers, and armour fit (the
share of a dealer's damage that gets through the round's DEF / RES — `mitigate` of the sim per hit, HP-weighted over
the wave). The deployed set maximizes unit value + activated bond tiers (exact counting via `computeBonds`; every
deployed focus member counts toward the next threshold). Items by what they do: equipment on the strongest deployed
damage dealers (survival items on blockers first, bond signature items on a member), 信标 on a bench single (never the
lineup when a bench single exists), 拟态物质 on a pair, 博士投影 (both qualities — neither takes an elite) on the strongest
normal operator, 突变细胞 on the least valuable normal operator below 6阶 (deployed or benched — never an elite, never one
of a merge pair, never one already carrying a cell; it comes back after every transformation, and a cell left in temp
gets a hand slot made for it, `makeHandRoom` — on a bot's own seat by destroying the cheapest other hand item if no
chess can be sold, never a human's item under AI 托管), 身份牌 / 通讯机 / 寻呼模块 on a focus member; 画卷 copies the most
valuable deployed operator; 教鞭 / “神秘顾客” are used after a perfect battle and otherwise kept in the hand — a bot drops
a kept one only when it needs the hand slot (“神秘顾客” then pays its fund), a human's seat under AI 托管 never. 机变: a
bounty card is scored by its expected payout minus its expected leaks × the value of an LP (2 + 20 / LP), the kill
chance from the exposure model below for that one enemy against the own board as it stands (its HP × the round's
multiplier, DEF / RES, speed, route kind) — an expected-value comparison: it prefers the card with the best payout
minus expected LP loss and takes one it is unlikely to beat only when nothing better is offered or the pay difference
is large (in co-op 绝境 most remaining bounty leaks come from drafts with no beatable card at all); tactic cards by what
they act on (a 盟誓 / 驰援 card on its bonds, 升华, …). Placement uses the round's enemy preview: every route is traced
over the own board (ground: the stage's device-aware ground paths; flyers: through their checkpoints) and weighted by
its enemies; an exposure model (time on each tile × DPS against the round's armour of the units covering it, blocker
hold time, anti-air only on flying routes) is maximized greedily (blockers, then damage dealers, then healers); a
tactician's 援军 goes on a tile of the tactician's attack range (`PlayerState.summonRange`, the server's own rule; player
report #9 after 0.1.0), and a tile the server's `g.move` refuses is skipped for the next best one (the planner reads
`board.js legalTiles` on the deploy map; `g.move` is the judge). Boss
rounds: the player's boss-field template (`Match.bossWaves`) is mapped onto the own board (rows −7, the right player
of a pair mirrored, only the routes that end on its half) and the leader counts as 10 tough enemies with a 30 s dwell
on its first tiles, so the damage dealers reach stationary leaders.
**Rehearsal:** with `opts.botRehearsal = N` (default 3) the bot simulates the N best
distinct layout variants once each with the real `Battle` (a rehearsal seed, no meta dispatch, board restored exactly)
and keeps the one with the fewest leaks; a candidate whose counted leaks already exceed the best finished one's stops
@@ -669,6 +694,10 @@ CUSTOM texts (eliminations, 联防, hidden core).
* `node tools/matchrun.mjs --mode coop --difficulty HARD --players 4 --seeds 20` — per-round balancing summary / aggregate
(`--check` audit, `--errors` per-source error table, `--lp N` / `--layers N` to reach late rounds — the boost stops at
999 per bond —, `--rehearsal N`).
* `node tools/botbench.mjs --configs solo:HARD,coop4:HARD --seeds 40 --jobs 4 --json new.json` — the AI player's
outcomes (wins, rounds passed, LP left, leaks per round, bounties taken / leaked and the kill-chance calibration,
merges, board value, bond tiers, layers, elites) and its decision time per prep (wall clock and CPU, p50 / p95, the
layout rehearsal apart); `--compare old.json new.json` prints the A/B tables (the same seeds on two builds).
* `node tools/balance.mjs --mode multi --difficulty NORMAL` — the competent-board difficulty model (docs/BALANCE.md):
per round leaks / LP after 联防 / clear time of representative boards against the real waves, boss damage by 150 s
and kill time; `--tuning off` (research numbers), `--legacy-time`, `--profile weak|strong`, `--bots N`, `--json`.