Polish MLS simulator: configNumber zero, logger warning, Map lookup
Three small fixes from secondary code review: 1. configNumber: allow value >= 0 (not just > 0) so admins can legitimately set baseDrawRate or drawDecay to 0 without the value being silently discarded and replaced with the default. 2. Add logger.warn when a participant is excluded from simulation due to a missing Elo rating, matching the NLL bracket-aware pattern. Gives admins a visible signal instead of a silent exclusion. 3. getBySeeds: build a Map once instead of calling Array.find() per seed. Eliminates 4M linear scans across 50k iterations for a 9- element array — trivially fast either way, but Map is the right tool. https://claude.ai/code/session_015wkBJ3SYGcMGjsddKKGkwa
This commit is contained in:
parent
43c9128e59
commit
8a0103e4c4
1 changed files with 11 additions and 3 deletions
|
|
@ -46,6 +46,7 @@ import { getParticipantSimulatorInputs, getSportsSeasonSimulatorConfig } from "~
|
||||||
import { simulateEloSoccerMatch, simulateSimpleSoccerGoals } from "./soccer-helpers";
|
import { simulateEloSoccerMatch, simulateSimpleSoccerGoals } from "./soccer-helpers";
|
||||||
import type { EloSoccerMatchOptions } from "./soccer-helpers";
|
import type { EloSoccerMatchOptions } from "./soccer-helpers";
|
||||||
import { normalizeSimulationResultColumns } from "./simulation-probabilities";
|
import { normalizeSimulationResultColumns } from "./simulation-probabilities";
|
||||||
|
import { logger } from "~/lib/logger";
|
||||||
|
|
||||||
// ─── Default constants (overridable via season simulator config) ───────────────
|
// ─── Default constants (overridable via season simulator config) ───────────────
|
||||||
|
|
||||||
|
|
@ -62,7 +63,7 @@ const MLS_PLAYOFF_TEAMS_PER_CONF = 9;
|
||||||
|
|
||||||
function configNumber(config: Record<string, unknown> | undefined, key: string, fallback: number): number {
|
function configNumber(config: Record<string, unknown> | undefined, key: string, fallback: number): number {
|
||||||
const value = config?.[key];
|
const value = config?.[key];
|
||||||
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Public types ─────────────────────────────────────────────────────────────
|
// ─── Public types ─────────────────────────────────────────────────────────────
|
||||||
|
|
@ -205,8 +206,9 @@ function getBySeeds(
|
||||||
seeds: MlsConferenceSeed[],
|
seeds: MlsConferenceSeed[],
|
||||||
...seedNums: number[]
|
...seedNums: number[]
|
||||||
): MlsConferenceSeed[] {
|
): MlsConferenceSeed[] {
|
||||||
|
const byNum = new Map(seeds.map((s) => [s.seed, s]));
|
||||||
return seedNums.map((n) => {
|
return seedNums.map((n) => {
|
||||||
const entry = seeds.find((s) => s.seed === n);
|
const entry = byNum.get(n);
|
||||||
if (!entry) throw new Error(`MLS playoff seed ${n} not found in conference bracket.`);
|
if (!entry) throw new Error(`MLS playoff seed ${n} not found in conference bracket.`);
|
||||||
return entry;
|
return entry;
|
||||||
});
|
});
|
||||||
|
|
@ -397,7 +399,13 @@ export class MLSSimulator implements Simulator {
|
||||||
const teamsWithElo = participants.flatMap((p): MlsTeamEntry[] => {
|
const teamsWithElo = participants.flatMap((p): MlsTeamEntry[] => {
|
||||||
const elo = eloMap.get(p.id);
|
const elo = eloMap.get(p.id);
|
||||||
const conf = conferenceMap.get(p.id);
|
const conf = conferenceMap.get(p.id);
|
||||||
if (elo === undefined || conf === undefined) return [];
|
if (elo === undefined || conf === undefined) {
|
||||||
|
logger.warn(
|
||||||
|
`MLSSimulator: no Elo rating for participant "${p.name}" (${p.id}). ` +
|
||||||
|
`They will be excluded from simulation. Enter sourceElo or projectedTablePoints via Admin → Elo Ratings.`
|
||||||
|
);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const standing = standingsMap.get(p.id);
|
const standing = standingsMap.get(p.id);
|
||||||
const wins = standing?.wins ?? 0;
|
const wins = standing?.wins ?? 0;
|
||||||
const draws = standing?.ties ?? 0;
|
const draws = standing?.ties ?? 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue