diff --git a/server/src/engine/scoring-analysis.test.ts b/server/src/engine/scoring-analysis.test.ts index 3333096..06d4f01 100644 --- a/server/src/engine/scoring-analysis.test.ts +++ b/server/src/engine/scoring-analysis.test.ts @@ -258,6 +258,59 @@ describe('scoring competitiveness analysis', () => { expect(true).toBe(true) }) + it('RESEARCH: combo system snowball analysis — first-to-lead win rate', () => { + const N = 1000 + let firstLeadWins = 0, nonFirstLeadWins = 0, draws = 0 + + for (let i = 0; i < N; i++) { + const result = simulateFight({ + bothCorrect: false, + botAAccuracy: 0.8, + botBAccuracy: 0.8, + botASpeedMs: 1200, + botBSpeedMs: 1200, + speedVariance: 400, + rounds: 20, + }) + + // Determine who won the first non-draw round + let firstLeader: string | null = null + for (const r of result.rounds) { + if (r.winnerId) { + firstLeader = r.winnerId + break + } + } + + if (!result.winnerId) { + draws++ + } else if (result.winnerId === firstLeader) { + firstLeadWins++ + } else { + nonFirstLeadWins++ + } + } + + const snowballRate = firstLeadWins / (firstLeadWins + nonFirstLeadWins) * 100 + + const section = [ + '## Combo System Snowball Analysis (1000 fights, 80% accuracy, equal speed)', + '', + `- First-to-lead wins: ${firstLeadWins} (${snowballRate.toFixed(1)}% of decided fights)`, + `- Non-first-lead wins: ${nonFirstLeadWins}`, + `- Draws: ${draws}`, + `- Snowball rate: ${snowballRate.toFixed(1)}% (target: <70%)`, + '', + ] + reportLines.push(...section) + + console.log('\n=== COMBO SNOWBALL ANALYSIS ===') + section.forEach(l => console.log(` ${l}`)) + + // Soft assertion + expect(true).toBe(true) + }) + it('writes scoring analysis reports', () => { const __filename = fileURLToPath(import.meta.url) const projectRoot = resolve(dirname(__filename), '..', '..', '..')