Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@ After finishing, you land on the **"Ready to host"** screen: big Beatify wordmar
</div>

**Learn the Game in 20 Seconds**
Players who scan the QR code drop into a swipeable 4-card tour that teaches the core mechanics in order: guess the year, double-or-nothing bet, steal an answer, guess the artist. Skip/Next always visible, auto-advances after 4 seconds per card. By the time the host hits Start, everyone knows what to do.
Players who scan the QR code drop into a swipeable 4-card tour that teaches the core mechanics in order: guess the year, triple-or-nothing bet, steal an answer, guess the artist. Skip/Next always visible, auto-advances after 4 seconds per card. By the time the host hits Start, everyone knows what to do.

**The Rush**
A song starts playing. The clock is ticking. You *know* this song... but was it '85 or '87?

**The Strategy**
Answer fast for bonus points. Hit a streak for multipliers. Feeling confident? Bet double-or-nothing.
Answer fast for bonus points. Hit a streak for multipliers. Feeling confident? Bet triple-or-nothing.

**The Reveal**
The year drops. The room erupts. Someone nailed it. Someone was *way* off. Everyone's laughing.
Expand Down Expand Up @@ -234,10 +234,10 @@ Linear scale in between. Hesitation costs points.

Miss one? Streak resets. The pressure is real.

### Double or Nothing
### Triple or Nothing
Feeling confident? Toggle the bet before submitting.
Score points: **Double them.**
Score zero: **Lose it all.**
Nail the **exact** year: **triple your points.**
Miss it — even by a year: **score nothing that round.**

### Artist Challenge (Optional)
Know your artists? Enable this mode in game setup.
Expand Down
24 changes: 16 additions & 8 deletions custom_components/beatify/game/scoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
POINTS_EXACT = 10
POINTS_WRONG = 0

# A won bet (exact year) multiplies the round score by this (#1004).
BET_WIN_MULTIPLIER = 3


