/** * scripts/verify-challenger-elite-stats.ts * * Empirical Challenger Verification Suite for Diablo II v1.13c Elite Monster Generation. * * Objective: * 1. Monte Carlo simulation (>= 10,000 trials) testing `planMonsterGroups` for elite selection: * - Champion ratio convergence to 20% within 3-sigma confidence interval. * - Unique ratio convergence to 80% within 3-sigma confidence interval. * - Minion counts for Uniques strictly bounded in [3, 6]. * - Champion pack sizes strictly bounded in [2, 4]. * - HP multipliers: Champions 3x, Boss 4x, Minions 2x. */ import * as fs from 'fs' import { MountedArchives } from '../src/mpq/mount.ts' import { MpqArchive } from '../src/mpq/archive.ts' import { fileSource } from '../src/mpq/file-source.ts' import { loadActTables } from '../src/game/acts.ts' import { readLevelMonsterPlan, readMonsterKinds, selectLevelTypes, planMonsterGroups, planLevelMonsters, ELITE_HEALTH_MULTIPLIER, MONUMOD_CONSTANTS, type MonsterKind, } from '../src/game/monsters.ts' import { Rng } from '../src/game/rng.ts' export interface MonteCarloReport { readonly trials: number readonly totalEliteGroups: number readonly championGroups: number readonly uniqueGroups: number readonly championRatio: number readonly uniqueRatio: number readonly threeSigmaMargin: number readonly championRatioWithin3Sigma: boolean readonly uniqueRatioWithin3Sigma: boolean readonly championPackSizeMin: number readonly championPackSizeMax: number readonly championPackSizeValid: boolean readonly championPackSizeHistogram: Record readonly uniqueMinionCountMin: number readonly uniqueMinionCountMax: number readonly uniqueMinionCountValid: boolean readonly uniqueMinionCountHistogram: Record readonly hpMultipliersValid: boolean readonly hpMultipliers: { champion: number uniqueBoss: number minion: number } } export async function runEliteMonteCarloSimulation(trials = 10000): Promise { const dir = fs.existsSync('samples/d2/Patch_D2.mpq') ? 'samples/d2' : (fs.existsSync('/usr/local/google/home/taodao/d2-data/Patch_D2.mpq') ? '/usr/local/google/home/taodao/d2-data' : 'samples/d2') const archives = new MountedArchives() for (const name of ['d2data.mpq', 'd2exp.mpq', 'Patch_D2.mpq']) { archives.add(name, await MpqArchive.open(await fileSource(`${dir}/${name}`))) } const tables = await loadActTables(archives) const kinds = readMonsterKinds(tables.monstats) const plan = readLevelMonsterPlan(tables.levels, 3, 'nightmare')! const types = selectLevelTypes(plan, kinds, new Rng(1), 'nightmare') let totalEliteGroups = 0 let championGroups = 0 let uniqueGroups = 0 let minChampPackSize = Infinity let maxChampPackSize = -Infinity const champPackSizes = new Map() let minUniqueMinionCount = Infinity let maxUniqueMinionCount = -Infinity const uniqueMinionCounts = new Map() for (let trial = 0; trial < trials; trial++) { const rng = new Rng(200000 + trial) // Budget 200 ensures packs are not artificially truncated by remaining budget const groups = planMonsterGroups(plan, types, kinds, 200, rng) for (const g of groups) { if (g.rank === 'champion') { championGroups++ totalEliteGroups++ minChampPackSize = Math.min(minChampPackSize, g.count) maxChampPackSize = Math.max(maxChampPackSize, g.count) champPackSizes.set(g.count, (champPackSizes.get(g.count) || 0) + 1) } else if (g.rank === 'unique') { uniqueGroups++ totalEliteGroups++ const minions = g.count - 1 minUniqueMinionCount = Math.min(minUniqueMinionCount, minions) maxUniqueMinionCount = Math.max(maxUniqueMinionCount, minions) uniqueMinionCounts.set(minions, (uniqueMinionCounts.get(minions) || 0) + 1) } } } const championRatio = championGroups / totalEliteGroups const uniqueRatio = uniqueGroups / totalEliteGroups const threeSigmaMargin = 3 * Math.sqrt((0.20 * 0.80) / totalEliteGroups) const championRatioWithin3Sigma = Math.abs(championRatio - 0.20) <= threeSigmaMargin const uniqueRatioWithin3Sigma = Math.abs(uniqueRatio - 0.80) <= threeSigmaMargin const championPackSizeValid = minChampPackSize >= 2 && maxChampPackSize <= 4 const uniqueMinionCountValid = minUniqueMinionCount >= 3 && maxUniqueMinionCount <= 6 const championHp = ELITE_HEALTH_MULTIPLIER.champion const uniqueHp = ELITE_HEALTH_MULTIPLIER.unique const minionHp = 1 + (MONUMOD_CONSTANTS.minionHpPct / 100) const hpMultipliersValid = championHp === 3 && uniqueHp === 4 && minionHp === 2 return { trials, totalEliteGroups, championGroups, uniqueGroups, championRatio, uniqueRatio, threeSigmaMargin, championRatioWithin3Sigma, uniqueRatioWithin3Sigma, championPackSizeMin: minChampPackSize, championPackSizeMax: maxChampPackSize, championPackSizeValid, championPackSizeHistogram: Object.fromEntries(champPackSizes), uniqueMinionCountMin: minUniqueMinionCount, uniqueMinionCountMax: maxUniqueMinionCount, uniqueMinionCountValid, uniqueMinionCountHistogram: Object.fromEntries(uniqueMinionCounts), hpMultipliersValid, hpMultipliers: { champion: championHp, uniqueBoss: uniqueHp, minion: minionHp, }, } } async function main() { console.log('======================================================================') console.log('🔬 EMPIRICAL CHALLENGER MONTE CARLO TEST: ELITE STATISTICAL PROPERTIES') console.log('======================================================================') const report = await runEliteMonteCarloSimulation(10000) console.log(`\nTrials Run: ${report.trials}`) console.log(`Total Elite Groups Sampled: ${report.totalEliteGroups}`) console.log(`Champion Groups: ${report.championGroups}`) console.log(`Unique Groups: ${report.uniqueGroups}`) console.log('\n--- Criterion 1 & 2: Statistical Convergence (3-Sigma) ---') console.log(`Observed Champion Ratio: ${(report.championRatio * 100).toFixed(3)}% (Target: 20.000%)`) console.log(`3-Sigma Confidence Interval: [${((0.20 - report.threeSigmaMargin) * 100).toFixed(3)}%, ${((0.20 + report.threeSigmaMargin) * 100).toFixed(3)}%]`) console.log(`Champion Ratio within 3-Sigma: ${report.championRatioWithin3Sigma ? '✅ PASS' : '❌ FAIL'}`) console.log(`\nObserved Unique Ratio: ${(report.uniqueRatio * 100).toFixed(3)}% (Target: 80.000%)`) console.log(`3-Sigma Confidence Interval: [${((0.80 - report.threeSigmaMargin) * 100).toFixed(3)}%, ${((0.80 + report.threeSigmaMargin) * 100).toFixed(3)}%]`) console.log(`Unique Ratio within 3-Sigma: ${report.uniqueRatioWithin3Sigma ? '✅ PASS' : '❌ FAIL'}`) console.log('\n--- Criterion 3: Minion Counts for Uniques strictly bounded in [3, 6] ---') console.log(`Observed Minion Range: [${report.uniqueMinionCountMin}, ${report.uniqueMinionCountMax}]`) console.log(`Histogram (minion count: occurrences):`, report.uniqueMinionCountHistogram) console.log(`Strictly Bounded in [3, 6]: ${report.uniqueMinionCountValid ? '✅ PASS' : '❌ FAIL'}`) console.log('\n--- Criterion 4: Champion Pack Sizes strictly bounded in [2, 4] ---') console.log(`Observed Champion Pack Size Range: [${report.championPackSizeMin}, ${report.championPackSizeMax}]`) console.log(`Histogram (pack size: occurrences):`, report.championPackSizeHistogram) console.log(`Strictly Bounded in [2, 4]: ${report.championPackSizeValid ? '✅ PASS' : '❌ FAIL'}`) console.log('\n--- Criterion 5: HP Multipliers (Champions 3x, Boss 4x, Minions 2x) ---') console.log(`Champion HP Multiplier: ${report.hpMultipliers.champion}x (Expected: 3x)`) console.log(`Unique Boss HP Multiplier: ${report.hpMultipliers.uniqueBoss}x (Expected: 4x)`) console.log(`Minion HP Multiplier: ${report.hpMultipliers.minion}x (Expected: 2x)`) console.log(`HP Multipliers Valid: ${report.hpMultipliersValid ? '✅ PASS' : '❌ FAIL'}`) console.log('\n======================================================================') const overallPass = report.championRatioWithin3Sigma && report.uniqueRatioWithin3Sigma && report.uniqueMinionCountValid && report.championPackSizeValid && report.hpMultipliersValid console.log(`FINAL EMPIRICAL VERDICT: ${overallPass ? 'APPROVE' : 'REQUEST_CHANGES'}`) console.log('======================================================================') if (!overallPass) { process.exit(1) } } if (import.meta.url === `file://${process.argv[1]}`) { main().catch((err) => { console.error(err) process.exit(1) }) }