If the hand's total value is >21, then the Ace value should be treated as 1 (default at 11)
suits = ('Hearts', 'Diamonds', 'Spades', 'Clubs')
ranks = ('Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King', 'Ace')
value = {'Two':2, 'Three':3, 'Four':4, 'Five':5, 'Six':6, 'Seven':7, 'Eight':8, 'Nine':9, 'Ten':10, 'Jack':10,
'Queen':10, 'King':10, 'Ace':11}
class Card:
def __init__(self,suit,rank):
self.suit=suit
self.rank=rank
self.value=value[self.rank]
def __str__(self):
return self.rank " of " self.suit
class Deck:
def __init__(self):
self.deck=[]
for suit in suits:
for rank in ranks:
self.deck.append(Card(suit,rank))
def __str__(self):
for item in self.deck:
return '\n ' item.__str__()
return 'The deck has:' deck_comp
def shuffle(self):
random.shuffle(self.deck)
def deal(self):
return self.deck.pop()
class Hand:
def __init__(self):
self.cards = [] # start with an empty list as we did in the Deck class
self.value = 0 # start with zero value
def add_card(self,card):
self.cards.append(card)
self.value = card.value
while self.value > 21:
for card in self.cards:
if card.rank == 'Ace':
self.value -= 10
def __str__(self):
hand=''
for item in self.cards:
hand = '\n ' item.__str__()
return hand
Now I'm trying to test it by adding 2 10 cards and 1 Ace card (it should come up to 21):
deck = Deck()
playerhand = Hand()
computerhand = Hand()
deck.shuffle()
playerhand.add_card(Card('Spade','Ten'))
playerhand.add_card(Card('Heart','Ten'))
playerhand.add_card(Card('Spade','Ace'))
and it works fine. However if I try to add another Ace:
playerhand.add_card(Card('Club','Ace'))
The value comes to 12 (instead of 22). I think it's because after the first loop, the value is 22 which still >21 so the loop runs again. I have no idea how to fix this
CodePudding user response:
Try replacing your add_card()
method with:
def add_card(self,card):
self.cards.append(card)
self.value = 0
for card in self.cards:
self.value = card.value
if self.value > 21 and card.rank == 'Ace':
self.value -= 10
This way, you're recalculating the hand value each time a new card is dealt to the hand, so you don't "lose" the information that the value was previously reduced by 10 because an Ace was dealt into an otherwise busted hand.
Now try this:
playerhand.add_card(Card('Spade','Ten'))
print(playerhand.value)
playerhand.add_card(Card('Heart','Ten'))
print(playerhand.value)
playerhand.add_card(Card('Spade','Ace'))
print(playerhand.value)
playerhand.add_card(Card('Club','Ace'))
print(playerhand.value)
... and the output should be:
10
20
21
22
CodePudding user response:
I suggest making value
a property so it just gets computed when you need it; that way you don't need to worry about needing to sync it with self.cards
:
class Hand:
def __init__(self):
self.cards = []
def add_card(self,card):
self.cards.append(card)
def value(self):
v = sum(card.value for card in self.cards)
for card in self.cards:
if card.rank == 'Ace' and v > 21:
v -= 10
return v
def __str__(self):
return '\n'.join(map(str, self.cards))
This is a specific application of the general principle that the less long-lived state you have in your program, the fewer opportunities you have for that state to go "bad" in some way.
Note that it gets a little simpler if you set ace's default value to 1:
value = {
'Ace':1, 'Two':2, 'Three':3, 'Four':4, 'Five':5, 'Six':6, 'Seven':7,
'Eight':8, 'Nine':9, 'Ten':10, 'Jack':10, 'Queen':10, 'King':10
}
...
def value(self):
v = sum(card.value for card in self.cards)
if v <= 11 and any(card.rank == 'Ace' for card in self.cards):
v = 10
return v
because if you have multiple aces, you will only want to count one of them (at most) as 11, so you only need to check if there are any aces (and maybe add 10 if there are) rather than counting all the aces and potentially subtracting 10 from each of them.