Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
425: Building a Simple Blackjack Card Game
Think of building a Blackjack game like organizing a small dinner party where you're the host and the referee. You've got a deck of cards on the table (your data source), a set of rules everyone agreed to (your game logic), and a sequence of events: you deal the cards, the guest decides if they want more, and finally, you compare who got closer to the target without going over. If you mess up the order of these events—like asking the guest if they want another card after you've already declared a winner—the whole night is a disaster.
In Python, we map this party directly to our code. The deck is a list we shuffle; the "dealing" is just popping elements off that list; and the guest's decision-making process is a while loop that only breaks when they "stand" or bust.
Managing the Deck as a Stack
I usually start by defining the deck using a list. Since we don't need to track the physical suit for a basic game, we can just focus on the ranks. Using random.shuffle() is the easiest way to ensure the game isn't predictable. I prefer using a list and pop() because it mimics the real-world action of taking a card off the top of the pile.
import random
def create_deck():
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
# We multiply by 4 to get a full deck of 52 cards
deck = ranks * 4
random.shuffle(deck)
return deck
The Ace Dilemma
Here is where most people trip up: the Ace. In Blackjack, an Ace is worth 11 unless that pushes the player over 21, in which case it becomes a 1. I've found the cleanest way to handle this is to calculate the score assuming all Aces are 11, and then subtract 10 for every Ace we have if the total is too high.
def calculate_score(hand):
score = 0
aces = 0
# Mapping face cards to 10 and Ace to 11
values = {'2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, '10':10, 'J':10, 'Q':10, 'K':10, 'A':11}
for card in hand:
score += values[card]
if card == 'A':
aces += 1
# Adjust for Aces if we're busting
while score > 21 and aces > 0:
score -= 10
aces -= 1
return score
The Player's Decision Loop
The core of the game is a loop. You aren't just asking once; you're asking repeatedly until a specific condition is met. I use a while loop here. It's important to check the score inside the loop so that if the player hits and busts, the game ends immediately without asking them if they want another card.
def play_game():
deck = create_deck()
player_hand = [deck.pop(), deck.pop()]
dealer_hand = [deck.pop(), deck.pop()]
while True:
player_score = calculate_score(player_hand)
print(f"Your hand: {player_hand}, score: {player_score}")
if player_score > 21:
print("Bust! You lose.")
return
choice = input("Do you want to 'hit' or 'stand'? ").lower()
if choice == 'hit':
player_hand.append(deck.pop())
else:
break
# Now we handle the dealer's turn...
print(f"Dealer's hand: {dealer_hand}, score: {calculate_score(dealer_hand)}")
One detail I noticed when building this is that the dealer's logic is actually simpler than the player's. The dealer doesn't get to "choose"—they follow a hard rule: they must keep hitting until their score is at least 17. This removes the need for input() and makes it a simple while loop based on the score.
📋 Practical Task
Implementing the Dealer's Automated Hit Logic
Your current game stops right after the player stands. To make this a functional game, you need to implement the dealer's turn. In Blackjack, the dealer must continue to draw cards (hit) until their total score is 17 or higher.
Modify the play_game function (or create a new function called dealer_turn) to implement the following logic:
- While the dealer's score is less than 17, they must
pop()a card from the deck and add it to their hand. - After the dealer finishes hitting, compare the dealer's final score to the player's final score.
- Print the final result: "Player Wins", "Dealer Wins", or "Push" (a tie).
- Remember to account for the possibility that the dealer might bust (go over 21), which would result in an automatic player win.
There are no comments for now.