/** * Not part of the suite — a measuring tool. Run with `npm run stats:bot`. * * Plays a large number of seeded matches between two BasicBots and prints how * they came out. Useful for sanity-checking a rules change (a sudden jump in * draws or in the first-attacker advantage means something moved) and as the * baseline any smarter bot has to beat. */ import { describe, it } from 'vitest'; import { BasicBot } from '@core/bot/BasicBot'; import { Match } from '@core/match/Match'; import { runMatch } from '@core/match/runMatch'; const MATCHES = 5000; describe('BasicBot vs BasicBot', () => { it(`plays ${MATCHES} matches`, () => { const tally: Record = { you: 0, bot: 0, draw: 0 }; let firstAttackerLost = 0; let actions = 0; let turns = 0; for (let seed = 0; seed < MATCHES; seed++) { const match = new Match({ players: ['you', 'bot'], seed }); const firstAttacker = match.state.players[match.state.attacker].id; const result = runMatch(match, { you: new BasicBot('you'), bot: new BasicBot('bot') }); tally[result.loser ?? 'draw'] += 1; if (result.loser === firstAttacker) firstAttackerLost += 1; actions += result.actions; turns += result.turns; } const pct = (n: number) => `${((100 * n) / MATCHES).toFixed(1)}%`; console.log([ `matches ${MATCHES}`, `seat 'you' lost ${tally.you} (${pct(tally.you)})`, `seat 'bot' lost ${tally.bot} (${pct(tally.bot)})`, `draws ${tally.draw} (${pct(tally.draw)})`, `first attacker lost ${pct(firstAttackerLost)}`, `average actions ${(actions / MATCHES).toFixed(1)}`, `average turns ${(turns / MATCHES).toFixed(1)}`, ].join('\n')); }); });