created harness to better test bots. improved bot play

This commit is contained in:
Jesse
2026-08-09 19:24:54 -04:00
parent 35575147cd
commit 4a800a053a
13 changed files with 6263 additions and 5503 deletions
+23 -8
View File
@@ -21,8 +21,12 @@
* abandoned an expensive channel for a cheap one, and the two are identical in a single number.
*
* Run with:
* node src/sim/compare.ts 1600 trainCapSlack=1
* node src/sim/compare.ts 400 trainCapSlack=0 --length short
* node src/sim/compare.ts 1600 noTrainCap=1 — what the A/D cap is worth today
* node src/sim/compare.ts 1600 noOperateFirst=1 — what operating before drawing is worth
*
* The flags are ABLATIONS: they turn off heuristics the bot already plays, so a negative delta is
* the heuristic earning its place. That is what a measured bot needs going forward — the question
* is no longer "does this help?" but "is this still true after the deck moved?".
*/
import { pump } from '../engine/advance.ts';
@@ -198,17 +202,28 @@ export function formatPaired(r: PairedResult): string {
// CLI
// ---------------------------------------------------------------------------
/** `trainCapSlack=1` -> `{ trainCapSlack: 1 }`. Unknown names are refused rather than ignored. */
/**
* `noTrainCap=1` -> `{ noTrainCap: true }`.
*
* Unknown names THROW rather than being ignored: a typo parsed as "no tweaks" would compare the bot
* against itself and report a confident zero, which is the most expensive way this tool could fail.
*/
export const NUMERIC_TWEAKS = new Set<string>([]);
export const BOOLEAN_TWEAKS = new Set(['noTrainCap', 'noOperateFirst']);
export function parseTweaks(args: string[]): BotTweaks {
const known = new Set(['trainCapSlack']);
const tweaks: Record<string, number> = {};
const tweaks: Record<string, number | boolean> = {};
for (const a of args) {
const m = /^([A-Za-z]\w*)=(-?\d+(?:\.\d+)?)$/.exec(a);
if (!m) continue;
if (!known.has(m[1]!)) {
throw new Error(`unknown tweak "${m[1]}" — known: ${[...known].join(', ')}`);
const name = m[1]!;
if (NUMERIC_TWEAKS.has(name)) tweaks[name] = Number(m[2]);
else if (BOOLEAN_TWEAKS.has(name)) tweaks[name] = Number(m[2]) !== 0;
else {
throw new Error(
`unknown tweak "${name}" — known: ${[...NUMERIC_TWEAKS, ...BOOLEAN_TWEAKS].join(', ')}`,
);
}
tweaks[m[1]!] = Number(m[2]);
}
return tweaks as BotTweaks;
}