test: add fight length and KO rate distribution test
Simulates 1000 full fights with HP tracking (200 HP start, 7-10 rounds) to verify average fight length (5-10 rounds) and KO rate (20-80%). Validates the balance between damage output and HP pool. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
57af4e6a25
commit
1f532681df
@@ -420,6 +420,63 @@ describe('fight lifecycle', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('average fight lasts 5-10 rounds with ~30-70% KO rate', () => {
|
||||||
|
const STARTING_HP = 200
|
||||||
|
let totalRounds = 0
|
||||||
|
let totalKOs = 0
|
||||||
|
const totalFights = 1000
|
||||||
|
|
||||||
|
for (let f = 0; f < totalFights; f++) {
|
||||||
|
const eloA = 1000 + Math.floor(Math.random() * 800)
|
||||||
|
const eloB = 1000 + Math.floor(Math.random() * 800)
|
||||||
|
const botA = { id: 'fl-a', name: 'A' }
|
||||||
|
const botB = { id: 'fl-b', name: 'B' }
|
||||||
|
const usedTypes = new Set<string>()
|
||||||
|
let hpA = STARTING_HP
|
||||||
|
let hpB = STARTING_HP
|
||||||
|
let comboA = 0
|
||||||
|
let comboB = 0
|
||||||
|
const maxRounds = 7 + Math.floor(Math.random() * 4) // 7-10 rounds like mock.ts
|
||||||
|
let rounds = 0
|
||||||
|
|
||||||
|
for (let r = 0; r < maxRounds; r++) {
|
||||||
|
const challenge = pickChallenge(usedTypes, null, undefined, r + 1)
|
||||||
|
usedTypes.add(challenge.type)
|
||||||
|
const respA = mockResponse(challenge, 'confident', eloA)
|
||||||
|
const respB = mockResponse(challenge, 'confident', eloB)
|
||||||
|
const result = scoreRound(
|
||||||
|
challenge, botA, botB,
|
||||||
|
{ answer: respA.answer, timeMs: respA.timeMs, timedOut: respA.timedOut, error: respA.error },
|
||||||
|
{ answer: respB.answer, timeMs: respB.timeMs, timedOut: respB.timedOut, error: respB.error },
|
||||||
|
null, comboA, comboB,
|
||||||
|
)
|
||||||
|
|
||||||
|
hpB = Math.max(0, hpB - result.botADamage)
|
||||||
|
hpA = Math.max(0, hpA - result.botBDamage)
|
||||||
|
if (result.winnerId === botA.id) { comboA++; comboB = 0 }
|
||||||
|
else if (result.winnerId === botB.id) { comboB++; comboA = 0 }
|
||||||
|
rounds++
|
||||||
|
|
||||||
|
if (hpA <= 0 || hpB <= 0) {
|
||||||
|
totalKOs++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalRounds += rounds
|
||||||
|
}
|
||||||
|
|
||||||
|
const avgRounds = totalRounds / totalFights
|
||||||
|
const koRate = totalKOs / totalFights
|
||||||
|
|
||||||
|
// Average fight should be 5-10 rounds
|
||||||
|
expect(avgRounds).toBeGreaterThan(4)
|
||||||
|
expect(avgRounds).toBeLessThan(10)
|
||||||
|
|
||||||
|
// KO rate should be reasonable (30-70% of fights end in KO)
|
||||||
|
expect(koRate).toBeGreaterThan(0.2)
|
||||||
|
expect(koRate).toBeLessThan(0.8)
|
||||||
|
})
|
||||||
|
|
||||||
it('Elo difference correlates with win rate', () => {
|
it('Elo difference correlates with win rate', () => {
|
||||||
const scenarios = [
|
const scenarios = [
|
||||||
{ eloA: 1400, eloB: 1400, expectedAWinMin: 0.40, expectedAWinMax: 0.60 },
|
{ eloA: 1400, eloB: 1400, expectedAWinMin: 0.40, expectedAWinMax: 0.60 },
|
||||||
|
|||||||
Reference in New Issue
Block a user