I'm new to Python and coding in general and am trying to create a blackjack game in Python but I'm having trouble getting the point counter point_selection
to update based on the card values in the player's hand:
deck_points = {2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10, 'J' : 10, 'Q'
: 10, 'K' : 10, 'A' : 11 }
dealer_hand = []
player_hand = []
dealer_points = 0
player_points = 0
def deal_initial_cards(hand, point_selection):
for i in range(2):
i = random.choice(list(deck_points))
hand.append(i)
for card in hand:
point_selection = deck_points[card]
deal_initial_cards(dealer_hand, dealer_points)
print(dealer_points)
Using the above code, the counter never updates past '0' and I'm not sure what I'm doing wrong. Any help is appreciated.
CodePudding user response:
Python ints are immutable, this means dealer_points
isn't updated. Initialy they have the same id(use id()
), but when you change the variable inside the function it creates a new variable. To fix your code you need to do something like
deck_points = {2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10, 'J' : 10, 'Q'
: 10, 'K' : 10, 'A' : 11 }
dealer_hand = []
player_hand = []
dealer_points = 0
player_points = 0
def deal_initial_cards(hand, point_selection):
for i in range(2):
i = random.choice(list(deck_points))
hand.append(i)
for card in hand:
point_selection = deck_points[card]
return point_selection
dealer_points = deal_initial_cards(dealer_hand, dealer_points)
print(dealer_points)
whereas a list, which you probably noticed, is mutable. This means the list inside the function stays the same(keeps its id) even when its edited.
CodePudding user response:
Here's a more Pythonic solution that fixes your main bug about your function deal_initial_cards()
operating on a copy of its (immutable) int argument point_selection
then throwing away the result, since it doesn't have a return point_selection
(or store the result in a class member self.points
). (Also, I made all your dict keys strings: '2','3',.... It's usually customary to represent '10' as 'T' to make all cards a single letter).
But since you're essentially declaring a Hand
class, then instantiating two objects of it (dealer_hand
, player_hand
). deal_initial_cards()
is essentially a Hand._init__()
in disguise, so we have a data member cards
(best not to also call it hand
). See how simple and clean ph = Hand()
is; no need for globals. Moreover, we could statically compute points
inside the __init__()
function and return it (or, better, store it in self.points
inside each hand object), but that would be a bad decomposition, since if we subsequently add cards to self.cards
, points wouldn't get updated. So, much more Pythonic is to make points
a property
of the class. We then access it
without parentheses: dh.points
, not dh.points()
. Last, note the use of a list comprehension (instead of a for-loop-append) to generate self.hand
. And inside points()
, note the use of a generator expression deck_points[card] for card in self.cards
, again more Pythonic than for-loop counter. So this small example is a great showcase of Python idiom and decomposition. We can add a __str__()
method to Hand. (You could also have a Card
class, but really that would be overkill.)
import random
deck_points = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'T': 10, 'J' : 10, 'Q'
: 10, 'K' : 10, 'A' : 11 }
# No globals, so no need to initialize anything
class Hand:
def __init__(self):
self.cards = [random.choice(list(deck_points)) for _ in range(2)]
@property
def points(self):
return sum(deck_points[card] for card in self.cards)
def __str__(self, join_char=''):
return join_char.join(card for card in self.cards)
#deal_initial_cards(dealer_hand, dealer_points)
ph = Hand()
dh = Hand()
print('Dealer: ', end='')
print(dh.points)
print('Player: ', end='')
print(ph.points)