feat: game importance factor in hype scoring
Adds calculate_game_importance() that boosts Priority for high-stakes regular-season matchups based on season progress (sharp ramp after game 55), playoff bubble proximity (wildcard rank ~17-19 = max relevance), and divisional/conference rivalry (1.4x/1.2x multipliers). Max bonus 150 pts applied to both LIVE and PRE games; playoff and FINAL games are unaffected. Extends standings schema with division, conference, games_played, and wildcard_sequence fields fetched from the NHL API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
84
app/games.py
84
app/games.py
@@ -52,7 +52,7 @@ def parse_games(scoreboard_data):
|
||||
"Intermission": game["clock"]["inIntermission"]
|
||||
if game_state == "LIVE"
|
||||
else "N/A",
|
||||
"Priority": calculate_game_priority(game) + get_comeback_bonus(game),
|
||||
"Priority": calculate_game_priority(game) + get_comeback_bonus(game) + calculate_game_importance(game),
|
||||
"Start Time": get_start_time(game),
|
||||
"Home Record": format_record(game["homeTeam"]["record"])
|
||||
if game["gameState"] in ["PRE", "FUT"]
|
||||
@@ -290,20 +290,94 @@ def get_team_standings(team_name):
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT league_sequence, league_l10_sequence
|
||||
SELECT league_sequence, league_l10_sequence,
|
||||
division_abbrev, conference_abbrev,
|
||||
games_played, wildcard_sequence
|
||||
FROM standings
|
||||
WHERE team_common_name = ?
|
||||
""",
|
||||
""",
|
||||
(team_name,),
|
||||
)
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
if result:
|
||||
return {
|
||||
"league_sequence": result[0],
|
||||
"league_l10_sequence": result[1],
|
||||
"division_abbrev": result[2],
|
||||
"conference_abbrev": result[3],
|
||||
"games_played": result[4],
|
||||
"wildcard_sequence": result[5],
|
||||
}
|
||||
return {
|
||||
"league_sequence": result[0] if result else 0,
|
||||
"league_l10_sequence": result[1] if result else 0,
|
||||
"league_sequence": 0,
|
||||
"league_l10_sequence": 0,
|
||||
"division_abbrev": None,
|
||||
"conference_abbrev": None,
|
||||
"games_played": 0,
|
||||
"wildcard_sequence": 32,
|
||||
}
|
||||
|
||||
|
||||
def calculate_game_importance(game):
|
||||
# Playoff games already have elevated priorities; don't double-count
|
||||
if game.get("gameType", 2) != 2:
|
||||
return 0
|
||||
# FINAL/OFF games must sort below LIVE and PRE games
|
||||
if game["gameState"] in ("FINAL", "OFF"):
|
||||
return 0
|
||||
|
||||
home_st = get_team_standings(game["homeTeam"]["name"]["default"])
|
||||
away_st = get_team_standings(game["awayTeam"]["name"]["default"])
|
||||
|
||||
# Season weight — near-zero before game 30, sharp ramp 55-70, max at 82
|
||||
avg_gp = (home_st["games_played"] + away_st["games_played"]) / 2
|
||||
if avg_gp <= 30:
|
||||
season_weight = 0.05
|
||||
else:
|
||||
t = (avg_gp - 30) / (82 - 30)
|
||||
season_weight = min(t ** 1.8, 1.0)
|
||||
|
||||
# Playoff relevance — peaks for bubble teams (wildcard rank ~17-19)
|
||||
best_wc = min(home_st["wildcard_sequence"] or 32, away_st["wildcard_sequence"] or 32)
|
||||
if best_wc <= 12:
|
||||
playoff_relevance = 0.60
|
||||
elif best_wc <= 16:
|
||||
playoff_relevance = 0.85
|
||||
elif best_wc <= 19:
|
||||
playoff_relevance = 1.00
|
||||
elif best_wc <= 23:
|
||||
playoff_relevance = 0.65
|
||||
else:
|
||||
playoff_relevance = 0.15
|
||||
|
||||
# Division/conference rivalry multiplier
|
||||
home_div = home_st["division_abbrev"]
|
||||
away_div = away_st["division_abbrev"]
|
||||
home_conf = home_st["conference_abbrev"]
|
||||
away_conf = away_st["conference_abbrev"]
|
||||
if home_div and away_div and home_div == away_div:
|
||||
rivalry_multiplier = 1.4
|
||||
elif home_conf and away_conf and home_conf == away_conf:
|
||||
rivalry_multiplier = 1.2
|
||||
else:
|
||||
rivalry_multiplier = 1.0
|
||||
|
||||
raw = season_weight * playoff_relevance * rivalry_multiplier
|
||||
importance = int((raw / 1.4) * 150)
|
||||
|
||||
logger.debug(
|
||||
"importance components — season_weight: %.3f, playoff_relevance: %.2f, "
|
||||
"rivalry: %.1f, importance: %s",
|
||||
season_weight,
|
||||
playoff_relevance,
|
||||
rivalry_multiplier,
|
||||
importance,
|
||||
)
|
||||
|
||||
return max(0, min(importance, 150))
|
||||
|
||||
|
||||
def utc_to_eastern(utc_time):
|
||||
utc_datetime = datetime.strptime(utc_time, "%Y-%m-%dT%H:%M:%SZ")
|
||||
eastern_datetime = utc_datetime.replace(tzinfo=timezone.utc).astimezone(EASTERN)
|
||||
|
||||
Reference in New Issue
Block a user