From 8452bdae73ed53ad77de44f85046700cb7b7e6e2 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Sat, 21 Mar 2026 00:34:32 -0700 Subject: [PATCH] player win/loss streaks --- static/css/style.css | 4 ++ stats.py | 79 ++++++++++++++++++++++++++++++ templates/player_detail.html | 94 +++++++++++++++++++++++++++++++++++- 3 files changed, 176 insertions(+), 1 deletion(-) diff --git a/static/css/style.css b/static/css/style.css index 1d4d563..1a9470b 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -828,6 +828,10 @@ td a:hover { background: rgba(255, 255, 255, 0.07); } +.chart-frame-small { + min-height: 260px; +} + @media (max-width: 980px) { .site-shell { width: min(100% - 24px, 100%); diff --git a/stats.py b/stats.py index 5d18234..9092688 100644 --- a/stats.py +++ b/stats.py @@ -76,6 +76,14 @@ class PlayerStats: total_cash_out_cents: int total_net_cents: int roi_pct: float + current_win_streak: int + current_loss_streak: int + longest_win_streak: int + longest_loss_streak: int + best_session_date: str | None + best_session_net_cents: int + worst_session_date: str | None + worst_session_net_cents: int rank_change: int = 0 @@ -189,6 +197,68 @@ def build_session_summaries(events: list[EventRow]) -> list[SessionSummary]: return sessions +def summarize_player_runs(entries: list[SessionEntry]) -> dict[str, int | str | None]: + ordered_entries = sorted(entries, key=lambda entry: entry.session_date) + + longest_win_streak = 0 + longest_loss_streak = 0 + current_run_wins = 0 + current_run_losses = 0 + + best_entry: SessionEntry | None = None + worst_entry: SessionEntry | None = None + + for entry in ordered_entries: + net = entry.net_cents + + if best_entry is None or net > best_entry.net_cents: + best_entry = entry + + if worst_entry is None or net < worst_entry.net_cents: + worst_entry = entry + + if net > 0: + current_run_wins += 1 + current_run_losses = 0 + elif net < 0: + current_run_losses += 1 + current_run_wins = 0 + else: + current_run_wins = 0 + current_run_losses = 0 + + longest_win_streak = max(longest_win_streak, current_run_wins) + longest_loss_streak = max(longest_loss_streak, current_run_losses) + + current_win_streak = 0 + current_loss_streak = 0 + + for entry in reversed(ordered_entries): + net = entry.net_cents + + if net > 0: + if current_loss_streak > 0: + break + current_win_streak += 1 + elif net < 0: + if current_win_streak > 0: + break + current_loss_streak += 1 + else: + break + + return { + "current_win_streak": current_win_streak, + "current_loss_streak": current_loss_streak, + "longest_win_streak": longest_win_streak, + "longest_loss_streak": longest_loss_streak, + "best_session_date": best_entry.session_date if best_entry else None, + "best_session_net_cents": best_entry.net_cents if best_entry else 0, + "worst_session_date": worst_entry.session_date if worst_entry else None, + "worst_session_net_cents": worst_entry.net_cents if worst_entry else 0, + } + + def build_leaderboard(sessions: list[SessionSummary]) -> list[PlayerStats]: player_entries: dict[str, list[SessionEntry]] = defaultdict(list) for session in sessions: @@ -198,6 +268,7 @@ def build_leaderboard(sessions: list[SessionSummary]) -> list[PlayerStats]: leaderboard: list[PlayerStats] = [] for player_name, entries in player_entries.items(): nets = [entry.net_cents for entry in entries] + run_summary = summarize_player_runs(entries) wins = [value for value in nets if value > 0] losses = [value for value in nets if value < 0] total_buy_in = sum(entry.buy_in_cents for entry in entries) @@ -232,6 +303,14 @@ def build_leaderboard(sessions: list[SessionSummary]) -> list[PlayerStats]: total_cash_out_cents=total_cash_out, total_net_cents=total_net, roi_pct=roi_pct, + current_win_streak=run_summary["current_win_streak"], + current_loss_streak=run_summary["current_loss_streak"], + longest_win_streak=run_summary["longest_win_streak"], + longest_loss_streak=run_summary["longest_loss_streak"], + best_session_date=run_summary["best_session_date"], + best_session_net_cents=run_summary["best_session_net_cents"], + worst_session_date=run_summary["worst_session_date"], + worst_session_net_cents=run_summary["worst_session_net_cents"], ) ) diff --git a/templates/player_detail.html b/templates/player_detail.html index 2dc144e..18fad5c 100644 --- a/templates/player_detail.html +++ b/templates/player_detail.html @@ -16,9 +16,24 @@
Buy-ins{{ player.total_buy_in_cents | money }}
Cash-outs{{ player.total_cash_out_cents | money }}
Sessions{{ player.sessions_played }}
+
+ Current Streak + + {% if player.current_win_streak > 0 %} + W{{ player.current_win_streak }} + {% elif player.current_loss_streak > 0 %} + L{{ player.current_loss_streak }} + {% else %} + - + {% endif %} + +
+ +
Longest win streak{{ player.longest_win_streak }}
+
Longest loss streak{{ player.longest_loss_streak }}
-
+
@@ -30,6 +45,9 @@
+
+ +
@@ -41,6 +59,17 @@
+
+
+
+

Breakdown

+

Result mix

+
+
+
+ +
+
@@ -60,6 +89,28 @@ Average Loss{{ player.avg_loss_cents | money }} Biggest Win{{ player.biggest_win_cents | money }} Biggest Loss{{ player.biggest_loss_cents | money }} + Current Win Streak{{ player.current_win_streak }} + Current Loss Streak{{ player.current_loss_streak }} + Longest Win Streak{{ player.longest_win_streak }} + Longest Loss Streak{{ player.longest_loss_streak }} + + Best Session + + {{ player.best_session_net_cents | money }} + {% if player.best_session_date %} + on {{ player.best_session_date | pretty_date }} + {% endif %} + + + + Worst Session + + {{ player.worst_session_net_cents | money }} + {% if player.worst_session_date %} + on {{ player.worst_session_date | pretty_date }} + {% endif %} + + @@ -138,4 +189,45 @@ }); } + + {% endblock %}