The casino package

Within your casino folder, create three files to house these. Name them hand.py, deck.py, and card.py.

In each one, paste in the code from the relevant class.

If you are using an IDE with syntax checking, you may notice a few errors. These are due to the now-missing imports.

In deck.py, ensure you have the following imports:

import random

from .card import Card

The random module is needed to shuffle our deck.

The Deck class also relies on having instances of our Card class, so we need to ensure we have access to it. We achieve this by using a relative import.

The relative import is indicated by a single or double dot in front of the module name. In this case, .card tells Python to import from a module named card, which is in the same directory as our deck.py file.

To fix our card.py file, ensure you have the following at the top of the file:

import os
from tkinter import PhotoImage

assets_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'assets/')

The os module will allow us to build the path to our assets_folder, which will live in this file for simplicity's sake.

The Player class will represent the user who is playing our game. We will use it to hold their hand of cards and control their money, as well as shorten certain function calls that are repeatedly used in the main flow of the game by utilizing Python's @property decorator:

from .hand import Hand


class Player:
def __init__(self):
self.money = 50
self.hand = Hand()

def add_winnings(self, winnings):
self.money += winnings

def can_place_bet(self, amount):
return self.money >= amount

def place_bet(self, amount):
self.money -= amount

def receive_card(self, card):
self.hand.add_card(card)

def empty_hand(self):
self.hand.cards = []

When initializing our Player, we need their hand and money. For simplicity we will start each player off with a fixed £50 of stake money. Their hand will be an instance of the Hand class, as expected.

If the player wins a round, they should receive the money that was bet. To achieve this, we use an add_winnings method, which increases their money attribute by the specified amount.

Before a player can place their share of the bet, we need to check whether they have sufficient funds. The can_place_bet method handles this by comparing the player's money total with the amount to bet against. We return whether or not the player has as much, or more, than the required bet.

In order to place a bet, we remove the needed amount from the player's total money.

The Hand instance assigned to the player will be managed via the Player instance. In order to add a card to the player's hand, we now need simply to call the Player class' receive_card method with the relevant Card instance.

To clear the Player class' hand between rounds, we have an empty_hand method.

Now we will use some class properties to streamline accessing the player's statistics from within the game logic:

@property
def score(self):
return self.hand.get_value()

@property
def is_over(self):
return self.hand.get_value() > 21

@property
def has_blackjack(self):
return self.hand.get_value() == 21

@property
def cards(self):
return self.hand.cards

Instead of calling get_value on the Hand instance every time, we can now get the player's score by accessing player.score.

We can remove the player_is_over method from our game logic by accessing player.is_over.

Similarly, the someone_has_blackjack method can be shortened by accessing the player.has_blackjack property from our Player instance.

Finally, the player's cards are accessed by player.cards.

With these changes, we no longer need to directly access any Hand instances from the game logic—all classes that need to affect a hand will now just deal with the player instances. This ensures that our game logic is as loosely coupled with our implementations of the casino elements as possible.

For the sake of naming clarity, we also define a Dealer class in this module. The Dealer will be a subclass of Player with no additional logic. This allows us to create an instance of a Dealer within our game logic, and if we decide that we want to add any dealer-specific functionality at a later date, we are already set up to do so:

class Dealer(Player):
pass

With these two classes, our casino modules are complete.

Now we need to make sure that we can import them easily when we need to use them in our main blackjack.py file. To do this, we simply need to create a file called __init__.py in our casino folder. Inside this file, type the following:

from .card import Card, assets_folder
from .deck import Deck
from .hand import Hand
from .player import Player, Dealer

These import statements don't appear to do anything in this file, but they will allow us to access each of these classes from the casino package's namespace. This means we do not need to know about the internal file structure used by our casino package in order to use its classes.

In practical terms, this means we only need to type from casino import Deck instead of from casino.deck import Deck.

Just like that, our casino package is finished! We now have a simple, reusable collection of classes that emulate various aspects of a real-life casino.

There is just one more package that we will need to make: the casino_sounds. This will be a simple package containing a class that makes playing audio clips easy.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset