More Practice with Python
After completing Automate The Boring Stuff, and while reading Learning Python 3 The Hard Way, I decided to tackle a few simple projects on my own. Below is a selection of the more involved projects that I completed.
Blackjack
Though admittedly I don’t know the rules of blackjack that well so there is likely so weird things . This program was exciting for me because it was the first experience with creating a program using object oriented design(OOP). I had previously made a blackjack game program using basic procedural techinques so. I really do think that the OOP design really. Especially it helped prevent repeated code for the player and dealer actions. Though as always looking back there are some structures that I would like to change. For instance, could inherit a method for firstDraw(), which defines the initial hand cards, from a parent abstract class that contains information used by both the player and the dealer
#! python3
#blackJacks_oop.py -
import random, logging,time,sys
#Sets up logging
logging.basicConfig(level=logging.DEBUG, format='\t%(asctime)s.%(msecs)03d: %(message)s', datefmt='%H:%M:%S')
logging.disable(logging.DEBUG) # uncomment to block debug logging.debug messages
#logging.disable(logging.INFO) # uncomment to block debug logging.info messages and below
'------------------------------------------------------------------------------'
class cardDeck(object):
# Holds data about the deck of cards
cardDeck_list = [['1', 4],['2', 4],['3', 4],['4', 4],['5', 4],['6', 4],['7', 4],
['8', 4],['9', 4],['10', 4], ['j', 4], ['q', 4], ['k', 4],['a', 4]]
cardDeck_len = len(cardDeck_list) # 14
def cardDrawing(self):
cardDeck_list = self.cardDeck_list
cardDeck_len = self.cardDeck_len
while True:
randDraw = random.randint(0, cardDeck_len - 1) # generates random position number within range of desk cars
drawCard = cardDeck_list[randDraw][0] # gets card from deck
# Check that card is in deck
if cardDeck_list[randDraw][1] > 0:
break
# Remove assign cards from deck
cardDeck_list[randDraw][1] = cardDeck_list[randDraw][1] - 1
# calculate the total of those card
if drawCard == 'j' or drawCard == 'q' or drawCard == 'k':
cardValue = 10
elif drawCard == 'a':
cardValue = 11
else:
cardValue = int(drawCard)
return drawCard, cardValue
def resetDeck(self): # resets the
for i in self.cardDeck_list:
i[1] = 4
logging.debug(f'Reset cardDeck_list: {self.cardDeck_list}')
class Player(object):
playerCards = [] # a list to hold player's card
playerTotal = 0 # holds the pplayer's card total
logging.debug(f'playerTotal: {playerTotal}')
player_bustState = False # sets to true if player total goes over 21
player_blackJacksState = False # sets to true if player total equals 21
def __init__(self):
self.Deck = cardDeck()
def P_firstDraw(self): # Start hand: draws two cards from deck and assigns data to associated variables
for i in range(0,2):
p_DrawCard, p_CardValue = self.Deck.cardDrawing()
self.playerTotal += int(p_CardValue) # calculates player's total card value
self.playerCards.append(p_DrawCard) # asssigns random card draw to player card list
logging.debug(f'Player\'s Cards: {self.playerCards} Card Value: {self.playerTotal}')
print(f'Player\'s Cards: {self.playerCards} Card Value: {self.playerTotal}')
def P_HitHold(self): # after player and dealer draw starting hand the player decides if he would like to hold or hit taking another card from the deck and adding it to his hand
while True:
'------------------------------------------------------------------'
# Checks if Player card value is over 21
if self.playerTotal > 21:
logging.debug('Player BUST')
self.player_bustState = True
break
# Checks if player got blackjacks
if self.playerTotal == 21:
logging.debug('Player BLACKJACK')
self.player_blackJacksState = True
break
'------------------------------------------------------------------'
#ask player if they would like to hit or holds
hitHold_input = input("\nWould you like to hit or hold? ")
print()
while hitHold_input != 'hit' and hitHold_input != 'hold':
print("ERROR: must enter either 'hit' or hold:", end = ' ')
hitHold_input = input()
if hitHold_input == 'hit':
logging.debug('Player Hit')
#draws and adds card to player's hand and total
p_DrawCard, p_CardValue = self.Deck.cardDrawing()
self.playerTotal += int(p_CardValue)
self.playerCards.append(p_DrawCard)
logging.debug(f'Player Cards: {self.playerCards}')
logging.debug(f'Player Total: {self.playerTotal}')
logging.debug(f'Updated Card list: {self.Deck.cardDeck_list}')
print(f"You drew: {p_DrawCard}")
print(f"You currently hold {','.join(self.playerCards)} for a card total of {self.playerTotal}")
else:
logging.debug('Player Hold')
break
'------------------------------------------------------------------'
logging.debug(f"""self.player_bustState: {self.player_bustState}
self.player_blackJacksState: {self.player_blackJacksState}""" )
return self.player_bustState, self.player_blackJacksState,self.playerTotal
def P_resetHand(self): # sets the playerCards to an empty list and the playerTotal to 0
self.playerCards.clear()
self.playerTotal = 0
self.player_bustState = False # sets to true if player total goes over 21
self.player_blackJacksState = False
logging.debug(f'Reset Player Hand: {self.playerCards} Total: {self.playerTotal}')
class Dealer(object):
dealerCards = [] # a list to hold the dealer's cards
dealerTotal = 0 # holds the dealer's card total
dealer_bustState = False # sets to true if DEALER total goes over 21
dealer_blackJacksState = False # sets to true if DEALER total equals 21
def __init__(self):
self.Deck = cardDeck()
def D_firstDraw(self): # Start hand: draws two cards from deck and assigns data to associated variables
for i in range(0,2):
d_DrawCard, d_CardValue = self.Deck.cardDrawing()
self.dealerTotal += int(d_CardValue) # calculates Dealer's total card value
self.dealerCards.append(d_DrawCard) # asssigns random card draw to Dealer card list
dealer_faceCard = self.dealerCards[0]
logging.debug(f'Dealer\'s Cards: {self.dealerCards} Card Value: {self.dealerTotal}')
print(f"Dealer's face card: {dealer_faceCard}")
def D_finalDraw(self,playerBust, playerBlackjacks, playerTotal): # After the player has decided to hold dealer draws cards until dealerTotal is greater than the playerTotal or the dealer bust/gets blacksjacks
self.playerBust = playerBust
self.playerBlackjacks = playerBlackjacks
self.playerTotal = playerTotal
print(f'Dealer shows: {self.dealerCards} Total Card Value: {self.dealerTotal}')
logging.debug('D_finalDraw function called')
# If P.playerTotal is greater than or equal self.dealerTotal dealer must draw unit he bust or wins
logging.debug(f'playerBust: {playerBust} playerBlackjacks: {playerBlackjacks}' )
if playerBust == False and playerBlackjacks == False:
logging.debug(f'dealerTotal: {self.dealerTotal} playerTotal: {playerTotal}')
while self.dealerTotal < 21 and self.dealerTotal <= playerTotal:
logging.debug("drawing card")
d_DrawCard, d_CardValue = self.Deck.cardDrawing()
self.dealerTotal += int(d_CardValue)
self.dealerCards.append(d_DrawCard)
print(f"Dealer drew {d_DrawCard}: Dealer now has {self.dealerTotal}")
if self.dealerTotal > 21:
self.dealer_bustState = True
elif self.dealerTotal == 21:
self.dealer_blackJacksState = True
logging.debug(f"""dealer_bustState: {self.dealer_bustState}
dealer_blackJacksState: {self.dealer_blackJacksState}
dealerTotal: {self.dealerTotal}""")
return self.dealer_bustState, self.dealer_blackJacksState, self.dealerTotal
def D_resetHand(self): # sets the dealerCards to an empty list and the dealerTotal to 0
self.dealerCards.clear()
self.dealerTotal = 0
self.dealer_bustState = False
self.dealer_blackJacksState = False
logging.debug(f'Reset Dealer Hand: {self.dealerCards} Total: {self.dealerTotal}')
class GameEngine(object):
def __init__(self):
print('\nThis is a game of black jack. \n')
self.Deck = cardDeck()
self.P = Player()
self.D = Dealer()
def Play(self): # Main function for controlling the high level logic of the game
self.P.P_firstDraw()
self.D.D_firstDraw()
p_bustState, p_blackJacksState, p_playerTotal = self.P.P_HitHold()
d_bustState, d_blackJacksState, d_dealerTotal = self.D.D_finalDraw(p_bustState, p_blackJacksState, p_playerTotal)
self.endstate(p_bustState, p_blackJacksState, p_playerTotal, d_bustState, d_blackJacksState, d_dealerTotal)
self.playAgain()
def endstate(self, p_bust, p_blackjack, p_total, d_bust, d_blackjack, d_total): # takes data from self.Play() and decides the out come of the game
self.p_bust = p_bust
self.p_blackjack = p_blackjack
self.p_total = p_total
self.d_bust = d_bust
self.d_blackjack = d_blackjack
self.d_total = d_total
winState = False
logging.debug('END STATE')
# Checks the final winstate of the game
if d_bust == True:
winState = True
elif d_blackjack == True:
winState = False
elif d_total > p_total:
winState = False
elif p_bust == True:
winState = False
elif p_blackjack == True:
winState = True
elif p_total > d_total:
winState = True
else:
pass
# prints out win or lose statements
if winState == True:
print('\nWIN: You win')
else:
print('\nLOSE: You lose')
def playAgain(self): # ask the player if they would like to play again if 'y' resets variables to their start state(player/dealer hand empty and cardDeck has all the cards)
logging.debug('playAgain')
playAgain_input = input("\nWould you like to play again: ")
print()
# Error check that user input is valid
while playAgain_input != 'y' and playAgain_input != 'n':
print('ERROR; must enter either \'y\' or \'n\'.')
playAgain_input = input()
if playAgain_input == 'y': # reset game
self.Deck.resetDeck()
self.P.P_resetHand()
self.D.D_resetHand()
self.Play()
else: # exit game
print('DONE: Good bye')
quit()
# Main Call
if __name__ == '__main__':
G = GameEngine()
G.Play()