feedback5 WE2: AI 托管 buys the player's own 自选 pieces more readily and levels toward them a round earlier (#13)

bot.js: the player's own slotted piece scores DIY_PIECE_BONUS (12) more; levelUp takes the
step that opens a slotted tier with copies left one round earlier (diyOpensAt). Bots field
no 自选 piece. Exports buyScoreOf / levelUp / diyOpensAt for the tests. Docs: DESIGN §6.6,
PLAYING. Golden: coop2-NORMAL-70-diy moved — the 自选 seat under AI 托管 reaches level 6 one
round earlier and fields its tier-6 Sharp at round 12.
This commit is contained in:
sganggs committed 2026-10-06 15:54:07 +08:00
1 parent d31de31e31
commit 2eaef154d5
5 files changed
+98 -16

No files matched your search

+25 -1
View File
@@ -119,6 +119,12 @@ const MAX_REFRESHES = 16;
const BENCH_BUDGET = 6;
/** Shop level the bot aims for at the start of round r (index = round). */
const LEVEL_TARGET = [1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 6];
/**
* AI 托管 of a human with 自选 picks (0.2.0; bots field none): the buy score of one of the player's own slotted pieces —
* the operator the player chose to field (follow-up #13: under AI 托管 they were rarely bought) — and the 调度中心 is
* levelled one round earlier for the step that opens a slotted tier (levelUp).
*/
export const DIY_PIECE_BONUS = 12;
const TIER_POWER = [0, 10, 12.5, 15, 18, 21.5, 25];
/** Prep-side 特质 that keep adding bond layers every round / every refresh (a player's main layer engine). */
const RECURRING_TRAIT_EVENTS = new Set(['SERVER_PREP_START', 'SERVER_PREP_FIN', 'SERVER_REFRESH_SHOP']);
@@ -563,6 +569,11 @@ function chooseLineup(m, ps, ctx) {
return { set, bench, score };
}
/** buyScore with a fresh context (tests). */
export function buyScoreOf(m, ps, id) {
return buyScore(m, ps, id, context(m, ps));
}
/** Shop / reward score of acquiring one copy of chess `id` (0 = not worth it). */
function buyScore(m, ps, id, ctx) {
const gd = ps?.gd || m.gd;
@@ -589,6 +600,8 @@ function buyScore(m, ps, id, ctx) {
if (isHealer(c)) s += ctx.roles.healers === 0 && m.round >= 3 ? 6 : ctx.roles.healers >= 2 ? -14 : -3;
if (c.attackKind === 'none' && !isHealer(c)) s -= 4;
if (ctx.model && !isHealer(c)) s += ARMOR_WEIGHT * 0.6 * (armorFit(ctx.model, c) - 0.6);
// the player's own 自选 piece (a slotted slot: its composed record carries diyFor) — AI 托管 of a human with picks
if (c.diyFor) s += DIY_PIECE_BONUS;
return s;
}
@@ -1385,7 +1398,16 @@ function maybeFreeze(m, ps) {
if (ps.shop.slots.some((s) => s && !s.sold && s.kind === 'chess' && ps.priceOf(s) > ps.funds && ps.completesChessMerge(s.id))) tryDo(() => ps.freeze());
}
function levelUp(m, ps, { spare = false } = {}) {
/** Whether level `lv` of the 调度中心 opens one of the player's slotted 自选 pieces with copies left (player/diy.js). */
export function diyOpensAt(ps, lv) {
const st = ps.diyStock;
if (!st || !st.entries || !st.entries.size) return false;
for (const e of st.entries.values()) if (e.shopLevel === lv && e.left > 0) return true;
return false;
}
/** The 调度中心 level-ups of a bot's prep (exported for tests). */
export function levelUp(m, ps, { spare = false } = {}) {
const gd = ps?.gd || m.gd;
for (let guard = 0; guard < 6; guard++) {
if (ps.shop.level >= gd.maxShopLevel) return;
@@ -1398,6 +1420,8 @@ function levelUp(m, ps, { spare = false } = {}) {
const boardReady = ps.allChess().length >= (r <= 4 ? ps.deployCap : Math.min(ps.deployCap, 6));
let want = price === 0;
if (!want && ps.shop.level < target && (boardReady || r >= 6)) want = true;
// a human's 自选 slots of the next level (AI 托管): that step one round earlier (DIY_PIECE_BONUS)
if (!want && boardReady && ps.shop.level < nextTarget && diyOpensAt(ps, ps.shop.level + 1)) want = true;
if (!want && ps.shop.level < nextTarget && price <= 2 && boardReady) want = true;
if (!want && spare && ps.funds >= price + 1 + fundsReserve(m, ps) && ps.shop.level < nextTarget + 1 && boardReady) want = true;
if (!want && ps.funds >= price + 14) want = true;