feedback1 cell: bots let their placement step judge the operator a 突变细胞 transformation gained
With the bench rule the gained operator starts the next prep on the bench while its carrier's deployment is free. The buy loop's pre-emptive bench shed sells the weakest bench single by piece value while the bench is crowded, before the placement step runs: in 20 solo 绝境 matches on 昆图斯 it sold 44 of 222 gained operators that way. - bot.js: botPrepEndSteps remembers the chess owned when the prep ends (rememberOwned); the shed's keepFresh now also spares a piece gained since then (a transformation's operator, battle-result / round-start grants), so the lineup step decides about it. No memory yet (a first prep, a seat just put under AI 托管) changes nothing. - botbench, decisions only: 昆图斯 (seeds 201-220) 绝境 7 -> 11 / 20 wins with the fix (8 on the WA build), 险境 16 -> 17 / 20 (15); the bots' own strategies unchanged within noise (solo 绝境 8 / 12 both, solo 险境 19 / 24 both, co-op 绝境 4 AI 9 -> 8 / 36). - Test: a real solo 绝境 昆图斯 bot match (seed 9 sold its R7 operator in the R8 prep before the fix): no gained operator shed in its first prep, none waiting on the bench beside a free deployment. - DESIGN §21.1 / §21.6 / §6.6, META and the CHANGELOG line say so.
This commit is contained in:
1 parent
2981ff7ae6
commit
3dcbcd572b
5 files changed
+69
-11
No files matched your search
@@ -520,6 +520,43 @@ test('#4 bots and AI 托管 deploy the gained operator in their normal placement
|
||||
m.dispose();
|
||||
});
|
||||
|
||||
test('#4 a bot on 昆图斯 lets the placement step judge each gained operator: the bench shed never sells one in its first prep, and no deployment stays free while one waits on the bench', () => {
|
||||
// a real solo 绝境 bot match on strategy 昆图斯 (the only band on offer, as tools/botbench.mjs --band) through R8: the
|
||||
// buy loop's pre-emptive bench shed sells by piece value while the bench is crowded — before rememberOwned it sold this
|
||||
// seed's R7 operator in the R8 prep (20 such matches: 44 of 222 gained operators, before any placement step saw them)
|
||||
const seats = [{ seat: 0, playerId: 'ai_0', name: 'AI', isBot: true, connected: true }];
|
||||
const h = makeMatch({ mode: 'solo', difficulty: 'HARD', seats, seed: 9, registry: REG });
|
||||
const m = h.m;
|
||||
m.gd.bandIds = () => ['band_quintus'];
|
||||
const ps = h.ps('ai_0');
|
||||
const gained = new Map(); // uid → round of the SETTLE that gained it
|
||||
const shed = [];
|
||||
const waiting = [];
|
||||
const transform = ps.transformChess.bind(ps);
|
||||
ps.transformChess = (...a) => { const np = transform(...a); if (np) gained.set(np.uid, m.round); return np; };
|
||||
const sell = ps.sell.bind(ps);
|
||||
ps.sell = (uid) => {
|
||||
if (gained.get(uid) === m.round - 1 && /buyLoopSteps/.test(new Error().stack)) shed.push(`R${m.round} ${ps.find(uid)?.piece.id}`);
|
||||
return sell(uid);
|
||||
};
|
||||
const setReady = ps.setReady.bind(ps);
|
||||
ps.setReady = (on) => {
|
||||
for (const [uid, r] of gained) {
|
||||
const loc = r === m.round - 1 ? ps.find(uid) : null;
|
||||
if (on && loc && loc.area !== 'board' && ps.deployCount < ps.deployCap) waiting.push(`R${m.round} ${loc.piece.id} ${ps.deployCount}/${ps.deployCap}`);
|
||||
}
|
||||
return setReady(on);
|
||||
};
|
||||
h.start();
|
||||
h.run(() => h.ended != null || (m.phase === 'PREP' && m.round === 9));
|
||||
assert.equal(ps.bandId, 'band_quintus');
|
||||
assert.ok(gained.size >= 5, `the cell transformed after every battle from R3 (${gained.size})`);
|
||||
assert.deepEqual(shed, [], 'no operator sold by the bench shed in the prep after its gain');
|
||||
assert.deepEqual(waiting, [], 'a gained operator off the board only when the board is full');
|
||||
checkInvariants(m);
|
||||
m.dispose();
|
||||
});
|
||||
|
||||
test('#10 AI 托管 never destroys a human\'s item to clear temp: a bench operator is sold for its slot instead', () => {
|
||||
const s = setup({ seed: 34 });
|
||||
const { m, ps } = s;
|
||||
|
||||
Reference in new issue
Block a user