|
2 | 2 |
|
3 | 3 | ## Project Overview |
4 | 4 |
|
5 | | -A Python project that generates mathematically optimal blackjack basic strategy tables based on configurable game rules. The strategy is computed using Expected Value (EV) calculations. |
| 5 | +A Python project that generates mathematically optimal blackjack basic strategy tables based on configurable game rules. The strategy is computed using Expected Value (EV) calculations. Includes an interactive web app for visualization. |
| 6 | + |
| 7 | +**Live Demo**: https://hankhsu1996.github.io/blackjack-basic-strategy/ |
6 | 8 |
|
7 | 9 | ## Quick Start |
8 | 10 |
|
| 11 | +### Web App (Recommended) |
| 12 | + |
| 13 | +```bash |
| 14 | +# Generate strategy JSON files |
| 15 | +uv run python -m scripts.generate_strategies |
| 16 | + |
| 17 | +# Start dev server |
| 18 | +cd web && npm run dev |
| 19 | +``` |
| 20 | + |
| 21 | +Open http://localhost:5173/blackjack-basic-strategy/ |
| 22 | + |
| 23 | +### CLI |
| 24 | + |
9 | 25 | ```bash |
10 | 26 | # Text output to terminal |
11 | 27 | uv run main.py |
12 | 28 |
|
13 | 29 | # HTML output (color-coded) |
14 | 30 | uv run main.py --format html |
15 | | - |
16 | | -# Custom output file |
17 | | -uv run main.py --format html --output my-strategy.html |
18 | 31 | ``` |
19 | 32 |
|
20 | | -## CLI Options |
| 33 | +## Project Structure |
21 | 34 |
|
22 | | -| Option | Description | |
23 | | -|--------|-------------| |
24 | | -| `-f, --format` | Output format: `text` (default) or `html` | |
25 | | -| `-o, --output` | Output file path (default: stdout for text, strategy.html for HTML) | |
| 35 | +``` |
| 36 | +├── src/blackjack/ # Python strategy calculation |
| 37 | +│ ├── config.py # GameConfig dataclass |
| 38 | +│ ├── cards.py # Card values, probabilities |
| 39 | +│ ├── dealer.py # Dealer outcome distribution |
| 40 | +│ ├── evaluator.py # EV calculations |
| 41 | +│ ├── strategy.py # Optimal action selection |
| 42 | +│ ├── tables.py # Strategy data generation |
| 43 | +│ └── renderers.py # Text/HTML renderers |
| 44 | +├── scripts/ |
| 45 | +│ └── generate_strategies.py # Generate JSON for web app |
| 46 | +├── web/ # Svelte + Tailwind + DaisyUI |
| 47 | +│ ├── src/ |
| 48 | +│ │ ├── App.svelte |
| 49 | +│ │ └── lib/ |
| 50 | +│ │ ├── components/ # UI components |
| 51 | +│ │ ├── stores/ # Svelte stores |
| 52 | +│ │ ├── types/ # TypeScript types |
| 53 | +│ │ └── utils/ # Color utilities |
| 54 | +│ └── public/strategies/ # Pre-computed JSON (generated) |
| 55 | +└── main.py # CLI entry point |
| 56 | +``` |
26 | 57 |
|
27 | 58 | ## Development |
28 | 59 |
|
29 | | -Setup (installs dependencies automatically): |
30 | | -```bash |
31 | | -uv sync |
32 | | -``` |
| 60 | +### Python |
33 | 61 |
|
34 | | -Run: |
35 | 62 | ```bash |
36 | | -uv run main.py |
| 63 | +uv sync # Install dependencies |
| 64 | +uv run main.py # Run CLI |
| 65 | +uv run ruff check . # Lint |
| 66 | +uv run ruff format . # Format |
37 | 67 | ``` |
38 | 68 |
|
39 | | -Lint: |
40 | | -```bash |
41 | | -uv run ruff check . |
42 | | -``` |
| 69 | +### Web App |
43 | 70 |
|
44 | | -Format: |
45 | 71 | ```bash |
46 | | -uv run ruff format . |
| 72 | +cd web |
| 73 | +npm install # Install dependencies |
| 74 | +npm run dev # Dev server |
| 75 | +npm run build # Production build |
47 | 76 | ``` |
48 | 77 |
|
49 | | -Lint and fix auto-fixable issues: |
| 78 | +### Generate Strategy JSON |
| 79 | + |
50 | 80 | ```bash |
51 | | -uv run ruff check --fix . |
| 81 | +uv run python -m scripts.generate_strategies |
52 | 82 | ``` |
53 | 83 |
|
54 | | -## Project Structure |
| 84 | +Generates 96 JSON files (6 deck options × 2⁴ boolean options) to `web/public/strategies/`. |
55 | 85 |
|
56 | | -``` |
57 | | -src/blackjack/ |
58 | | -├── config.py # GameConfig dataclass - all rule variations |
59 | | -├── cards.py # Card values, probabilities, hand_value() |
60 | | -├── dealer.py # DealerProbabilities - dealer outcome distribution |
61 | | -├── evaluator.py # EVCalculator - EV for stand/hit/double/split |
62 | | -├── strategy.py # BasicStrategy - optimal action selection |
63 | | -├── tables.py # StrategyTables - data generation |
64 | | -└── renderers.py # TextRenderer, HTMLRenderer - output formatting |
65 | | -``` |
| 86 | +## Configuration Options |
| 87 | + |
| 88 | +| Parameter | Default | Description | |
| 89 | +|-----------|---------|-------------| |
| 90 | +| num_decks | 6 | Number of decks (0 = infinite) | |
| 91 | +| dealer_hits_soft_17 | False | H17 vs S17 rule | |
| 92 | +| double_after_split | True | DAS allowed | |
| 93 | +| resplit_aces | False | RSA allowed | |
| 94 | +| dealer_peeks | True | Dealer checks for blackjack | |
| 95 | + |
| 96 | +## Action Codes |
| 97 | + |
| 98 | +- `S` - Stand |
| 99 | +- `H` - Hit |
| 100 | +- `D` / `Dh` / `Ds` - Double (or Hit/Stand if not allowed) |
| 101 | +- `P` / `Ph` - Split (or Hit if not allowed) |
66 | 102 |
|
67 | 103 | ## Architecture |
68 | 104 |
|
69 | 105 | ### Data Flow |
70 | 106 |
|
71 | 107 | ``` |
72 | | -GameConfig → EVCalculator → BasicStrategy → StrategyTables → Renderer → Output |
73 | | - ↓ ↓ |
74 | | - DealerProbabilities StrategyData |
| 108 | +GameConfig → EVCalculator → BasicStrategy → StrategyTables → JSON/Renderer |
| 109 | + ↓ |
| 110 | + DealerProbabilities |
75 | 111 | ``` |
76 | 112 |
|
77 | 113 | ### Key Classes |
@@ -107,51 +143,34 @@ For finite decks (num_decks > 0), the calculator uses composition-dependent prob |
107 | 143 |
|
108 | 144 | This matches real-world 4-8 deck basic strategy charts. For infinite deck (num_decks = 0), standard probabilities are used. |
109 | 145 |
|
110 | | -## Configuration Options |
| 146 | +### Web App Stack |
111 | 147 |
|
112 | | -| Parameter | Default | Description | |
113 | | -|-----------|---------|-------------| |
114 | | -| num_decks | 6 | Number of decks (0 = infinite) | |
115 | | -| dealer_hits_soft_17 | False | H17 vs S17 rule | |
116 | | -| double_after_split | True | DAS allowed | |
117 | | -| resplit_aces | False | RSA allowed | |
118 | | -| max_splits | 3 | Max splits (3 = up to 4 hands) | |
119 | | -| blackjack_pays | 1.5 | 3:2 = 1.5, 6:5 = 1.2 | |
120 | | -| dealer_peeks | True | Dealer checks for blackjack | |
| 148 | +- **Svelte 5** - Reactive UI framework |
| 149 | +- **Tailwind CSS** - Utility-first styling |
| 150 | +- **DaisyUI** - Component library |
| 151 | +- **Vite** - Build tool |
121 | 152 |
|
122 | | -## Action Codes |
| 153 | +### Key Design Decisions |
123 | 154 |
|
124 | | -- `S` - Stand |
125 | | -- `H` - Hit |
126 | | -- `D` - Double |
127 | | -- `Dh` - Double if allowed, otherwise Hit |
128 | | -- `Ds` - Double if allowed, otherwise Stand |
129 | | -- `P` - Split |
| 155 | +1. **Pre-computed strategies**: 96 JSON files cover all rule combinations. Faster than runtime calculation. |
| 156 | +2. **HSL colors**: Easy to adjust whiteness/saturation for accessibility. |
| 157 | +3. **Responsive layout**: Desktop shows sidebar + horizontal tables; mobile uses collapsible config. |
| 158 | + |
| 159 | +## Deployment |
| 160 | + |
| 161 | +GitHub Actions automatically: |
| 162 | +1. Generates strategy JSON files |
| 163 | +2. Builds Svelte app |
| 164 | +3. Deploys to GitHub Pages |
130 | 165 |
|
131 | 166 | ## Commit Format |
132 | 167 |
|
133 | 168 | ``` |
134 | 169 | <Summary starting with verb, 50 chars or less> |
135 | 170 |
|
136 | | -- First change description (wrap at 72 chars) |
137 | | -- Second change description |
138 | | -- 2-5 bullets based on change size |
| 171 | +- Bullet points (2-5) |
139 | 172 |
|
140 | 173 | 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
141 | 174 |
|
142 | 175 | Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
143 | 176 | ``` |
144 | | - |
145 | | -## Testing |
146 | | - |
147 | | -```bash |
148 | | -python3 -m pytest tests/ |
149 | | -``` |
150 | | - |
151 | | -## Dependencies |
152 | | - |
153 | | -Runtime: `tabulate` for table formatting |
154 | | - |
155 | | -Dev: `ruff` for linting and formatting |
156 | | - |
157 | | -Managed with `uv` - see https://docs.astral.sh/uv/ |
|
0 commit comments