118 lines
3.1 KiB
TypeScript
118 lines
3.1 KiB
TypeScript
import type { PlayerStatsInput } from "@/lib/types";
|
|
|
|
type StatValue = number | null | undefined;
|
|
|
|
function stat(value: StatValue) {
|
|
return value ?? 0;
|
|
}
|
|
|
|
function hasValue(value: StatValue) {
|
|
return value !== null && value !== undefined;
|
|
}
|
|
|
|
function formatRate(value: number | null, digits = 3) {
|
|
if (value === null || Number.isNaN(value)) {
|
|
return null;
|
|
}
|
|
|
|
return value.toFixed(digits).replace(/^0(?=\.)/, "");
|
|
}
|
|
|
|
function formatDecimal(value: number | null, digits = 2) {
|
|
if (value === null || Number.isNaN(value)) {
|
|
return null;
|
|
}
|
|
|
|
return value.toFixed(digits);
|
|
}
|
|
|
|
export function formatInningsPitched(outs: StatValue) {
|
|
const totalOuts = stat(outs);
|
|
if (totalOuts <= 0) {
|
|
return null;
|
|
}
|
|
|
|
const wholeInnings = Math.floor(totalOuts / 3);
|
|
const remainder = totalOuts % 3;
|
|
return `${wholeInnings}.${remainder}`;
|
|
}
|
|
|
|
export function hasBattingStats(stats?: PlayerStatsInput | null) {
|
|
if (!stats) return false;
|
|
|
|
return [
|
|
stats.atBats,
|
|
stats.runs,
|
|
stats.hits,
|
|
stats.doubles,
|
|
stats.triples,
|
|
stats.homeRuns,
|
|
stats.runsBattedIn,
|
|
stats.walks,
|
|
stats.strikeouts,
|
|
stats.stolenBases
|
|
].some(hasValue);
|
|
}
|
|
|
|
export function hasPitchingStats(stats?: PlayerStatsInput | null) {
|
|
if (!stats) return false;
|
|
|
|
return [
|
|
stats.inningsPitchedOuts,
|
|
stats.earnedRunsAllowed,
|
|
stats.hitsAllowed,
|
|
stats.walksAllowed,
|
|
stats.strikeoutsPitched
|
|
].some(hasValue);
|
|
}
|
|
|
|
export function getBattingSummary(stats?: PlayerStatsInput | null) {
|
|
if (!hasBattingStats(stats)) {
|
|
return [];
|
|
}
|
|
|
|
const atBats = stat(stats?.atBats);
|
|
const hits = stat(stats?.hits);
|
|
const walks = stat(stats?.walks);
|
|
const doubles = stat(stats?.doubles);
|
|
const triples = stat(stats?.triples);
|
|
const homeRuns = stat(stats?.homeRuns);
|
|
const singles = Math.max(hits - doubles - triples - homeRuns, 0);
|
|
const totalBases = singles + doubles * 2 + triples * 3 + homeRuns * 4;
|
|
|
|
const average = atBats > 0 ? hits / atBats : null;
|
|
const onBase = atBats + walks > 0 ? (hits + walks) / (atBats + walks) : null;
|
|
const slugging = atBats > 0 ? totalBases / atBats : null;
|
|
const ops = onBase !== null || slugging !== null ? (onBase ?? 0) + (slugging ?? 0) : null;
|
|
|
|
return [
|
|
["AVG", formatRate(average)],
|
|
["OBP", formatRate(onBase)],
|
|
["SLG", formatRate(slugging)],
|
|
["OPS", formatRate(ops)]
|
|
] as const;
|
|
}
|
|
|
|
export function getPitchingSummary(stats?: PlayerStatsInput | null) {
|
|
if (!hasPitchingStats(stats)) {
|
|
return [];
|
|
}
|
|
|
|
const outs = stat(stats?.inningsPitchedOuts);
|
|
const innings = outs / 3;
|
|
const earnedRuns = stat(stats?.earnedRunsAllowed);
|
|
const hitsAllowed = stat(stats?.hitsAllowed);
|
|
const walksAllowed = stat(stats?.walksAllowed);
|
|
const strikeoutsPitched = stat(stats?.strikeoutsPitched);
|
|
|
|
const era = outs > 0 ? (earnedRuns * 27) / outs : null;
|
|
const whip = innings > 0 ? (hitsAllowed + walksAllowed) / innings : null;
|
|
|
|
return [
|
|
["IP", formatInningsPitched(outs)],
|
|
["ERA", formatDecimal(era)],
|
|
["WHIP", formatDecimal(whip)],
|
|
["K", strikeoutsPitched > 0 || hasValue(stats?.strikeoutsPitched) ? String(strikeoutsPitched) : null]
|
|
] as const;
|
|
}
|