diff --git a/app/database.py b/app/database.py index 00559c1..63c4ba9 100644 --- a/app/database.py +++ b/app/database.py @@ -126,6 +126,7 @@ async def init_db(): "ALTER TABLE magic_link_tokens ADD COLUMN code TEXT", "ALTER TABLE games ADD COLUMN skin_value REAL", "ALTER TABLE games ADD COLUMN skin_double_back_nine INTEGER NOT NULL DEFAULT 0", + "ALTER TABLE games ADD COLUMN skins_net INTEGER NOT NULL DEFAULT 0", ]: try: await db.execute(migration) diff --git a/app/routers/games.py b/app/routers/games.py index c4b2977..07e5fa7 100644 --- a/app/routers/games.py +++ b/app/routers/games.py @@ -90,16 +90,22 @@ def _strokes_per_hole(players: list, holes: list, hole_stroke_indices: dict) -> def _calc_skins(players: list, scores: dict, holes: list, carryover: bool = True, - skin_value: float | None = None, skin_double_back9: bool = False): + skin_value: float | None = None, skin_double_back9: bool = False, + strokes_per_hole: dict | None = None): """Returns (skins_per_player, hole_results, unclaimed_pot, money_per_player, unclaimed_money) - money_per_player is None when skin_value is not set.""" + money_per_player is None when skin_value is not set. + strokes_per_hole is {uid: {hole: strokes}} for net scoring.""" skins = {p["id"]: 0 for p in players} money = {p["id"]: 0.0 for p in players} hole_results = {} pot = 0 money_pot = 0.0 for hole in holes: - scored = {uid: s["strokes"] for uid, s in scores.get(hole, {}).items() if s.get("strokes")} + raw = {uid: s["strokes"] for uid, s in scores.get(hole, {}).items() if s.get("strokes")} + if strokes_per_hole: + scored = {uid: g - (strokes_per_hole.get(uid) or {}).get(hole, 0) for uid, g in raw.items()} + else: + scored = raw if not scored: continue pot += 1 @@ -277,10 +283,11 @@ async def create_game(request: Request, holes_count: int = Form(...), skin_value_str = (form.get("skin_value") or "").strip() skin_value = float(skin_value_str) if skin_value_str else None skin_double_back_nine = 1 if form.get("skin_double_back_nine") == "1" else 0 + skins_net = 1 if form.get("skins_net") == "1" else 0 await db.execute( - "INSERT INTO games (id, format, holes_count, status, created_by, created_at, course_id, carryover, skin_value, skin_double_back_nine) VALUES (?,?,?,?,?,?,?,?,?,?)", - (game_id, format, holes_count, "active", user["id"], now, course_id, carryover, skin_value, skin_double_back_nine), + "INSERT INTO games (id, format, holes_count, status, created_by, created_at, course_id, carryover, skin_value, skin_double_back_nine, skins_net) VALUES (?,?,?,?,?,?,?,?,?,?,?)", + (game_id, format, holes_count, "active", user["id"], now, course_id, carryover, skin_value, skin_double_back_nine, skins_net), ) # Pre-fetch course holes for handicap calculation @@ -378,10 +385,12 @@ async def game_summary(game_id: str, request: Request, user: dict = Depends(get_ skins_won, skins_hole_results, unclaimed, money_won, unclaimed_money = None, None, 0, None, 0.0 skin_value = game["skin_value"] skin_double_back9 = bool(game["skin_double_back_nine"]) + skins_net = bool(game["skins_net"]) if game["format"] == "skins": carryover = bool(game["carryover"]) + net_sph = strokes_per_hole if skins_net else None skins_won, skins_hole_results, unclaimed, money_won, unclaimed_money = _calc_skins( - players, scores, holes, carryover, skin_value, skin_double_back9) + players, scores, holes, carryover, skin_value, skin_double_back9, net_sph) results = sorted(players, key=lambda p: skins_won.get(p["id"], 0), reverse=True) else: results = sorted(players, key=lambda p: totals.get(p["id"], {}).get("total", 0), reverse=True) @@ -395,7 +404,7 @@ async def game_summary(game_id: str, request: Request, user: dict = Depends(get_ "results": results, "skins_won": skins_won, "skins_hole_results": skins_hole_results, "unclaimed": unclaimed, "money_won": money_won, "unclaimed_money": unclaimed_money, "skin_value": skin_value, - "skin_double_back9": skin_double_back9, + "skin_double_back9": skin_double_back9, "skins_net": skins_net, "carryover": bool(game["carryover"]), }) @@ -436,6 +445,7 @@ async def game_page(game_id: str, request: Request, user: dict = Depends(get_cur "carryover": bool(game["carryover"]), "skin_value": game["skin_value"], "skin_double_back9": bool(game["skin_double_back_nine"]), + "skins_net": bool(game["skins_net"]), }) diff --git a/app/templates/games/game.html b/app/templates/games/game.html index c03fb7e..c19b813 100644 --- a/app/templates/games/game.html +++ b/app/templates/games/game.html @@ -280,6 +280,7 @@ const GAME_FORMAT = "{{ game.format }}"; const SKINS_CARRYOVER = {{ carryover | tojson }}; const SKIN_VALUE = {{ skin_value | tojson }}; const SKIN_DOUBLE_BACK9 = {{ skin_double_back9 | tojson }}; +const SKINS_NET = {{ skins_net | tojson }}; const HOLE_PARS = {{ hole_pars | tojson }}; const HOLE_SIS = {{ hole_stroke_indices | tojson }}; const STROKES_PER_HOLE = {{ strokes_per_hole | tojson }}; @@ -494,8 +495,12 @@ function gameApp() { if (this.isSkipped(hole)) continue; const holeScores = this.scores[hole] || {}; const scored = PLAYERS_DATA - .map(p => ({ id: p.id, strokes: holeScores[p.id]?.strokes || 0 })) - .filter(x => x.strokes > 0); + .map(p => { + const gross = holeScores[p.id]?.strokes || 0; + const net = SKINS_NET ? gross - ((STROKES_PER_HOLE[p.id] || {})[hole] || 0) : gross; + return { id: p.id, strokes: net, gross }; + }) + .filter(x => x.gross > 0); if (scored.length === 0) continue; pot += 1; if (SKIN_VALUE) moneyPot += SKIN_VALUE * (SKIN_DOUBLE_BACK9 && hole >= 10 ? 2 : 1); diff --git a/app/templates/games/new_game.html b/app/templates/games/new_game.html index 33e4001..a9de23b 100644 --- a/app/templates/games/new_game.html +++ b/app/templates/games/new_game.html @@ -30,6 +30,7 @@ carryoverEnabled: true, skinValue: '', skinDoubleBackNine: false, + skinsNet: false, holesCount: '', selectedPlayers: ['{{ user.id }}'], selectedTees: {}, @@ -104,6 +105,19 @@
+ +
+ + +
+
+ Scoring + +
Carryover diff --git a/app/templates/games/summary.html b/app/templates/games/summary.html index 5cc13ad..f7d79f8 100644 --- a/app/templates/games/summary.html +++ b/app/templates/games/summary.html @@ -7,7 +7,7 @@ ← Back
{{ game.course_name or 'Bingo Bango Bongo' }}
-
{{ game.holes_count }} holes · {{ game.created_at[:10] }}
+
{{ game.holes_count }} holes · {{ game.created_at[:10] }}{% if game.format == 'skins' and skins_net %} · net{% endif %}