Blackjack Card Game
Casino Card Game Simulation
Design a Blackjack table: a shoe of shuffled decks, hands that count an ace as 1 or 11, bets, hit, stand, double and split, a dealer that follows fixed rules, and the payout.
Overview
Blackjack is a card game played against a dealer. Each player bets, gets two cards, and then draws more cards to get as close to 21 as possible without going over. The dealer draws last and follows fixed rules, so the dealer makes no choices at all. A player who beats the dealer wins the bet; a blackjack (an ace and a ten-point card as the first two cards) pays more.
The problem looks like a toy, but it tests real design skills. Can you count an ace as 1 or 11 without a bug? Can you stop a player from hitting when it is not their turn? Can split, which turns one hand into two in the middle of play, fit your model without special cases everywhere? And can a test control which cards come out of the shoe, so every rule can be checked with exact numbers?
A strong answer scopes the rules first, draws the round as a small state machine, puts the ace logic in the hand, and keeps the dealer's rule and the payout ratio as configuration.
Scoping the problem
House rules differ from casino to casino, so ask before you design.
- How many decks are in the shoe? — Size of the shoe and when to reshuffle — Six decks, reshuffle at a cut card
- Does the dealer hit a soft 17? — Changes the dealer's rule — Configurable; default stands on all 17s
- What does a blackjack pay? — The payout formula — 3 to 2, configurable
- Which actions are in scope? — Each one is a method and a rule check — Hit, stand, double, split; insurance and surrender are follow-ups
- How many hands may a split make? — Limits re-splitting — Up to four
- How many players at a table? — Turn order — Several, played in seat order
The rules the code follows
These are the common casino rules; each is a line in the code.
- Number cards count their number, face cards count 10, an ace counts 1 or 11 — Card.points and Hand.value
- A blackjack is an ace and a ten-point card as the first two cards of an unsplit hand — Hand.is_blackjack
- Over 21 is a bust and loses at once, even if the dealer busts later — _settle checks bust first
- The dealer draws on 16 or less and stands on 17 or more — StandOnSoft17
- Some tables make the dealer hit a soft 17 — HitSoft17
- A blackjack pays 3 to 2; a win pays 1 to 1; a tie is a push and returns the bet — Rules.blackjack_pays, _settle
- If the dealer has a blackjack, every hand loses except a player blackjack, which pushes — checked right after the deal
- Split aces get one card each, and 21 after a split is not a blackjack — split and from_split
- Double doubles the bet for exactly one more card — double
Counting the ace
A hand is soft when one of its aces is counted as 11. Count every ace as 1 first, then add 10 if the hand has an ace and the total stays at or under 21. Only one ace can ever count as 11, because two would already be 22.
- A, 6 — 7 — yes: 17 ≤ 21 — 17 — yes
- A, 6, 8 — 15 — no: 25 > 21 — 15 — no
- A, A, 9 — 11 — yes: 21 ≤ 21 — 21 — yes
- K, Q, 5 — 25 — no ace — 25 — bust
The ace rule belongs to the hand, not the card. A card cannot know its value, because its value depends on the other cards.
Core entities
A player owns a list of hands, not one hand. That single choice is what makes split easy: split inserts a second hand after the current one, and the turn loop visits it next.
The round as a state machine
Every action is legal in only one phase. Betting after the deal, or hitting before it, must fail. The table keeps a phase and each method checks it first. The dealer's turn has no player input, so it runs straight through and is not a phase anyone waits in.
Here is the first round of the demo, with a stacked shoe so the cards are known. Players A and B each bet 100 and start with 1000.
- 1 — deal — A, K: blackjack, finished — 10, 6 = 16 — 9 up, 7 down
- 2 — B hits, draws 5 — 21, finished
- 3 — dealer plays: 16, draws 10 — 26, bust
- 4 — settle — paid 100 + 150 = 250 — paid 200
- 5 — balances — 1150 — 1100
What you will be able to do
- Scope the house rules with the interviewer and turn each one into a line of code or a setting.
- Count an ace correctly and explain why the rule lives in the hand.
- Guard every action with the round's phase so illegal moves fail loudly.
- Model split as one more hand in a player's list, including split aces.
- Test every rule with a stacked shoe and exact balances.
Functional requirements
- A shoe of several 52-card decks, shuffled, and reshuffled between rounds once the cut point is reached
- place_bet(player, amount) before the deal, within the table limits and the player balance
- Hand value counts an ace as 1 or 11; detect soft hands, blackjack and bust
- Player actions on the current hand: hit, stand, double down, split a pair (up to four hands)
- The dealer follows a fixed rule: stand on all 17s, or hit a soft 17 at tables that use that rule
- Settle every hand: blackjack pays 3 to 2, a win pays 1 to 1, a tie pushes, a bust loses
- Several players at one table, played in seat order
Non-functional requirements
- Correctness: each action is allowed only in its phase and on a hand where it is legal
- Configurable: table limits, blackjack payout, maximum hands and the dealer rule are settings, not code changes
- Testable: the shoe is injected, so a test can stack the cards and assert exact balances
- Money is whole chips (integers), so payouts never suffer floating-point error; 3 to 2 on an odd bet rounds the half chip down, so a real table counts in smaller units or takes only even bets
Interview questions
- Why does the ace logic live in Hand and not in Card?
- Walk me through split. What makes it tricky?
- How do you support house rule variations?
- How does the shoe decide when to reshuffle, and why only between rounds?
- Many tables run at once, and players use a phone app. How do you handle concurrency?
Sign up free to read the full topic
More Low-Level Design topics
Start free on Cariara · Coding problems · System design studio