Blackjack Game in Python
Intermediate · Games · about 90 minutes to build · 149 lines
You bet chips, take cards or stand, and try to finish closer to 21 than the dealer without going over.
The program
Press Run and answer its questions in the box that appears under the code.
Open it in the full editor to save it, share it and keep building.
Sample run
What the program printed, and what was typed (in yellow).
=== Blackjack === Get closer to 21 than the dealer. Aces count 1 or 11, picture cards 10. You have 100 chips. Your bet (1-100), or 0 to leave: 500 Please type a whole number from 0 to 100. Your bet (1-100), or 0 to leave: 20 Dealer: J of spades, [hidden card] You: 9 of hearts, A of hearts (total 20) Hit or stand? (h/s): s Dealer: J of spades, 4 of clubs (total 14) Dealer: J of spades, 4 of clubs, 5 of spades (total 19) You win the hand. You have 120 chips. Your bet (1-120), or 0 to leave: 30 Dealer: 10 of diamonds, [hidden card] You: 6 of spades, 8 of spades (total 14) Hit or stand? (h/s): h You: 6 of spades, 8 of spades, K of diamonds (total 24) Bust. You lose your bet. You have 90 chips. Your bet (1-90), or 0 to leave: 50 Dealer: 8 of diamonds, [hidden card] You: 10 of clubs, 2 of hearts (total 12) Hit or stand? (h/s): h You: 10 of clubs, 2 of hearts, 7 of spades (total 19) Hit or stand? (h/s): x Please type h to take a card or s to stop. Hit or stand? (h/s): s Dealer: 8 of diamonds, 4 of spades (total 12) Dealer: 8 of diamonds, 4 of spades, 3 of diamonds (total 15) Dealer: 8 of diamonds, 4 of spades, 3 of diamonds, 2 of diamonds (total 17) You win the hand. You have 140 chips. Your bet (1-140), or 0 to leave: 0 You leave with 140 chips (+40 since you sat down).
How it is built
1. A shuffled deck
A list comprehension pairs every suit with every rank to make 52 (rank, suit) tuples, and random.shuffle mixes them. Dealing a card is deck.pop(), which takes one off the end.
def new_deck(): """Return a shuffled deck of 52 cards as (rank, suit) pairs.""" deck = [(rank, suit) for suit in SUITS for rank in RANKS] random.shuffle(deck) return deck
2. Counting a hand
Every ace starts as 11. While the total is over 21 and an ace is still counted as 11, that ace drops to 1, which is how the rule works at a real table.
def hand_total(hand): """Add up a hand, counting aces as 1 instead of 11 while the total is over 21.""" total = 0 aces = 0 for rank, _ in hand: if rank == "A": total += 11 aces += 1 elif rank in ("J", "Q", "K"): total += 10 else: total += int(rank) while total > 21 and aces: total -= 10 aces -= 1 return total
3. The player's turn
The player can take cards until they stand or reach 21. The hand is a list, so hand.append(deck.pop()) moves a card from the deck into it.
def player_turn(deck, hand): """Deal cards to the player until they stand or reach 21; return the total.""" while hand_total(hand) < 21: if ask_hit_or_stand() == "s": break hand.append(deck.pop()) show_hand("You", hand) return hand_total(hand)
4. The dealer's turn
The dealer has no choices: the rules say draw below 17 and stand from 17 up. The loop follows that rule with DEALER_STANDS_AT.
def dealer_turn(deck, hand): """Turn over the hidden card and draw until the total reaches 17; return it.""" show_hand("Dealer", hand) while hand_total(hand) < DEALER_STANDS_AT: hand.append(deck.pop()) show_hand("Dealer", hand) return hand_total(hand)
5. One hand from deal to result
Cards are dealt one at a time to each side, and the dealer keeps one card hidden. A two-card 21 is a blackjack: the player's pays 3 to 2 and the dealer's wins at once. Otherwise both sides take their turns and the totals are compared, and the function returns the chips won or lost so main() only adds them up.
def play_hand(deck, bet): """Play one hand and return the chips won (negative when the player loses).""" # Deal like a casino: one card each, then a second card each. player, dealer = [], [] for _ in range(2): player.append(deck.pop()) dealer.append(deck.pop()) print(f" Dealer: {card_name(dealer[0])}, [hidden card]") show_hand("You", player) if hand_total(player) == 21: show_hand("Dealer", dealer) if hand_total(dealer) == 21: print("Both have blackjack. Your bet comes back.") return 0 print("Blackjack. It pays 3 to 2.") return bet * 3 // 2 if hand_total(dealer) == 21: show_hand("Dealer", dealer) print("The dealer has blackjack. You lose your bet.") return -bet player_total = player_turn(deck, player) if player_total > 21: print("Bust. You lose your bet.") return -bet dealer_total = dealer_turn(deck, dealer) if dealer_total > 21 or player_total > dealer_total: print("You win the hand.") return bet if player_total < dealer_total: print("The dealer wins the hand.") return -bet print("A tie (a push). Your bet comes back.") return 0
6. Chips and the table
The loop runs while the player has chips, and a bet of 0 leaves the table. When fewer than RESHUFFLE_BELOW cards are left, a fresh deck is shuffled.
def main(): """Deal hands until the player leaves the table or runs out of chips.""" print("=== Blackjack ===") print("Get closer to 21 than the dealer. Aces count 1 or 11, picture cards 10.") chips = STARTING_CHIPS deck = new_deck() while chips > 0: print(f"\nYou have {chips} chips.") bet = ask_number(f"Your bet (1-{chips}), or 0 to leave: ", 0, chips) if bet == 0: break if len(deck) < RESHUFFLE_BELOW: print(" (Shuffling a fresh deck.)") deck = new_deck() chips += play_hand(deck, bet) if chips == 0: print("\nYou are out of chips. Better luck next time.") else: change = chips - STARTING_CHIPS print(f"\nYou leave with {chips} chips ({change:+d} since you sat down).")
Make it bigger
- Add doubling down: double the bet, take exactly one more card, then stand.
- Let the player split a pair into two hands.
- Show the dealer's hidden card when the player busts, so they see what they were up against.
- Count wins, losses and pushes and print them when the player leaves.