feedback1 gaps: bands.json bondIds is built once and read by the bot
The band -> bond derivation moves out of GameData into shared/bandBonds.js, which tools/build-data.mjs runs per band to write bands.json bondIds (regenerated with --offline; 9 bands are tied, the build checks the ids). GameData.bandBondIds reads the field, so the server and the client share one source. DATA.md documents the field; the test checks the helper on synthetic bands and that the data matches it.
This commit is contained in:
1 parent
3bd855982e
commit
1f29b8a3d0
7 files changed
+86
-46
No files matched your search
+2
-2
@@ -60,8 +60,8 @@
|
||||
// for it, makeHandRoom, instead of being destroyed), keep one hand slot free (freeHandSlot: a kept bounty Art goes
|
||||
// before a chess on a bot's own seat, never on a human's seat under AI 托管), then Ready.
|
||||
// Strategy (botPickBand): weighted by starting LP among the offered bands; never one whose mechanic rides on a bond the
|
||||
// mode switches off (gd.bandBondIds: the bond its text names in <…> or its effect's blackboards name — 标准's 潘格尼尼,
|
||||
// 克莱门莎, 玛恩纳; DESIGN §21.26); alone, 老鲤's withheld first-round funds only rarely (× 0.02).
|
||||
// mode switches off (gd.bandBondIds = bands.json bondIds: the bond its text names in <…> or its blackboards name — 标准's
|
||||
// 潘格尼尼, 克莱门莎, 玛恩纳; DESIGN §21.26); alone, 老鲤's withheld first-round funds only rarely (× 0.02).
|
||||
// 机变 (botPickCard): a bounty by its expected payout minus the expected LP lost — bountyKillChance runs the exposure
|
||||
// model for that one enemy against the own board; a card the board is unlikely to beat wins only when nothing better
|
||||
// is offered or it pays much more —; tactic cards by what they act on (a 盟誓 / 驰援 card on the own bonds, 升华 …);
|
||||
|
||||
@@ -90,8 +90,7 @@ export class GameData {
|
||||
for (const k of Object.keys(this.shopItemsByTier)) this.shopItemsByTier[k].sort();
|
||||
this.bondIds = Object.keys(this._bonds).sort((a, b) => (numOr(this._bonds[a].identifier, 99) - numOr(this._bonds[b].identifier, 99)) || (a < b ? -1 : 1));
|
||||
this.modeInactiveBonds = new Set(Array.isArray(this.mode.inactiveBondIds) ? this.mode.inactiveBondIds : []);
|
||||
/** bond name → id (bandBondIds) and its memo */
|
||||
this._bondByName = new Map(Object.entries(this._bonds).filter(([, r]) => r && typeof r.name === 'string').map(([id, r]) => [r.name, id]));
|
||||
/** bandBondIds memo */
|
||||
this._bandBonds = new Map();
|
||||
this.inactiveEnemies = new Set(Array.isArray(this.mode.inactiveEnemyKeys) ? this.mode.inactiveEnemyKeys : []);
|
||||
/** data/tuning.json (titles only, see the header) */
|
||||
@@ -462,41 +461,19 @@ export class GameData {
|
||||
}
|
||||
|
||||
/**
|
||||
* The bonds a strategy's mechanic is built around, read from its own data (DESIGN §21.26): the bond names its text puts
|
||||
* in <…> — the official note "在<X>部分干员缺席时体验可能不完整" names that bond too — and the bond ids and bond pools its
|
||||
* effect's blackboards name (bb / bbStr values: 克莱门莎's `bond_id` egirShip, 玛恩纳's `bond` kazimierzShip, 潘格尼尼's
|
||||
* `pool` pool_char_later → choices.json pools[pool].bond lateranoShip). Names map to ids through bonds.json; a bracketed
|
||||
* name that is no bond (<寻呼模块>, <画卷>, <鸭爵> …) and a pool without a bond add nothing. Bond ids in data order,
|
||||
* [] for an unknown band or one tied to no bond (华法琳, 阿米娅 …). The bot never picks a strategy tied to a bond the mode
|
||||
* switches off (bot.js botPickBand: 标准's 潘格尼尼 / 克莱门莎 / 玛恩纳).
|
||||
* The bonds a strategy's mechanic is built around (DESIGN §21.26): bands.json `bondIds`, written at build time by
|
||||
* shared/bandBonds.js from the band's own text and blackboards (潘格尼尼 → 拉特兰, 克莱门莎 → 阿戈尔, 玛恩纳 → 卡西米尔 …) —
|
||||
* the field the strategy draft's 本局禁用 mark reads too. Known bond ids in data order; [] for an unknown band, one tied to
|
||||
* no bond (华法琳, 阿米娅 …) or data without the field. The bot never picks a strategy tied to a bond the mode switches
|
||||
* off (bot.js botPickBand).
|
||||
* @param {string} bandId
|
||||
* @returns {string[]}
|
||||
*/
|
||||
bandBondIds(bandId) {
|
||||
if (this._bandBonds.has(bandId)) return this._bandBonds.get(bandId);
|
||||
const b = this.band(bandId);
|
||||
const found = new Set();
|
||||
if (b) {
|
||||
for (const [, name] of String(b.desc || '').matchAll(/<([^<>]+)>/g)) {
|
||||
const id = this._bondByName.get(name.trim());
|
||||
if (id) found.add(id);
|
||||
}
|
||||
const pools = this.choices.pools && typeof this.choices.pools === 'object' ? this.choices.pools : {};
|
||||
for (const buff of Array.isArray(b.buffs) ? b.buffs : []) {
|
||||
for (const board of [buff && buff.bb, buff && buff.bbStr]) {
|
||||
if (!board || typeof board !== 'object') continue;
|
||||
for (const v of Object.values(board)) {
|
||||
if (typeof v !== 'string') continue;
|
||||
for (const part of v.split(',').map((s) => s.trim())) {
|
||||
if (this.bond(part)) found.add(part);
|
||||
const pool = own(pools, part);
|
||||
if (pool && typeof pool.bond === 'string' && this.bond(pool.bond)) found.add(pool.bond);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const out = Object.freeze(this.bondIds.filter((id) => found.has(id)));
|
||||
const listed = this.band(bandId)?.bondIds;
|
||||
const set = new Set(Array.isArray(listed) ? listed : []);
|
||||
const out = Object.freeze(this.bondIds.filter((id) => set.has(id)));
|
||||
this._bandBonds.set(bandId, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user