Blackjack Game Using Python With Source
Introduction :
Blackjack, also known as 21, is a popular card game that combines strategy and luck. In this blog post, we will walk through the creation of a simple Blackjack game using Python, featuring a graphical user interface (GUI). The game involves a deck of cards, where players aim to beat the dealer by getting a hand value as close to 21 as possible without exceeding it. This project utilizes the simplegui module for GUI development and random for shuffling the deck. Our Blackjack game will cover the essential aspects of gameplay, including dealing cards, handling player actions (hit or stand), and determining the winner
Required Modules or Packages :
To build this Blackjack game, you’ll need the following modules:
● simplegui: A GUI library used for drawing and handling events.
● random:Amodule to shuffle the deck of cards.
To install these packages, use the following command:
pip install simplegui
How to Run the Code :-
Clone the Repository (if applicable):
git clone [repository link]
Navigate to the Project Directory:
cd [project-directory]
Install the Required Packages:
pip install simplegui
Run the Main Script:
python blackjack.py
Code Explanation :-
Classes
● CardClass: Represents a single card with a rank, color, and exposed state. It has methods to expose or hide the card and to retrieve its rank and color.
class Card:
def __init__(self, rank, color, exposed=True):
self.rank = rank
self.color = color
self.exposed = exposed
def __str__(self):
return f"Rank is {self.rank}, Color is {self.color}, exposed
is {self.exposed}"
def get_rank(self):
return self.rank
def get_color(self):
return self.color
def is_exposed(self):
return self.exposed
def expose_it(self):
self.exposed = True
def hide_it(self):
self.exposed = False
DeckClass: Represents a deck of cards. It initializes with a full deck, shuffles it, and
provides methods to deal cards
class Deck:
def __init__(self):
self.cards = [Card(rank, color) for color in COLORS for rank
in RANKS]
random.shuffle(self.cards)
def __str__(self):
return ''.join(str(card) for card in self.cards)
def get_one_card(self):
return self.cards.pop()
def get_all_cards(self):
return self.cards
HandClass: Represents a hand of cards. It calculates the total value of the hand, adding or hiding cards as needed
class Hand:
def __init__(self):
self.cards = []
def __str__(self):
return ''.join(str(card) for card in self.cards)
def get_sum(self):
sum_cards = sum(VALUES[card.get_rank()] for card in
self.cards)
has_ace = any(card.get_rank() == 'A' for card in self.cards)
if has_ace and sum_cards + 10 <= 21:
return sum_cards + 10, sum_cards
return sum_cards, sum_cards
def add_one_card(self, deck):
self.cards.append(deck.get_one_card())
def hide_one_card(self, index):
self.cards[index].hide_it()
def expose_one_card(self, index):
self.cards[index].expose_it()
def get_all_cards(self):
return self.cards
GameFunctions
● new_game(): Initializes a new game, sets up the deck, and deals cards to the player and dealer
def new_game():
global message_upper, message_lower, state, deck, dealer_hand,
player_hand
message_upper = 'This is a new round.'
message_lower = 'Hit or stand?'
state = 'running'
deck = Deck()
dealer_hand = Hand()
player_hand = Hand()
for i in range(2):
dealer_hand.add_one_card(deck)
player_hand.add_one_card(deck)
dealer_hand.hide_one_card(0)
draw_handler(canvas): Draws the game state on the canvas, including the score, dealer’s and player’s hands, and messages..
def draw_handler(canvas):
canvas.draw_text('BlackJack', (225, 80), 80, 'Black')
canvas.draw_text('BlackJack', (225 - FONT_OFFSET, 80 - FONT_OFFSET), 80, 'Blue')
canvas.draw_polygon([[TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1] + 120],
[TABLE_UPPER_LEFT_CORNER[0], TABLE_UPPER_LEFT_CORNER[1] + 120],
TABLE_UPPER_LEFT_CORNER,
[TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1]]],
2, 'Yellow')
canvas.draw_line((TABLE_UPPER_LEFT_CORNER[0], TABLE_UPPER_LEFT_CORNER[1] + 80),
(TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1] + 80), 2, 'Yellow')
canvas.draw_line((TABLE_UPPER_LEFT_CORNER[0], TABLE_UPPER_LEFT_CORNER[1] + 40),
(TABLE_UPPER_LEFT_CORNER[0] + 200, TABLE_UPPER_LEFT_CORNER[1] + 40), 2, 'Yellow')
canvas.draw_line((TABLE_UPPER_LEFT_CORNER[0] + 130, TABLE_UPPER_LEFT_CORNER[1] + 40),
(TABLE_UPPER_LEFT_CORNER[0] + 130, TABLE_UPPER_LEFT_CORNER[1] + 120), 2, 'Yellow')
canvas.draw_text('Score', (TABLE_UPPER_LEFT_CORNER[0] + 60, TABLE_UPPER_LEFT_CORNER[1] + 35), 35, 'Black')
canvas.draw_text('Score', (TABLE_UPPER_LEFT_CORNER[0] + 60 - FONT_OFFSET,
TABLE_UPPER_LEFT_CORNER[1] + 35 - FONT_OFFSET), 35, 'Yellow')
canvas.draw_text('Dealer', (TABLE_UPPER_LEFT_CORNER[0] + 20, TABLE_UPPER_LEFT_CORNER[1] + 75), 35, 'Black')
canvas.draw_text('Dealer', (TABLE_UPPER_LEFT_CORNER[0] + 20 - FONT_OFFSET,
TABLE_UPPER_LEFT_CORNER[1] + 75 - FONT_OFFSET), 35, 'Red')
canvas.draw_text('Player', (TABLE_UPPER_LEFT_CORNER[0] + 20, TABLE_UPPER_LEFT_CORNER[1] + 113), 35, 'Black')
canvas.draw_text('Player', (TABLE_UPPER_LEFT_CORNER[0] + 20 - FONT_OFFSET,
TABLE_UPPER_LEFT_CORNER[1] + 113 - FONT_OFFSET), 35, 'Orange')
canvas.draw_text(str(score_dealer), (TABLE_UPPER_LEFT_CORNER[0] + 150, TABLE_UPPER_LEFT_CORNER[1] + 75), 35, 'Black')
canvas.draw_text(str(score_dealer), (TABLE_UPPER_LEFT_CORNER[0] + 150 - FONT_OFFSET,
TABLE_UPPER_LEFT_CORNER[1] + 75 - FONT_OFFSET), 35, 'Red')
canvas.draw_text(str(score_player), (TABLE_UPPER_LEFT_CORNER[0] + 150, TABLE_UPPER_LEFT_CORNER[1] + 115), 35, 'Black')
canvas.draw_text(str(score_player), (TABLE_UPPER_LEFT_CORNER[0] + 150 - FONT_OFFSET,
TABLE_UPPER_LEFT_CORNER[1] + 115 - FONT_OFFSET), 35, 'Orange')
canvas.draw_text('Dealer', (70, 150), 35, 'Black')
canvas.draw_text('Dealer', (70 - FONT_OFFSET, 150 - FONT_OFFSET), 35, 'Red')
canvas.draw_text('Player', (70, 400), 35, 'Black')
canvas.draw_text('Player', (70 - FONT_OFFSET, 400 - FONT_OFFSET), 35, 'Orange')
canvas.draw_text(message_upper, (150, 350), 50, 'Black')
canvas.draw_text(message_upper, (150 - FONT_OFFSET, 350 - FONT_OFFSET), 50, 'Yellow')
canvas.draw_text(message_lower, (30, 550), 35, 'Black')
canvas.draw_text(message_lower, (30 - FONT_OFFSET, 550 - FONT_OFFSET), 35, 'Orange')
cards_margin = 30
dealer_cards_line = 210
player_cards_line = 460
index_of_dealer_cards = 0
index_of_player_cards = 0
center_in_png = (CARD_WIDTH / 2.0, CARD_HEIGHT / 2.0)
for card in dealer_hand.get_all_cards():
index_rank = RANKS.index(card.get_rank())
index_color = COLORS.index(card.get_color())
if card.is_exposed():
canvas.draw_image(IMG_CARDS, (center_in_png[0] + index_rank * CARD_WIDTH,
center_in_png[1] + index_color * CARD_HEIGHT),
(CARD_WIDTH, CARD_HEIGHT),
(dealer_cards_line + CARD_WIDTH * index_of_dealer_cards + CARD_WIDTH / 2.0,
TABLE_UPPER_LEFT_CORNER[1] + CARD_HEIGHT / 2.0),
(CARD_WIDTH, CARD_HEIGHT))
else:
canvas.draw_image(IMG_CARDS, (center_in_png[0], center_in_png[1]),
(CARD_WIDTH, CARD_HEIGHT),
(dealer_cards_line + CARD_WIDTH * index_of_dealer_cards + CARD_WIDTH / 2.0,
TABLE_UPPER_LEFT_CORNER[1] + CARD_HEIGHT / 2.0),
(CARD_WIDTH, CARD_HEIGHT))
index_of_dealer_cards += 1
for card in player_hand.get_all_cards():
index_rank = RANKS.index(card.get_rank())
index_color = COLORS.index(card.get_color())
if card.is_exposed():
canvas.draw_image(IMG_CARDS, (center_in_png[0] + index_rank * CARD_WIDTH,
center_in_png[1] + index_color * CARD_HEIGHT),
(CARD_WIDTH, CARD_HEIGHT),
(player_cards_line + CARD_WIDTH * index_of_player_cards + CARD_WIDTH / 2.0,
TABLE_UPPER_LEFT_CORNER[1] + CARD_HEIGHT / 2.0),
(CARD_WIDTH, CARD_HEIGHT))
else:
canvas.draw_image(IMG_CARDS, (center_in_png[0], center_in_png[1]),
(CARD_WIDTH, CARD_HEIGHT),
(player_cards_line + CARD_WIDTH * index_of_player_cards + CARD_WIDTH / 2.0,
TABLE_UPPER_LEFT_CORNER[1] + CARD_HEIGHT / 2.0),
(CARD_WIDTH, CARD_HEIGHT))
index_of_player_cards += 1
hit(): Handles the player’s action to take another card. It updates the hand and checks for busts
def hit():
global message_upper, message_lower, state, score_player
if state != 'running':
return
player_hand.add_one_card(deck)
score_player, _ = player_hand.get_sum()
if score_player > 21:
message_upper = 'You busted! Dealer wins.'
message_lower = 'Game Over'
state = 'ended'
elif score_player == 21:
message_upper = 'You got 21! You win.'
message_lower = 'Game Over'
state = 'ended'
stand(): Handles the player’s decision to stop taking cards and lets the dealer play. It calculates the final scores and determines the winner.
def stand():
global message_upper, message_lower, score_player, score_dealer,
state
if state != 'running':
return
dealer_hand.expose_one_card(0)
score_dealer, _ = dealer_hand.get_sum()
while score_dealer 21:
message_upper = 'Dealer busts! You win.'
elif score_dealer == score_player:
message_upper = 'It\'s a tie.'
elif score_dealer > score_player:
message_upper = 'Dealer wins.'
else:
message_upper = 'You win.'
message_lower = 'Game Over'
state = 'ended'
mouseclick(pos): Handles mouse clicks to start a new game, hit, or stand based on the game state.
def mouseclick(pos):
global state
if state == 'ended':
if NEW_GAME_BUTTON_POS[0] <= pos[0] <= NEW_GAME_BUTTON_POS[0]
+ NEW_GAME_BUTTON_WIDTH and NEW_GAME_BUTTON_POS[1] <= pos[1] <=
NEW_GAME_BUTTON_POS[1] + NEW_GAME_BUTTON_HEIGHT:
new_game()
elif state == 'running':
if HIT_BUTTON_POS[0] <= pos[0] <= HIT_BUTTON_POS[0] +
HIT_BUTTON_WIDTH and HIT_BUTTON_POS[1] <= pos[1] <= HIT_BUTTON_POS[1]
+ HIT_BUTTON_HEIGHT:
hit()
elif STAND_BUTTON_POS[0] <= pos[0] <= STAND_BUTTON_POS[0] +
STAND_BUTTON_WIDTH and STAND_BUTTON_POS[1] <= pos[1] <=
STAND_BUTTON_POS[1] + STAND_BUTTON_HEIGHT:
stand()
Source Code :
import simplegui
import random
# Step 2: declare some global variables
CANVAS_SIZE = (740, 650)
IMG_CARDS = simplegui.load_image('http://commondatastorage.googleapis.com/codeskulptor-assets/cards.jfitz.png')
IMG_BACK = simplegui.load_image('http://commondatastorage.googleapis.com/codeskulptor-assets/card_back.png')
CARD_WIDTH = 73
CARD_HEIGHT = 98
RANKS = ('A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K')
COLORS = ('Club', 'Spade', 'Heart', 'Diamond')
VALUES = {'A': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10, 'J': 10, 'Q': 10, 'K': 10}
FONT_OFFSET = 2
TABLE_UPPER_LEFT_CORNER = (CANVAS_SIZE[0] - 200, CANVAS_SIZE[1] - 120)
score_dealer = 0
score_player = 0
message_upper = ''
message_lower = ''
state = 'stop' # There are 2 states: 'stop' and 'running'
deck = None
dealer_hand = None
player_hand = None
# Step 3: create 3 classes: Card, Deck, Hand
class Card:
def __init__(self, rank, color, exposed=True):
self.rank = rank
self.color = color
self.exposed = exposed
def __str__(self):
return "Rank is " + self.rank + ", Color is " + self.color + ", exposed is " + str(self.exposed)
def get_rank(self):
return self.rank
def get_color(self):
return self.color
def is_exposed(self):
return self.exposed
def expose_it(self):
self.exposed = True
def hide_it(self):
self.exposed = False
class Deck:
def __init__(self):
self.cards = []
for color in COLORS:
for rank in RANKS:
self.cards.append(Card(rank, color))
random.shuffle(self.cards)
def __str__(self):
for card in self.cards:
print(card)
return ""
def get_one_card(self):
return self.cards.pop()
def get_all_cards(self):
return self.cards
class Hand:
def __init__(self):
self.cards = []
def __str__(self):
for card in self.cards:
print(card)
return ""
def get_sum(self):
sum_cards = 0
has_ace = False
for card in self.cards:
sum_cards += VALUES[card.get_rank()]
if card.get_rank() == 'A':
has_ace = True
sum_max = sum_cards
sum_min = sum_cards
if has_ace:
if sum_cards + 10 21:
dealer_hand.expose_one_card(0)
score_dealer += 1
message_upper = 'You went bust and lose.'
message_lower = 'New deal?'
state = 'stop'
def btn_stand():
global score_dealer, score_player, message_upper, message_lower, state, dealer_hand, player_hand
if state != 'stop':
player_max, player_min = player_hand.get_sum()
play_sum = player_max if player_max <= 21 else player_min
dealer_sum = 0
while True:
dealer_max, dealer_min = dealer_hand.get_sum()
dealer_sum = dealer_max if dealer_max = 17:
break
else:
dealer_hand.add_one_card(deck)
dealer_hand.expose_one_card(0)
if dealer_sum > 21:
score_player += 1
message_upper = 'Dealer went bust and lose.'
message_lower = 'You win! New deal?'
state = 'stop'
else:
if dealer_sum < play_sum:
score_player += 1
message_upper = 'You win!'
message_lower = 'New deal?'
state = 'stop'
else:
score_dealer += 1
message_upper = 'You lose!'
message_lower = 'New deal?'
state = 'stop'
# Step 7: create a frame
frame = simplegui.create_frame('Blackjack', CANVAS_SIZE[0], CANVAS_SIZE[1], 150)
frame.set_canvas_background('Green')
# Step 8: register all event handlers
frame.set_draw_handler(draw_handler)
frame.add_button('Deal', btn_deal, 150)
frame.add_button('Hit', btn_hit, 150)
frame.add_button('Stand', btn_stand, 150)
# Step 9: start a new game
new_game()
# Step 10: start frame
frame.start()
Output :
Find More Projects
Build a Quiz Game Using HTML CSS and JavaScript Introduction Hello coders, you might have played various games, but were you aware …
Emoji Catcher Game Using HTML CSS and JavaScript Introduction Hello Coders, Welcome to another new blog. In this article we’ve made a …
Typing Challenge Using HTML CSS and JavaScript Introduction Hello friends, all you developer friends are welcome to our new project. If you …
Breakout Game Using HTML CSS and JavaScript With Source Code Introduction Hello friends, welcome to today’s new blog post. All of you …
Digital and Analog Clock using HTML CSS and JavaScript Introduction : This project is a digital clock and stopwatch system, which allows …
Coffee Shop Website using HTML, CSS & JavaScript Introduction : This project is a website for coffee house business. It uses HTML …