def calculate_accuracy_score(
guess: int,
Expand Down Expand Up @@ -136,18 +139,23 @@ def calculate_round_score(
def apply_bet_multiplier(
round_score: int,
bet: bool, # noqa: FBT001
is_exact: bool, # noqa: FBT001
) -> tuple[int, str | None]:
"""
Apply bet multiplier to round score (Story 5.3).
Apply bet multiplier to round score (Story 5.3, redesigned #1004).

Betting is double-or-nothing:
- If bet and scored points (>0): double the score, outcome="won"
- If bet and 0 points: score stays 0, outcome="lost"
- If no bet: score unchanged, outcome=None
Betting is a real "exact or nothing" gamble:
- If bet and the guess is the EXACT year: round_score x BET_WIN_MULTIPLIER,
outcome="won".
- If bet and the guess is not exact: score becomes 0, outcome="lost" —
the player forfeits the points a close guess would otherwise have
earned. That forfeit is the stake that makes the bet a real risk.
- If no bet: score unchanged, outcome=None.

Args:
round_score: Points earned before bet (accuracy x speed)
bet: Whether player placed a bet
is_exact: Whether the guess matched the correct year exactly

Returns:
Tuple of (final_score, bet_outcome)
Expand All @@ -157,8 +165,8 @@ def apply_bet_multiplier(
if not bet:
return round_score, None

if round_score > 0:
return round_score * 2, "won"
if is_exact:
return round_score * BET_WIN_MULTIPLIER, "won"
return 0, "lost"


Expand Down Expand Up @@ -599,7 +607,7 @@ def score_player_round(
player.years_off = abs(player.current_guess - correct_year)
player.missed_round = False
player.round_score, player.bet_outcome = apply_bet_multiplier(
speed_score, player.bet
speed_score, player.bet, player.years_off == 0
)
Comment on lines 609 to 611

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The new "exact or nothing" betting logic introduces a bug where a player's streak is not reset when they lose a bet on a "close" guess.

In the previous implementation, a bet only resulted in a "lost" outcome if the base score was already 0. Now, a bet can be lost even if the guess was within the scoring range (i.e., speed_score > 0).

Because _apply_streak (on line 613) is called with speed_score instead of the final player.round_score, the streak will incorrectly increment and potentially award a streak bonus despite the player scoring 0 for the round. Updating speed_score to match the post-bet round_score ensures that any round resulting in 0 points correctly resets the streak.

Suggested change
player.round_score, player.bet_outcome = apply_bet_multiplier(
speed_score, player.bet
speed_score, player.bet, player.years_off == 0
)
player.round_score, player.bet_outcome = apply_bet_multiplier(
speed_score, player.bet, player.years_off == 0
)
# Use post-bet score for streak calculation to ensure lost bets reset streaks
speed_score = player.round_score


_apply_streak(player, speed_score, streak_achievements)
Expand Down
18 changes: 9 additions & 9 deletions custom_components/beatify/www/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
"submittedCount": "{count}/{total} abgegeben",
"round": "Runde {current} von {total}",
"timeRemaining": "Noch {seconds}s",
"bet": "Alles oder Nichts",
"betShort": "×2",
"bet": "Dreifach oder nichts",
"betShort": "×3",
"betActive": "Wette aktiv!",
"noBonusThisRound": "Kein Bonus diese Runde — hau das Jahr rein",
"lockedIn": "Tipp abgegeben · warte auf andere",
Expand Down Expand Up @@ -156,7 +156,7 @@
"streakLost": "{count}er Serie verloren",
"baseScore": "Basispunkte",
"speedBonus": "Schnellbonus",
"betWon": "Wette gewonnen! 2x Punkte",
"betWon": "Wette gewonnen! 3x Punkte",
"betLost": "Wette verloren",
"noSubmission": "Kein Tipp abgegeben",
"allPlayers": "Alle Spieler",
Expand All @@ -180,7 +180,7 @@
"noGuess": "—"
},
"chip": {
"betWon": "Wette gewonnen · ×2",
"betWon": "Wette gewonnen · ×3",
"betLost": "Wette verloren",
"streakBonus": "{count}-Serie · +{bonus}"
},
Expand All @@ -192,7 +192,7 @@
"artistBonus": "Künstler-Challenge",
"movieBonus": "Film-Challenge",
"introBonus": "Intro-Speed-Bonus",
"betMultiplier": "Alles oder nichts",
"betMultiplier": "Dreifach oder nichts",
"betLost": "Wette verloren",
"total": "Gesamt diese Runde",
"noSubmission": "Keinen Tipp abgegeben"
Expand Down Expand Up @@ -620,11 +620,11 @@
"totalBets": "Wetten Gesamt",
"totalBetsDesc": "Platzierte Wetten",
"betsWon": "Gewonnene Wetten",
"betsWonDesc": "Doppelte Punkte!",
"betsWonDesc": "Dreifache Punkte!",
"winRate": "Gewinnrate",
"winRateDesc": "Erfolgsprozentsatz",
"noBettingData": "Noch keine Wettdaten",
"bettingHint": "Spieler koennen wetten, um ihre Punkte bei sicheren Schaetzungen zu verdoppeln",
"bettingHint": "Spieler koennen wetten, um ihre Punkte zu verdreifachen - es gewinnt aber nur das exakte Jahr",
"overview": "Übersicht",
"games": "Spiele",
"avgPlayersShort": "Ø Spieler",
Expand Down Expand Up @@ -926,8 +926,8 @@
"letsPlay": "Los geht's",
"yearTitle": "Rate das Jahr",
"yearCaption": "Näher = mehr Punkte",
"betTitle": "Alles oder nichts",
"betCaption": "Wette, dass du nah dran bist. Verdopple die Punkte.",
"betTitle": "Dreifach oder nichts",
"betCaption": "Wette auf das exakte Jahr. Dreifache Punkte.",
"stealTitle": "Antwort klauen",
"stealCaption": "Kopiere einen anderen Spieler. Einmal pro Spiel.",
"stealHint": "Nutz es, wenn du keine Ahnung hast.",
Expand Down
18 changes: 9 additions & 9 deletions custom_components/beatify/www/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
"submittedCount": "{count}/{total} submitted",
"round": "Round {current} of {total}",
"timeRemaining": "{seconds}s remaining",
"bet": "Double or Nothing",
"betShort": "×2",
"bet": "Triple or Nothing",
"betShort": "×3",
"betActive": "Bet Active!",
"noBonusThisRound": "No bonus this round — nail the year",
"lockedIn": "Locked in · waiting for others",
Expand Down Expand Up @@ -156,7 +156,7 @@
"streakLost": "Lost {count}-streak",
"baseScore": "Base score",
"speedBonus": "Speed bonus",
"betWon": "Bet won! 2x points",
"betWon": "Bet won! 3x points",
"betLost": "Bet lost",
"noSubmission": "No guess submitted",
"allPlayers": "All Players",
Expand All @@ -180,7 +180,7 @@
"noGuess": "—"
},
"chip": {
"betWon": "Bet won · ×2",
"betWon": "Bet won · ×3",
"betLost": "Bet lost",
"streakBonus": "{count}-streak · +{bonus}"
},
Expand All @@ -192,7 +192,7 @@
"artistBonus": "Artist challenge",
"movieBonus": "Movie challenge",
"introBonus": "Intro speed bonus",
"betMultiplier": "Double or Nothing",
"betMultiplier": "Triple or Nothing",
"betLost": "Bet lost",
"total": "Total this round",
"noSubmission": "No guess this round"
Expand Down Expand Up @@ -620,11 +620,11 @@
"totalBets": "Total Bets",
"totalBetsDesc": "Bets placed",
"betsWon": "Bets Won",
"betsWonDesc": "Double points!",
"betsWonDesc": "Triple points!",
"winRate": "Win Rate",
"winRateDesc": "Success percentage",
"noBettingData": "No betting data yet",
"bettingHint": "Players can bet to double their points on confident guesses",
"bettingHint": "Players can bet to triple their points — but only an exact-year guess wins",
"overview": "Overview",
"games": "Games",
"avgPlayersShort": "Avg Plrs",
Expand Down Expand Up @@ -926,8 +926,8 @@
"letsPlay": "Let's play",
"yearTitle": "Guess the year",
"yearCaption": "Closer = more points",
"betTitle": "Double or nothing",
"betCaption": "Bet you're close. Win double.",
"betTitle": "Triple or nothing",
"betCaption": "Nail the exact year. Win triple.",
"stealTitle": "Steal an answer",
"stealCaption": "Copy another player. Once per game.",
"stealHint": "Use it when you have no idea.",
Expand Down
18 changes: 9 additions & 9 deletions custom_components/beatify/www/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
"submittedCount": "{count}/{total} enviados",
"round": "Ronda {current} de {total}",
"timeRemaining": "{seconds}s restantes",
"bet": "Doble o nada",
"betShort": "×2",
"bet": "Triple o nada",
"betShort": "×3",
"noBonusThisRound": "Sin bonus esta ronda — acierta el año",
"lockedIn": "Bloqueado · esperando a los demás",
"lockedInWaitingCount": "Bloqueado · esperando a {count} más",
Expand Down Expand Up @@ -156,7 +156,7 @@
"streakLost": "Perdiste racha de {count}",
"baseScore": "Puntuacion base",
"speedBonus": "Bonus de velocidad",
"betWon": "Apuesta ganada! 2x puntos",
"betWon": "Apuesta ganada! 3x puntos",
"betLost": "Apuesta perdida",
"noSubmission": "No enviaste respuesta",
"allPlayers": "Todos los jugadores",
Expand All @@ -180,7 +180,7 @@
"noGuess": "—"
},
"chip": {
"betWon": "Apuesta ganada · ×2",
"betWon": "Apuesta ganada · ×3",
"betLost": "Apuesta perdida",
"streakBonus": "Racha de {count} · +{bonus}"
},
Expand All @@ -192,7 +192,7 @@
"artistBonus": "Desafío de artista",
"movieBonus": "Desafío de película",
"introBonus": "Bonus de intro rápida",
"betMultiplier": "Dobla o nada",
"betMultiplier": "Triplica o nada",
"betLost": "Apuesta perdida",
"total": "Total de esta ronda",
"noSubmission": "No enviaste respuesta"
Expand Down Expand Up @@ -620,11 +620,11 @@
"totalBets": "Apuestas Totales",
"totalBetsDesc": "Apuestas realizadas",
"betsWon": "Apuestas Ganadas",
"betsWonDesc": "Puntos dobles!",
"betsWonDesc": "Puntos triples!",
"winRate": "Tasa de Victoria",
"winRateDesc": "Porcentaje de exito",
"noBettingData": "Sin datos de apuestas todavia",
"bettingHint": "Los jugadores pueden apostar para duplicar sus puntos en adivinanzas seguras",
"bettingHint": "Los jugadores pueden apostar para triplicar sus puntos, pero solo gana el año exacto",
"overview": "Resumen",
"games": "Juegos",
"avgPlayersShort": "Prom Jug",
Expand Down Expand Up @@ -926,8 +926,8 @@
"letsPlay": "¡A jugar!",
"yearTitle": "Adivina el año",
"yearCaption": "Más cerca = más puntos",
"betTitle": "Dobla o nada",
"betCaption": "Apuesta a que estás cerca. Gana el doble.",
"betTitle": "Triple o nada",
"betCaption": "Apuesta por el año exacto. Gana el triple.",
"stealTitle": "Roba una respuesta",
"stealCaption": "Copia a otro jugador. Una vez por partida.",
"stealHint": "Úsalo cuando no tengas ni idea.",
Expand Down
18 changes: 9 additions & 9 deletions custom_components/beatify/www/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
"submittedCount": "{count}/{total} envoyés",
"round": "Manche {current} sur {total}",
"timeRemaining": "{seconds}s restantes",
"bet": "Quitte ou double",
"betShort": "×2",
"bet": "Quitte ou triple",
"betShort": "×3",
"noBonusThisRound": "Pas de bonus ce tour — trouve l'année",
"lockedIn": "Verrouillé · en attente des autres",
"lockedInWaitingCount": "Verrouillé · en attente de {count} joueur(s)",
Expand Down Expand Up @@ -156,7 +156,7 @@
"streakLost": "Série de {count} perdue",
"baseScore": "Score de base",
"speedBonus": "Bonus de vitesse",
"betWon": "Pari gagné ! 2x points",
"betWon": "Pari gagné ! 3x points",
"betLost": "Pari perdu",
"noSubmission": "Pas de réponse envoyée",
"allPlayers": "Tous les joueurs",
Expand All @@ -180,7 +180,7 @@
"noGuess": "—"
},
"chip": {
"betWon": "Pari gagné · ×2",
"betWon": "Pari gagné · ×3",
"betLost": "Pari perdu",
"streakBonus": "Série de {count} · +{bonus}"
},
Expand All @@ -192,7 +192,7 @@
"artistBonus": "Défi artiste",
"movieBonus": "Défi film",
"introBonus": "Bonus intro rapide",
"betMultiplier": "Quitte ou double",
"betMultiplier": "Quitte ou triple",
"betLost": "Pari perdu",
"total": "Total du tour",
"noSubmission": "Aucune réponse"
Expand Down Expand Up @@ -620,11 +620,11 @@
"totalBets": "Paris totaux",
"totalBetsDesc": "Paris effectués",
"betsWon": "Paris gagnés",
"betsWonDesc": "Points doublés !",
"betsWonDesc": "Points triplés !",
"winRate": "Taux de victoire",
"winRateDesc": "Pourcentage de réussite",
"noBettingData": "Pas encore de données de paris",
"bettingHint": "Les joueurs peuvent parier pour doubler leurs points sur des réponses sûres",
"bettingHint": "Les joueurs peuvent parier pour tripler leurs points, mais seule l'année exacte gagne",
"overview": "Aperçu",
"games": "Parties",
"avgPlayersShort": "Moy Jou",
Expand Down Expand Up @@ -926,8 +926,8 @@
"letsPlay": "C'est parti",
"yearTitle": "Devine l'année",
"yearCaption": "Plus près = plus de points",
"betTitle": "Quitte ou double",
"betCaption": "Parie que tu es proche. Gagne le double.",
"betTitle": "Quitte ou triple",
"betCaption": "Parie sur l'année exacte. Gagne le triple.",
"stealTitle": "Vole une réponse",
"stealCaption": "Copie un autre joueur. Une fois par partie.",
"stealHint": "Utilise-le quand tu n'as aucune idée.",
Expand Down
Loading
Loading