Only standard-rules games now count toward leaderboard stats. Games
with any house rule variant are marked "Unranked" in the active rules
bar, and a notice appears in the lobby when house rules are selected.
Also fixes game_logger duplicate options dicts (now uses dataclasses.asdict,
capturing all options including previously missing ones) and refactors
duplicated achievement-checking logic into shared helpers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client-side scoring (points badge and score tally animation) ignored
house rules that modify pair behavior. Extract shared
calculateColumnScores() helper that mirrors server logic for
eagle_eye, negative_pairs_keep_value, wolfpack, four_of_a_kind,
and one_eyed_jacks rules. Server now sends scoring_rules flags
in game state.
Also fix opponent flip animation card font-size matching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tighten should_knock_early() so AI no longer knocks with projected
scores of 12-14. New range: max_acceptable 5-9 (was 8-18), with
scaled knock_chance by score quality and an exception when all
opponents show 25+ visible points.
Fix 5 pre-existing test failures:
- test_event_replay: use game.current_player() instead of hardcoding
"p1", since dealer logic makes p2 go first
- game.py: include current_player_idx in round_started event so state
replay knows the correct starting player
- test_house_rules: rename test_rule_config → run_rule_config so
pytest doesn't collect it as a test fixture
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When you accidentally click the discard pile, you can now put the card
back instead of being forced to swap. The "Put Back" button appears
only when you've drawn from the discard pile.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 - Critical Fixes:
- Add game_lock (asyncio.Lock) to Room class for serializing mutations
- Wrap all game action handlers in lock to prevent race conditions
- Split Card.to_dict into to_dict (full data) and to_client_dict (hidden)
- Fix CardState.from_dict to handle missing rank/suit gracefully
- Fix GameOptions reconstruction in recovery_service (dict -> object)
- Extend state cache TTL from 4h to 24h, add touch_game method
Phase 2 - Security:
- Add optional WebSocket authentication via token query param
- Use authenticated user ID/name when available
- Add auth support to spectator WebSocket endpoint
Phase 3 - Performance:
- Make stats processing async (fire-and-forget) to avoid blocking
game completion notifications
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Early Knock variant: flip all remaining cards (≤2) to go out early
- Update RULES.md with comprehensive documentation for all new variants
- Shorten flip mode dropdown descriptions for cleaner UI
- Add try-catch and optional chaining in startGame() for robustness
- Add WebSocket connection error feedback with reject sound
- AI awareness for Early Knock decisions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive docstrings to game.py, room.py, constants.py
- Document all classes, methods, and module-level items
- Move active rules display into game header as inline column
- Update header to 5-column grid layout
- Update joker mode descriptions (Lucky Swing, Eagle-Eye)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add big final results modal at game end with rankings and share button
- Add active rules bar showing enabled variants during gameplay
- Increase spacing between player cards and opponents row
- Add Wolfpack bonus rule (2 pairs of Jacks = -5 pts)
- Change joker options to radio buttons (None/Standard/Lucky Swing/Eagle-Eye)
- Update Eagle-Eye jokers: +2 pts unpaired, -4 pts paired
- Add card flip animation on discard pile
- Redesign waiting room layout with side-by-side columns
- Style card backs with red Bee-style diamond crosshatch pattern
- Compact standings panel to show top 4 per category
- Various CSS polish and responsive improvements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add constants.py as the single source of truth for card values
- Derive RANK_VALUES from DEFAULT_CARD_VALUES instead of duplicating
- Add centralized get_card_value() function in game.py for Card objects
- Add get_card_value_for_rank() in constants.py for string-based lookups
- Fix bug: AI ten_penny returned 0 instead of 1 per RULES.md
- Update ai.py and game_analyzer.py to use centralized functions
- UI improvements for client
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Features:
- Multiplayer WebSocket game server (FastAPI)
- 8 AI personalities with distinct play styles
- 15+ house rule variants
- SQLite game logging for AI analysis
- Comprehensive test suite (80+ tests)
AI improvements:
- Fixed Maya bug (taking bad cards, discarding good ones)
- Personality traits influence style without overriding competence
- Zero blunders detected in 1000+ game simulations
Testing infrastructure:
- Game rules verification (test_game.py)
- AI decision analysis (game_analyzer.py)
- Score distribution analysis (score_analysis.py)
- House rules testing (test_house_rules.py)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>