File size: 2,579 Bytes
c6abe34 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import re
from typing import Tuple, Dict, List, Any
from app.models.stats import PlayerStatRow, TeamTotalsRow, TeamStatistics
def parse_made_attempted(value: str) -> Tuple[int, int]:
"""Parse a field like '5-10' or '5/10' into (made, attempted). Returns (0, 0) if invalid."""
if not value or not isinstance(value, str):
return 0, 0
match = re.search(r'(\d+)\s*[\-/\|]\s*(\d+)', value)
if match:
return int(match.group(1)), int(match.group(2))
return 0, 0
def validate_and_compute_totals(players: List[PlayerStatRow]) -> TeamTotalsRow:
"""Computes all FIBA-style totals from player rows."""
totals = TeamTotalsRow()
for p in players:
# Re-parse ratios if integer components are 0 but ratio strings exist
if p.fg and p.fg_m == 0 and p.fg_a == 0:
p.fg_m, p.fg_a = parse_made_attempted(p.fg)
if p.tp and p.tp_m == 0 and p.tp_a == 0:
p.tp_m, p.tp_a = parse_made_attempted(p.tp)
if p.thp and p.thp_m == 0 and p.thp_a == 0:
p.thp_m, p.thp_a = parse_made_attempted(p.thp)
if p.ft and p.ft_m == 0 and p.ft_a == 0:
p.ft_m, p.ft_a = parse_made_attempted(p.ft)
# Update percentages
p.fg_pct = round((p.fg_m / p.fg_a * 100), 1) if p.fg_a > 0 else 0.0
p.tp_pct = round((p.tp_m / p.tp_a * 100), 1) if p.tp_a > 0 else 0.0
p.thp_pct = round((p.thp_m / p.thp_a * 100), 1) if p.thp_a > 0 else 0.0
p.ft_pct = round((p.ft_m / p.ft_a * 100), 1) if p.ft_a > 0 else 0.0
# Aggregate
totals.pts += p.pts
totals.fg_m += p.fg_m
totals.fg_a += p.fg_a
totals.tp_m += p.tp_m
totals.tp_a += p.tp_a
totals.thp_m += p.thp_m
totals.thp_a += p.thp_a
totals.ft_m += p.ft_m
totals.ft_a += p.ft_a
totals.off += p.off
totals.def_reb += p.def_reb
totals.reb += p.reb
totals.ast += p.ast
totals.to_cnt += p.to_cnt
totals.stl += p.stl
totals.blk += p.blk
totals.pf += p.pf
totals.fls_on += p.fls_on
totals.index += (p.index or 0)
# Compute team percentages
totals.fg_pct = round((totals.fg_m / totals.fg_a * 100), 1) if totals.fg_a > 0 else 0.0
totals.tp_pct = round((totals.tp_m / totals.tp_a * 100), 1) if totals.tp_a > 0 else 0.0
totals.thp_pct = round((totals.thp_m / totals.thp_a * 100), 1) if totals.thp_a > 0 else 0.0
totals.ft_pct = round((totals.ft_m / totals.ft_a * 100), 1) if totals.ft_a > 0 else 0.0
return totals
|