Initial commit: 6-Card Golf with AI opponents

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>
This commit is contained in:
Aaron D. Lee
2026-01-24 19:26:12 -05:00
parent b4a661a801
commit d18cea2104
18 changed files with 8186 additions and 0 deletions

190
server/RULES.md Normal file
View File

@@ -0,0 +1,190 @@
# 6-Card Golf Rules
This document defines the canonical rules implemented in this game engine, based on standard 6-Card Golf rules from [Pagat.com](https://www.pagat.com/draw/golf.html) and [Bicycle Cards](https://bicyclecards.com/how-to-play/six-card-golf).
## Overview
Golf is a card game where players try to achieve the **lowest score** over multiple rounds ("holes"). The name comes from golf scoring - lower is better.
## Players & Equipment
- **Players:** 2-6 players
- **Deck:** Standard 52-card deck (optionally with 2 Jokers)
- **Multiple decks:** For 5+ players, use 2 decks
## Setup
1. Dealer shuffles and deals **6 cards face-down** to each player
2. Players arrange cards in a **2 row × 3 column grid**:
```
[0] [1] [2] ← Top row
[3] [4] [5] ← Bottom row
```
3. Remaining cards form the **draw pile** (face-down)
4. Top card of draw pile is flipped to start the **discard pile**
5. Each player flips **2 of their cards** face-up (standard rules)
## Card Values
| Card | Points |
|------|--------|
| Ace | 1 |
| 2 | **-2** (negative!) |
| 3-10 | Face value |
| Jack | 10 |
| Queen | 10 |
| King | **0** |
| Joker | -2 |
## Column Pairing
**Critical rule:** If both cards in a column have the **same rank**, that column scores **0 points** regardless of the individual card values.
Example:
```
[K] [5] [7] K-K pair = 0
[K] [3] [9] 5+3 = 8, 7+9 = 16
Total: 0 + 8 + 16 = 24
```
**Note:** Paired 2s score 0 (not -4). The pair cancels out, it doesn't double the negative.
## Turn Structure
On your turn:
### 1. Draw Phase
Choose ONE:
- Draw the **top card from the draw pile** (face-down deck)
- Take the **top card from the discard pile** (face-up)
### 2. Play Phase
**If you drew from the DECK:**
- **Swap:** Replace any card in your grid (old card goes to discard face-up)
- **Discard:** Put the drawn card on the discard pile and flip one face-down card
**If you took from the DISCARD PILE:**
- **You MUST swap** - you cannot re-discard the same card
- Replace any card in your grid (old card goes to discard)
### Important Rules
- Swapped cards are always placed **face-up**
- You **cannot look** at a face-down card before deciding to replace it
- When swapping a face-down card, reveal it only as it goes to discard
## Round End
### Triggering the Final Turn
When any player has **all 6 cards face-up**, the round enters "final turn" phase.
### Final Turn Phase
- Each **other player** gets exactly **one more turn**
- The player who triggered final turn does NOT get another turn
- After all players have had their final turn, the round ends
### Scoring
1. All remaining face-down cards are revealed
2. Calculate each player's score (with column pairing)
3. Add round score to total score
## Winning
- Standard game: **9 rounds** ("9 holes")
- Player with the **lowest total score** wins
- Optionally play 18 rounds for a longer game
---
# House Rules (Optional)
Our implementation supports these optional rule variations:
## Standard Options
| Option | Description | Default |
|--------|-------------|---------|
| `initial_flips` | Cards revealed at start (0, 1, or 2) | 2 |
| `flip_on_discard` | Must flip a card after discarding from deck | Off |
| `knock_penalty` | +10 if you go out but don't have lowest score | Off |
| `use_jokers` | Add Jokers to deck (-2 points each) | Off |
## Point Modifiers
| Option | Effect |
|--------|--------|
| `lucky_swing` | Single Joker worth **-5** (instead of two -2 Jokers) |
| `super_kings` | Kings worth **-2** (instead of 0) |
| `lucky_sevens` | 7s worth **0** (instead of 7) |
| `ten_penny` | 10s worth **1** (instead of 10) |
## Bonuses & Penalties
| Option | Effect |
|--------|--------|
| `knock_bonus` | First to reveal all cards gets **-5** bonus |
| `underdog_bonus` | Lowest scorer each round gets **-3** |
| `tied_shame` | Tying another player's score = **+5** penalty to both |
| `blackjack` | Exact score of 21 becomes **0** |
## Gameplay Twists
| Option | Effect |
|--------|--------|
| `queens_wild` | Queens match any rank for column pairing |
| `four_of_a_kind` | 4 cards of same rank in grid = all 4 score 0 |
| `eagle_eye` | Paired Jokers score **-8** (instead of canceling to 0) |
---
# Game Theory Notes
## Expected Turn Count
With standard rules (2 initial flips):
- Start: 2 face-up, 4 face-down
- Each turn reveals 1 card (swap or discard+flip)
- **Minimum turns to go out:** 4
- **Typical range:** 4-8 turns per player per round
## Strategic Considerations
### Good Cards (keep these)
- **Jokers** (-2 or -5): Best cards in the game
- **2s** (-2): Second best, but don't pair them!
- **Kings** (0): Safe, good for pairing
- **Aces** (1): Low risk
### Bad Cards (replace these)
- **10, J, Q** (10 points): Worst cards
- **8, 9** (8-9 points): High priority to replace
### Pairing Strategy
- Pairing is powerful - column score goes to 0
- **Don't pair negative cards** - you lose the negative benefit
- Target pairs with mid-value cards (3-7) for maximum gain
### When to Go Out
- Go out with **score ≤ 10** when confident you're lowest
- Consider opponent visible cards before going out early
- With `knock_penalty`, be careful - +10 hurts if you're wrong
---
# Test Coverage
The game engine has comprehensive test coverage in `test_game.py`:
- **Card Values:** All 13 ranks verified
- **Column Pairing:** Matching, non-matching, negative card edge cases
- **House Rules:** All scoring modifiers tested
- **Draw/Discard:** Deck draws, discard draws, must-swap rule
- **Turn Flow:** Turn advancement, wrap-around, player validation
- **Round End:** Final turn triggering, one-more-turn logic
- **Multi-Round:** Score accumulation, hand reset
Run tests with:
```bash
pytest test_game.py -v
```