The GameState class

We will put the code which needs to run at the beginning of any game into the GameState __init__ method. This code will then run any time we make a new game:

class GameState:
def __init__(self):
self.deck = Deck()
self.deck.shuffle()

self.player_hand = Hand()
self.dealer_hand = Hand(dealer=True)

for i in range(2):
self.player_hand.add_card(self.deck.deal())
self.dealer_hand.add_card(self.deck.deal())

self.has_winner = ''

Inside the __init__ method, we create and shuffle our Deck, assign a Hand to our player and dealer, and initialize the winner as nobody (using an empty string).

Our player_is_over method now sits in this class. Copy it over if you are using a new file.

We will slightly modify our old check_for_blackjack function, and rename it someone_has_blackjack to signify the difference:

def someone_has_blackjack(self):
player = False
dealer = False
if self.player_hand.get_value() == 21:
player = True
if self.dealer_hand.get_value() == 21:
dealer = True

if player and dealer:
return 'dp'
elif player:
return 'p'
elif dealer:
return 'd'

return False

Since we no longer are using a terminal window to display results, there is no longer any need for the previous calls to the print function.

As graphical displaying of information to the user is now separate from the game logic, we need to indicate to the caller of this function which contestant (if any) is the one with blackjack. We use a simple string to indicate this information: d for the dealer, p for the player, and dp for both.

If nobody has blackjack, then we will just return False. This allows the results of this method to be treated as a Boolean and used in the condition of an if statement.

Now we will need a way for the player to add cards to their hand when they choose to hit.

When the player chooses to hit, we will call the hit method from this class. The body of this method is much like it was in the previous chapter:

def hit(self):
self.player_hand.add_card(self.deck.deal())
if self.someone_has_blackjack() == 'p':
self.has_winner = 'p'
if self.player_is_over():
self.has_winner = 'd'

return self.has_winner

We add a card to the user's hand with the familiar add_card method, called with the Deck class' deal method as an argument.

Since their hand's value has changed, we should check for blackjack. We use the someone_has_blackjack method and check if it returns the p string indicating that the player's hand is worth 21. If it is, we assign this p string to our has_winner attribute to indicate that the game has finished and the player has won.

We should also check if the player is now over 21. If so, we assign the d string to our has_won attribute to indicate that the dealer has won this round.

Between each hit, we need to send information about the table's state over to our graphical GameScreen class so that the board can be drawn and shown to the user.

We will represent the board state using a simple dictionary.

The GameScreen will need to know:

  • The cards in the player's hand
  • The cards in the dealer's hand
  • If there is a winner or not
  • If the winner has blackjack or not

We will need a method to obtain this dictionary, which we will call get_table_state:

def get_table_state(self):
blackjack = False
winner = self.has_winner
if not winner:
winner = self.someone_has_blackjack()
if winner:
blackjack = True
table_state = {
'player_cards': self.player_hand.cards,
'dealer_cards': self.dealer_hand.cards,
'has_winner': winner,
'blackjack': blackjack,
}

return table_state

We will use a Boolean to store whether a user has blackjack.

The winner will be represented by the use of a string, d for the dealer, p for the player, and dp for a tie. This is all handled by the someone_has_blackjack method from before.

Before checking for blackjack, we will see if our has_winner attribute contains a winner string already. If so, the player has gone over 21 and so there's no need to check for blackjack.

We do not need to check whether the player has over 21 in this method, as the initial deal cannot produce a hand of more than 21, and there is already a call to player_is_over in the hit method.

Once we have determined whether or not we have a winner, we can begin building our return dictionary, which will be used by the GameScreen class.

The player's and dealer's cards are accessed via their attributes in this class.

When the player chooses to stick with their hand, then the game enters the final state. This means there will be no more changes to the cards in the player's hand, and so we will need to compare their score with the dealer's and determine a final winner:

def calculate_final_state(self):
player_hand_value = self.player_hand.get_value()
dealer_hand_value = self.dealer_hand.get_value()

if player_hand_value == dealer_hand_value:
winner = 'dp'
elif player_hand_value > dealer_hand_value:
winner = 'p'
else:
winner = 'd'

table_state = {
'player_cards': self.player_hand.cards,
'dealer_cards': self.dealer_hand.cards,
'has_winner': winner,
}

return table_state

In order to obtain the final state, we first obtain both the player's and the dealer's score from our attributes. We now need to compare them to see which is higher.

We do not need to check for a loss or blackjack here since this is checked after each time the player decides to hit.

If the player and the dealer have the same value in their hand, the winner is assigned as the string dp.

If the player has a higher score, the winner becomes p.

If the dealer has the larger hand, we use the string d.

We now pass this information over as a dictionary, very similar to the get_table_state method, so that it can be used by the GameScreen class in the same way.

The final piece of information the GameScreen will need from the GameState is the player's score. This will be displayed as text on our canvas. Since this is stored as an integer, we need to convert it to a string before it can be displayed:

def player_score_as_text(self):
return "Score: " + str(self.player_hand.get_value())

We concatenate the word Score: to the player's hand value so that the GameScreen can just display all of the text returned by this method. This also tells the user what they are looking at, as a number by itself on the screen may not be all that self explanatory.

Now that we have completed the class which will hold all of the information about our game state and logic, we can move on to displaying our graphical elements.

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

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