A terminal-based Blackjack game written in Python with no external dependencies. Cards are rendered as ASCII art directly in the console.
A complete single-hand game of Blackjack against a dealer, built to practise core Python: data structures, function decomposition, and control flow. The whole game runs on the standard library — the only import is random.
The interesting part of this project is the card rendering. Each card is stored as a dictionary containing its rank, suit, value and a list of strings representing its ASCII art. To display a hand side by side, the game iterates over art rows and joins the same row from every card in the hand:
╔═════════╗ ╔═════════╗
║ K ║ ║ 7 ║
║ ║ ║ ║
║ ║ ║ ║
║ ♠ ║ ║ ♥ ║
║ ║ ║ ║
║ ║ ║ ║
║ K ║ ║ 7 ║
╚═════════╝ ╚═════════╝
Score: 17
- Full 52-card deck built programmatically from rank and suit dictionaries, then shuffled
- Cards drawn from the deck with
pop(), so no card is ever dealt twice - Player turn with hit/stand input, and automatic detection of bust and of a natural 21
- Dealer AI following the standard casino rule: draw while the hand is below 17, then stand
- Win conditions covering player bust, dealer bust, higher score, and tie
Requires Python 3.6 or newer. No installation needed.
git clone https://github.com/AugustSud/Mini-Python-Game-Blackjack.git
cd Mini-Python-Game-Blackjack/Blackjack
python main.pyThe suit symbols (♠ ♥ ♣ ♦) need a terminal with UTF-8 support. On older Windows consoles, run chcp 65001 first if the symbols appear as question marks.
At the prompt, type hit to draw another card or stand to end your turn. The dealer then plays out its hand and the winner is announced.
Blackjack/
└── main.py # entire game: deck creation, turns, scoring, win logic
The code is organised into single-purpose functions rather than one long script:
| Function | Responsibility |
|---|---|
create_deck() |
Builds and shuffles the 52-card deck |
player_hand() / dealer_hand() |
Deals and displays the opening two cards |
player_turn() |
Handles the hit/stand loop and bust detection |
dealer_turn() |
Runs the dealer's draw-below-17 rule |
decide_winner() |
Compares final scores and prints the outcome |
blackjack() |
Orchestrates the round |
Documented rather than hidden — these are the things I would fix in a next pass:
- Aces are always worth 1. Real Blackjack scores an Ace as 1 or 11, whichever is better for the hand. This is the main rules gap.
- No input validation. Anything other than
hitorstandsilently loops instead of prompting again. - Single round. The game exits after one hand; there is no replay loop or chip balance.
- No split, double down or insurance.
Modelling a card as a dictionary that carries its own display representation made the rendering logic trivial — the display function never needs to know anything about ranks or suits, it just joins rows of strings. Getting the turn order right also turned out to be more subtle than expected: the dealer must not play at all if the player has already busted or hit exactly 21, which is why that check sits between the two turn calls.
