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 …

Get Huge Discounts
More Python Projects

All Coding Handwritten Notes