From b64a4ad2d0beb3867ba6755d14090002ee2cd51e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 7 May 2026 03:34:03 +0000 Subject: [PATCH] Add Neutral Zone Impact Score (NZIS) statistic NZIS quantifies a player's neutral zone effectiveness per game using takeaways, giveaways, hits, and face-off percentage. Also wires up the Flask stats page to fetch live player data and display all stats. https://claude.ai/code/session_01Vh4wiRVXFNMnhzdiv9iUVP --- src/mainApp.py | 27 ++++++++++++++-- src/player.py | 66 ++++++++++++++++++++++++++++------------ src/templates/Stats.html | 16 ++++++---- 3 files changed, 81 insertions(+), 28 deletions(-) diff --git a/src/mainApp.py b/src/mainApp.py index d3c2f72..349c933 100644 --- a/src/mainApp.py +++ b/src/mainApp.py @@ -1,4 +1,6 @@ from flask import Flask, request, render_template, redirect, url_for +from player import parsePlayer +from team import search_team, search_player, parse_teams, parse_roster app = Flask(__name__) @@ -11,7 +13,28 @@ def index(): @app.route("/stats///") def statsPage(team, player): - return player + " stats page" + parse_teams() + teamID = search_team(team) + if teamID == -1: + return "Team not found: " + team + parse_roster(teamID) + playerID = search_player(player) + if playerID == -1: + return "Player not found: " + player + p = parsePlayer(playerID) + if p is None: + return "Could not load stats for " + player + return render_template("Stats.html", + playerName=p.name, + gamesPlayed=p.gp, + goals=p.goals, + assists=p.assists, + points=p.points, + takeaways=p.takeaways, + giveaways=p.giveaways, + hits=p.hits, + faceOffPct=p.faceOffPct, + nzis=p.nzis) if __name__ == "__main__": - app.run() \ No newline at end of file + app.run() diff --git a/src/player.py b/src/player.py index eb5afd9..ab35fcf 100644 --- a/src/player.py +++ b/src/player.py @@ -8,21 +8,43 @@ class Player(object): goals = 0 assists = 0 points = 0 + takeaways = 0 + giveaways = 0 + hits = 0 + faceOffPct = 0.0 + nzis = 0.0 - # The class "constructor" - It's actually an initializer - def __init__(self, name, gp, goals, assists, points): + def __init__(self, name, gp, goals, assists, points, takeaways, giveaways, hits, faceOffPct): self.name = name self.gp = gp self.goals = goals self.assists = assists self.points = points + self.takeaways = takeaways + self.giveaways = giveaways + self.hits = hits + self.faceOffPct = faceOffPct + self.nzis = self._calculate_nzis() - def printPlayer(self): - print("Name: " + self.name + "\n Games Played: " + str(self.gp) + "\n Goals: " + str(self.goals) + "\n Assists: " + str(self.assists) + "\n Total Points: " + str(self.points)) + def _calculate_nzis(self): + if self.gp == 0: + return 0.0 + per_game = (self.takeaways - self.giveaways + self.hits * 0.25) / self.gp + # Face-off adjustment only applies when a player actually takes face-offs + faceoff_adj = (self.faceOffPct - 50.0) / 100.0 if self.faceOffPct > 0 else 0.0 + return round(per_game + faceoff_adj, 2) -def make_player(name, gp, g, a, p): - player = Player(name,gp,g,a,p) - return player + def printPlayer(self): + print("Name: " + self.name + + "\n Games Played: " + str(self.gp) + + "\n Goals: " + str(self.goals) + + "\n Assists: " + str(self.assists) + + "\n Total Points: " + str(self.points) + + "\n Takeaways: " + str(self.takeaways) + + "\n Giveaways: " + str(self.giveaways) + + "\n Hits: " + str(self.hits) + + "\n Face-off %: " + str(self.faceOffPct) + + "\n NZIS: " + str(self.nzis)) def getFeed(url): request = urllib.request.Request(url) @@ -31,24 +53,28 @@ def getFeed(url): def parsePlayer(playerID): try: - root = getFeed("https://statsapi.web.nhl.com/api/v1/people/" + str(playerID) +"?hydrate=stats(splits=statsSingleSeason)") + root = getFeed("https://statsapi.web.nhl.com/api/v1/people/" + str(playerID) + "?hydrate=stats(splits=statsSingleSeason)") except Exception as e: print("Failed to find player") - print("Exception: " + e) - #gathering data to make Player object + print("Exception: " + str(e)) + return None + stat = root["people"][0]["stats"][0]["splits"][0]["stat"] playerName = root["people"][0]["fullName"] - gamesPlayed = root["people"][0]["stats"][0]["splits"][0]["stat"]["games"] - playerGoals = root["people"][0]["stats"][0]["splits"][0]["stat"]["goals"] - playerAssists = root["people"][0]["stats"][0]["splits"][0]["stat"]["assists"] - playerPoints = root["people"][0]["stats"][0]["splits"][0]["stat"]["points"] - newPlayer = make_player(playerName,gamesPlayed,playerGoals,playerAssists,playerPoints) - return newPlayer + gamesPlayed = stat["games"] + playerGoals = stat["goals"] + playerAssists = stat["assists"] + playerPoints = stat["points"] + takeaways = stat.get("takeaways", 0) + giveaways = stat.get("giveaways", 0) + hits = stat.get("hits", 0) + faceOffPct = stat.get("faceOffPct", 0.0) + return Player(playerName, gamesPlayed, playerGoals, playerAssists, playerPoints, + takeaways, giveaways, hits, faceOffPct) def main(): - #currently is Sidney Crosby's stats - parsePlayer(8471675) - - + player = parsePlayer(8471675) + if player: + player.printPlayer() if __name__ == '__main__': main() diff --git a/src/templates/Stats.html b/src/templates/Stats.html index d1a6f8e..d3a06d7 100644 --- a/src/templates/Stats.html +++ b/src/templates/Stats.html @@ -4,12 +4,16 @@ {{ playerName }}'s Statistics - {{ playerName }}'s statistics for 2019-2020 -

Name: {{ playerName }}

-

Games: {{ gamesPlayed }}

+

{{ playerName }}'s Statistics

+

Games Played: {{ gamesPlayed }}

Goals: {{ goals }}

Assists: {{ assists }}

-

Points: {{ points }}

- +

Points: {{ points }}

+
+

Neutral Zone Impact Score (NZIS): {{ nzis }}

+

Takeaways: {{ takeaways }}

+

Giveaways: {{ giveaways }}

+

Hits: {{ hits }}

+

Face-off %: {{ faceOffPct }}

- \ No newline at end of file +