Skip to content

feat: betting is now exact-or-nothing, not free upside (#1004)#1006

Merged
mholzi merged 2 commits into
mainfrom
feat/1004-betting-redesign
May 19, 2026
Merged

feat: betting is now exact-or-nothing, not free upside (#1004)#1006
mholzi merged 2 commits into
mainfrom
feat/1004-betting-redesign

Conversation

@mholzi

@mholzi mholzi commented May 19, 2026

Copy link
Copy Markdown
Owner

Why

Discussion #950 / issue #1004: the double-or-nothing bet had zero downside. A bet doubled the score on any points and gave 0 otherwise — but a round scoring 0 already breaks the streak and banks 0, so a "lost" bet cost nothing. Betting was free upside; the rational play was to always bet.

Change — Design A "exact or nothing" + rename to Triple or Nothing

Mechanic (scoring.py, test_scoring.py):

  • A bet wins only on the exact year → round score × 3 (BET_WIN_MULTIPLIER).
  • A bet on a non-exact guess → 0 for the round — forfeiting those points is the real stake.
  • apply_bet_multiplier(round_score, bet, is_exact); caller passes player.years_off == 0.
  • No negative scores. 52 scoring tests passing.

Copy — the feature is renamed Double → Triple or Nothing, and every user-facing string moves from ×2 / "double" / "bet you're close" to ×3 / "triple" / "exact year":

  • player.html onboarding tour (title, caption, bet button, score mockup 12×3=36)
  • i18n/{en,de,es,fr,nl}.json — bet, betShort, betWon, betMultiplier, betsWonDesc, bettingHint, onboarding title/caption
  • README "Triple or Nothing" section + mentions

⚠️ Test note

Frontend not browser-tested — please smoke-test the onboarding tour + bet flow before merge.

Closes #1004

🤖 Generated with Claude Code

Before, a bet doubled the score on any points and yielded 0 otherwise —
but scoring 0 already breaks the streak and banks 0, so a "lost" bet
cost nothing. Betting was pure free upside; every rational player just
always bet.

Now (#1004, Design A): a bet wins only on the EXACT year → round score
x3 (BET_WIN_MULTIPLIER). A non-exact guess forfeits the round score
entirely — that forfeit is the stake that makes it a real gamble.
`apply_bet_multiplier` takes an `is_exact` flag; the caller passes
`player.years_off == 0`.

README "Double or Nothing" section updated. In-app ×2 labels still need
a copy sweep — tracked separately.

Closes #1004

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request redesigns the betting mechanic from a double-or-nothing system to an "exact or nothing" gamble. Players now receive a triple-point multiplier for guessing the exact year but forfeit all points for the round if they miss the exact year while a bet is active. The changes include updates to the scoring logic, documentation in the README, and corresponding unit tests. A critical issue was identified where lost bets fail to reset the player's streak because the streak calculation incorrectly uses the pre-bet score; a fix was suggested to use the final round score instead.

Comment on lines 609 to 611
player.round_score, player.bet_outcome = apply_bet_multiplier(
speed_score, player.bet
speed_score, player.bet, player.years_off == 0
)

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

Follow-up to the betting-mechanic change: the feature is renamed
Double → Triple or Nothing, and every user-facing string is corrected
from the old ×2 / "double" / "you're close" wording to ×3 / "triple" /
"exact year". Covers the onboarding tour (player.html), the bet button,
won-bet labels, stats and hints across all five locales, and the README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mholzi mholzi merged commit fd719f9 into main May 19, 2026
7 checks passed
@mholzi mholzi deleted the feat/1004-betting-redesign branch May 19, 2026 10:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Betting has no downside — make double-or-nothing a real gamble (#950)

1 participant