import { NCAABasketballSimulator } from "./ncaa-basketball-simulator"; import type { Simulator, SimulationResult } from "./types"; const KENPOM_SCALE_FACTOR = 7.5; /** * NCAAM neutral-court win probability using a KenPom-like adjusted efficiency * margin. Ratings are season-scoped simulator inputs, not hardcoded data. */ export function kenpomWinProbability(netrtgA: number, netrtgB: number): number { return 1 / (1 + Math.exp(-(netrtgA - netrtgB) / KENPOM_SCALE_FACTOR)); } function optionalPositiveNumber(value: unknown, fallback: number): number { return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback; } function kenpomWinProbabilityWithScale(scaleFactor: number): (netrtgA: number, netrtgB: number) => number { return (netrtgA, netrtgB) => 1 / (1 + Math.exp(-(netrtgA - netrtgB) / scaleFactor)); } export class NCAAMSimulator implements Simulator { private readonly simulator = new NCAABasketballSimulator({ source: "ncaam_bracket_rating", missingRatingName: "KenPom-like rating", selectionRatingDivisor: 8, winProbability: kenpomWinProbability, getWinProbability: (config) => kenpomWinProbabilityWithScale(optionalPositiveNumber(config.ratingScaleFactor, KENPOM_SCALE_FACTOR)), }); simulate(sportsSeasonId: string): Promise { return this.simulator.simulate(sportsSeasonId); } }