Hello all,

I am working on a Blackjack program, but am having a bit of trouble with the finer details.

At the moment, I have a list of the cards and their values, as follows:

Jack = 10
Queen = 10
King = 10
Ace = 11
# card list
cards = [2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace]

This allows the calculations later on in the program to do their bit, which is fine.
However, at the moment I get this:

Dealer has [2, 10, 10] for a total of 22
--> The Dealer is busted!

So, currently it's displaying the number 10 for the Royal cards, because that's what's been assigned to it.
Fair enough.
But instead of displaying a 10 for the Royal cards, I want it to just display J, Q or K for the Royal cards, and A for the final card.

How do I go about doing that?

Thanks

Tristan

Edited 5 Years Ago by tristanbacon: n/a

How are you designating the cards, numbers 1-52, or value and suit (10Heart)?. You can use one of the following depending on how the cards are kept:

# two related lists 
cards = [2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace]
cards_name=['2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace']
#
# a list of tuples
cards=[(2. '2'), (3, '3') --> (10, 'Jack'), (10, 'Queen'), (10, 'King'), (11, 'Ace')]
print "value=%s, name=%s"  (cards[0]. cards[1])
#
# a dictionary
cards_dict={}
cards_dict['2']=2
cards_dict['Ace']=11

Edited 5 Years Ago by woooee: n/a

woooee's list of tuples is quite similar to what I went with, another method would be to create a hand class and have a method to check the hand for face cards and add their values to some variable and check that total maybe something like:

class class Hand(object):
    """A black jack hand"""
    def __init__(self, cards, player,hand_val=0):
        self.cards=cards
        self.total_check(cards)
        hand_val=0
        self.player=player
    """Check the value of the hand"""
    def total_check(self, cards):
        self.hand_val=0
        for card in cards:
            if card == 'A':
                card=11
                self.hand_val+=card
            if card=='J' or card=='K' or card=='Q':
                card=10
                self.hand_val+=card
            else:
                self.hand_val+=card
        if self.hand_val>21:
            self.bust()
        else:
            self.hit_or_stay()

    def bust(self):
        print(self.cards,'=',self.hand_val,'\n', self.player,'busted!')
       
    def hit_or_stay(self):
        print('\nCurrent hand:', self.cards,'=',self.hand_val)#remember that self.cards will show the strings A J K Q
        choice=input('Would you like to hit or stay?: ')
        choice=choice.lower()
        if choice=='hit':
            self.hit()
        else:#would not actually be my first choice but I'm trying to make a point
            self.compare()
##main##        
hand=(1,'K')
player='person'
Hand(hand,player)

And in the main part of the program, or another class, depending on your style and needs, assign the hand...blah blah blah.

Edited 5 Years Ago by pyguy62: too tired...syntax error

Thanks for your replies guys - much appreciated!

I've only just started out with Python, and so my knowledge is somewhat limited.

@woooee - your suggestions is exactly the kind of thing I was looking for, but I just wasn't sure how to assign it. I tried lots of different methods, but it kept spitting out error about being unable to call strings or something. So thank you for that!

I'll try out the two related lists one first, but at some point I'll need to look at converting that into the four different suits. Perhaps the list of tuples would be more relevant? Based on that, I could probably find a way to limit the amount of cards to however many decks I want to add (probably 2 decks), so that there are only 104 cards. Once they go down after however many hands, the computer will then 'reshuffle'.
But equally, that will mean that I have to take the random selection element out of the code, because at the moment, it just randomly chooses a card from the list, with complete disregard for whether it's been dealt 4 times already. The aim is to make this a realistic game, which can be later converted into a 3D minigame for the online casino project I'm working on. (More on that later ;-) )

@pyguy62 - the only reason I'm not going to use your method is because I really don't understand it... I'm not sure which method is better, but perhaps I could integrate it at some point later, if it is in fact better. What are the advantages of using your method? Would it be easier to implement the 104 card deck system that I mentioned above?

For your reference, I've decided to post the code, so you know where I'm coming from:

# BlackJack
# Unitled Project
# Copyright 2011 Boomerang Studios


from random import choice as rc
import time

def total(hand):
    # how many aces in the hand
    aces = hand.count(Ace)
    # to complicate things a little the ace can be 11 or 1
    # this little while loop figures it out
    t = sum(hand)
    # gone over 21 but there is an ace
    if t > 21 and aces > 0:
        while aces > 0 and t > 21:
            # this will switch the ace from 11 to 1
            t -= 10
            aces -= 1
    return t

Jack = 10
Queen = 10
King = 10
Ace = 11
# card list
cards = [2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace]


cwin = 0  # dealer win counter
pwin = 0  # player win counter
name = raw_input("Good evening Sir, what's your name? ")
print
print "Welcome to the Untitled Casino,",name
print
print
time.sleep(2)
while True:
    player = []
    print "The Dealer is dealing your cards..."
    # draw 2 cards for the player to start
    player.append(rc(cards))
    player.append(rc(cards))
    pbust = False  # player busted flag
    cbust = False  # dealer busted flag
    while True:
        # loop for the player's play ...
        tp = total(player)
        time.sleep(1)
        print "You've been dealt %s, which totals %d" % (player, tp)
        if tp > 21:
            print "--> Bust!"
            pbust = True
            break
        elif tp == 21:
            print "BLACKJACK!!!"
            break
        else:
            time.sleep(1)
            hs = raw_input("Hit or Stand (H or S): ").lower()
            print
            if 'h' in hs:
                player.append(rc(cards))
            else:
                break
    while True:
        # loop for the dealer's play ...
        comp = []
        comp.append(rc(cards))
        comp.append(rc(cards))
        
        # dealer generally stands around 17 or 18
        while True:
            tc = total(comp)                
            if tc < 18:
                comp.append(rc(cards))
               
            else:
                break
        time.sleep(1)    
        print "Dealer has %s for a total of %d" % (comp, tc)
        # now figure out who won ...
        if tc > 21:
            time.sleep(1)
            print "--> The Dealer is busted!"
            cbust = True
            if pbust == False:
                time.sleep(1)
                print "You win!"
                pwin += 1
        elif tc > tp:
            time.sleep(1)
            print "Dealer wins.."
            cwin += 1
        elif tc == tp:
            time.sleep(1)
            print "It's a draw!"
        elif tp > tc:
            if pbust == False:
                time.sleep(1)
                print "You win!"
                pwin += 1
            elif cbust == False:
                time.sleep(1)
                print "Dealer wins.."
                cwin += 1
        break
    print
    print "Score:", name," = %d  House = %d" % (pwin, cwin)
    time.sleep(1)
    exit = raw_input("Play another hand? (Y/N) -> ").lower()
    if 'n' in exit:
        break
    else:
        print
        time.sleep(0.5)
        print"Very well..."
        print
        print
        print
        time.sleep(1)
        print "New Hand"
        print
        print
        time.sleep(2)
print
print "Thanks for playing BlackJack at the currently unnamed Casino!"

How exactly do I go about implementing the dictionary version? I did this:

# card dictionary
cards_dict={}
cards_dict['2']=2
cards_dict['3']=3
cards_dict['4']=4
cards_dict['5']=5
cards_dict['6']=6
cards_dict['7']=7
cards_dict['8']=8
cards_dict['9']=9
cards_dict['10']=10
cards_dict['Jack']=10
cards_dict['Queen']=10
cards_dict['King']=10
cards_dict['Ace']=11

and changed all of the

append(rc(cards))

to

append(rc(cards_dict))

But I got this error, and I have no idea what it means:

Traceback (most recent call last):
  File "C:\Users\admin\Python Development\Various Projects\Casino\BlackJack.py", line 51, in <module>
    player.append(rc(cards_dict))
  File "C:\Python27\lib\random.py", line 274, in choice
    return seq[int(self.random() * len(seq))]  # raises IndexError if seq is empty
KeyError: 11
>>>

Any idea what that's about? All of sudden, it's thrown up an error in the one of the core Python files...

deck= [(value, suit) for value in values for suit in suits)] 
random.shuffle(deck)

dictionary is not appropriate, use list.

Edited 5 Years Ago by pyTony: n/a

there are quicker ways to do it, but I prefer something like what I have below to do it step-by-step:

suit=['c', 'd', 'h', 's']
vals=[1,2,3,4,5,6,7,8,9,10,'J','Q','K','A']
deck=[]
for st in suit:
    for val in vals:
        card=str(val)+str(st)
        deck.append(card)
import random
random.shuffle(deck)
hand=deck[0:2]

Now I believe you said you want a double deck, and while there are several other ways to do this, since you're new I'd suggest doing it step-by-step to get the feel

suit=['c', 'd', 'h', 's']
vals=[1,2,3,4,5,6,7,8,9,10,'J','Q','K','A']
deck1=[]
deck2=[]
deck=[]
for st in suit:
    for val in vals:
        card=str(val)+str(st)
        deck1.append(card)
deck2=deck1[:]#this means make a copy of deck1 as opposed to just pointing at it.
deck1.append(deck2)#    <
deck.append(deck1)#     <not both of these are necessary, one is enough but it makes things clearer for learning to me. 
import random
random.shuffle(deck)
hand=deck[0:2]
deck.pop(0)
deck.pop(1)
random.shuffle(deck)

Edited 5 Years Ago by pyguy62: expand

it sounds like you probably haven't learned how to use classes or OOP yet, when you do get there the benefits are that you need less Global variables and you have a reusable class to use for other players or the computer and that using the deck that way makes it easier to recreate the deck after it's expended.

and I just realized there's a typo in my code from last night. It would be class Hand not class class hand.

there are quicker ways to do it, but I prefer something like what I have below to do it step-by-step:

suit=['c', 'd', 'h', 's']
vals=[1,2,3,4,5,6,7,8,9,10,'J','Q','K','A']
deck=[]
for st in suit:
    for val in vals:
        card=str(val)+str(st)
        deck.append(card)
import random
random.shuffle(deck)
hand=deck[0:2]

Now I believe you said you want a double deck, and while there are several other ways to do this, since you're new I'd suggest doing it step-by-step to get the feel

suit=['c', 'd', 'h', 's']
vals=[1,2,3,4,5,6,7,8,9,10,'J','Q','K','A']
deck1=[]
deck2=[]
deck=[]
for st in suit:
    for val in vals:
        card=str(val)+str(st)
        deck1.append(card)
deck2=deck1[:]#this means make a copy of deck1 as opposed to just pointing at it.
deck1.append(deck2)#    <
deck.append(deck1)#     <not both of these are necessary, one is enough but it makes things clearer for learning to me. 
import random
random.shuffle(deck)
hand=deck[0:2]
deck.pop(0)
deck.pop(1)
random.shuffle(deck)

Ok, thanks for that.
How would I actually go about adding that to my code? The issue I'm having is that I've barely been able to get to the level the current code is now. Now, I've realised I need to improve it a lot, in terms of depth, but I haven't got the first clue how.
And with the code you've suggested, I'm not sure how I would add it in, while making sure it fits in correctly with what I have...

You've been great so far, thanks!!

Here is one old Python 2 experiment of mine, if you want to use it for inspiration. Probably better to refresh your knowledge of generators

import random
from itertools import islice
from pprint import pprint

valuecode={14:'A',13:'K',12:'Q',11:'J',10:'T'}
for i in range(2,10):
    valuecode[i] = str(i)

def dealer(deck):
    while deck:
        yield deck.pop()

def gethands(dealer):
    while dealer:
        cards = sorted(islice(dealer,5))
        if len(cards) == 5:
            yield cards
        else:
            break

def cardcode(value,suit):
    return suit[0].upper()+valuecode[value]

def codedhand(cards):
    return ', '.join(cardcode(*card) for card in cards)

def newdeck():
    ## cards with ace as more high value 14
    deck = [(value,suit)
              for suit in ('heart','diamonds','spade','club')
              for value in range(2,15)]
    random.shuffle(deck)
    return deck

if __name__== '__main__':
    deck = newdeck()
    get_card = dealer(deck)
    number_of_players = 6
    cards_each = 5
    # initialize hand for each
    player_hands = [[next(get_card) for count in range(cards_each)]
                         for player_count in range(number_of_players)]
    pprint(player_hands)
    # generate the full five hands
    for hand in gethands(get_card):
        print '\nYour sorted by value hand is %s.' % codedhand(hand)
        print 'Cards in suit order are: %s.' %  codedhand(sorted(hand, key=lambda x: x[1]))

    deck = newdeck()
    print '\nNext three cards of new deck are:', codedhand(next(dealer(deck)) for _ in range(3))
    print '%i cards left in deck.' % len(deck)

Edited 5 Years Ago by pyTony: n/a

Without using classes, which would really make your project MUCH easier, you would need to remember to define the global variables in each function as I did below, start from there.

suit=['c', 'd', 'h', 's']
vals=[1,2,3,4,5,6,7,8,9,10,'J','Q','K','A']
deck=[]
deck2=[]
hand=''
def make_deck(deckname):
    global suit
    global vals
    for st in suit:
        for val in vals:
            card=str(val)+str(st)
            deckname.append(card)
make_deck(deck)
make_deck(deck2)
for card in deck2:
    deck.append(card)
import random
random.shuffle(deck)


def deal():
    global hand
    global deck
    dealt_cards=deck[0:2]
    hand=dealt_cards
    deck.pop(0)
    deck.pop(0)

def give(hand):
    global deck
    hit_card=deck[0]
    hand.append(hit_card)
    deck.pop(0)

"""You could test it with"""
print(hand,'\n')
deal()
print(hand)
print('')
give(hand)
print(hand)

It's important when starting a project as a beginner to remember that you may have done something that isn't compatible with your goal "which is why it's important to test your code very often during the process and understand the Error if one is thrown. Don't get caught up on what you already have, remember your goal and moreover remember that the real goal is learning, so that you really get the concept and what can and, likely will go wrong with it and how to fix it or work around it.

Using global is bad style and needed only if variable is used at left hand side of assignment in function, aces were doubled in pyguy's deck:

import random # put imports first

suit = ['c', 'd', 'h', 's']
vals = [2,3,4,5,6,7,8,9,10,'J','Q','K','A'] # doubled Ace removed

def make_deck(deckname):
    for st in suit:
        for val in vals:
            card=str(val)+str(st)
            deckname.append(card)
            
def deal(deck):
    # it is more efficient to deal from end of list
    return deck.pop(), deck.pop()

def give(deck, hand):
    hand.append(deck.pop())

def show_hand(hand):
    print('Cards in hand: %s' % hand)

# lines only run when run directly, not imported
if __name__ == '__main__':
    deck=[]
    deck2=[]
    hand=[]

    make_deck(deck)
    make_deck(deck2)
    double_deck = deck + deck2
        
    random.shuffle(double_deck)
    # this assertion showed the bug of doubled Aces
    assert len(double_deck) == 104

    cards = deal(double_deck)
    print(cards)

    give(double_deck, hand)
    show_hand(hand)
    
    give(double_deck, hand)
    show_hand(hand)

    print('Cards left in double deck: %i' % len(double_deck))

For efficiency top of deck is considered to be last card in the list.

Edited 5 Years Ago by pyTony: n/a

@pyTony maybe you can help me, I was trying to utilize classes for this and it usually works but periodically I get the Error::

Traceback (most recent call last):
  File "E:\Cardgame\stuff.py", line 88, in <module>
    hand.total_check(hand.cards)
  File "E:\Cardgame\stuff.py", line 35, in total_check
    if card[0]=='J' or card[0]=='K' or card[0]=='Q':
TypeError: 'int' object is not subscriptable

The code so far is

suit=['c', 'd', 'h', 's']
vals=[2,3,4,5,6,7,8,9,10,'J','Q','K','A']
deck=[]
for st in suit:
    for val in vals:
        card=str(val)+str(st)
        deck.append(card)
import random
random.shuffle(deck)
hand=deck[0:2]
deck.pop(0)
deck.pop(0)
random.shuffle(deck)
class Hand(object):
    """A blackjack hand"""
    def __init__(self, cards, player,hand_val=0):
        self.cards=cards
        hand_val=0
        self.player=player
    """Check the value of the hand"""
    def recieve(self, card):
        self.cards.append(card)
        self.total_check(self.cards)
        
    def total_check(self, cards):
        self.hand_val=0
        for card in cards:
            card=str(card)
            if card[0] == 'A':
                card=11
                self.hand_val+=card
            if card[0]=='J' or card[0]=='K' or card[0]=='Q':
                card=10
                self.hand_val+=card
            else:
                card=int(card[0])
                if card==1:
                    card=10
                self.hand_val+=card
        if self.hand_val>21:
            self.bust()
        else:
            self.hit_or_stay()

    def bust(self):
        print(self.cards,'=',self.hand_val,'\n', self.player,'busted!')
       
    def hit_or_stay(self):
        print('\nCurrent hand:', self.cards,'=',self.hand_val)#remember that self.cards will show the strings A J K Q
        choice=input('Would you like to hit or stay?: ')
        choice=choice.lower()
        if choice=='hit':
            deck.give()
        else:#would not actually be my first choice but I'm trying to make a point
            print(self.hand_val)
            import random
            enemy=random.randint(16,21)
            if self.hand_val>enemy:
                print('Player:',self.hand_val,'\nComputer:',enemy,' Player Wins!')
            elif self.hand_val==enemy:
                print('Push')
            else:
                print('Player:',self.hand_val,'\nComputer:',enemy,' Computer Wins :(')
        

class Deck(object):
    def __init__(self, deck):
        self.deck=deck
    def give(self):
        togive=self.deck[0]
        self.deck.pop(0)
        hand.recieve(togive)
       
        

        
       
deck=Deck(deck)
name=input('Enter Your Name: ')
hand=Hand(hand,name)
hand.total_check(hand.cards)

If the OP would post the code for creating the 52 card deck it would yield better/more answers as the logic depends on how the deck it formatted.

player.append(rc(cards))

Note also, that random choice can return the same item/card multiple times. Use random.shuffle(card_deck) and deal the (now randomly arranged) cards in order.

Edited 5 Years Ago by woooee: n/a

@pyTony maybe you can help me, I was trying to utilize classes for this and it usually works but periodically I get the Error::

Traceback (most recent call last):
  File "E:\Cardgame\stuff.py", line 88, in <module>
    hand.total_check(hand.cards)
  File "E:\Cardgame\stuff.py", line 35, in total_check
    if card[0]=='J' or card[0]=='K' or card[0]=='Q':
TypeError: 'int' object is not subscriptable

The code so far is

suit=['c', 'd', 'h', 's']
vals=[2,3,4,5,6,7,8,9,10,'J','Q','K','A']
deck=[]
for st in suit:
    for val in vals:
        card=str(val)+str(st)
        deck.append(card)
import random
random.shuffle(deck)
hand=deck[0:2]
deck.pop(0)
deck.pop(0)
random.shuffle(deck)
class Hand(object):
    """A blackjack hand"""
    def __init__(self, cards, player,hand_val=0):
        self.cards=cards
        hand_val=0
        self.player=player
    """Check the value of the hand"""
    def recieve(self, card):
        self.cards.append(card)
        self.total_check(self.cards)
        
    def total_check(self, cards):
        self.hand_val=0
        for card in cards:
            card=str(card)
            if card[0] == 'A':
                card=11
                self.hand_val+=card
            if card[0]=='J' or card[0]=='K' or card[0]=='Q':
                card=10
                self.hand_val+=card
            else:
                card=int(card[0])
                if card==1:
                    card=10
                self.hand_val+=card
        if self.hand_val>21:
            self.bust()
        else:
            self.hit_or_stay()

    def bust(self):
        print(self.cards,'=',self.hand_val,'\n', self.player,'busted!')
       
    def hit_or_stay(self):
        print('\nCurrent hand:', self.cards,'=',self.hand_val)#remember that self.cards will show the strings A J K Q
        choice=input('Would you like to hit or stay?: ')
        choice=choice.lower()
        if choice=='hit':
            deck.give()
        else:#would not actually be my first choice but I'm trying to make a point
            print(self.hand_val)
            import random
            enemy=random.randint(16,21)
            if self.hand_val>enemy:
                print('Player:',self.hand_val,'\nComputer:',enemy,' Player Wins!')
            elif self.hand_val==enemy:
                print('Push')
            else:
                print('Player:',self.hand_val,'\nComputer:',enemy,' Computer Wins :(')
        

class Deck(object):
    def __init__(self, deck):
        self.deck=deck
    def give(self):
        togive=self.deck[0]
        self.deck.pop(0)
        hand.recieve(togive)
       
        

        
       
deck=Deck(deck)
name=input('Enter Your Name: ')
hand=Hand(hand,name)
hand.total_check(hand.cards)

When you process Ace:

if card[0] == 'A':
                card=11
                self.hand_val+=card
            if card[0]=='J' or card[0]=='K' or card[0]=='Q':
                card=10
                self.hand_val+=card

You set card to number instead of string and if card[0] does not work.

You could value in Ace case without changing the card value. Also it would make sense to have the second check as elif instead of if:

if card[0] == 'A':
                self.hand_val += 11
            elif card[0] in 'JKQ':
                self.hand_val += 10

Actually it woul be cleaner to have the card values from the type of card set from dictionary to avoid many conditions, like discussed in previous posts.

Edited 5 Years Ago by pyTony: n/a

When you process Ace:

if card[0] == 'A':
                card=11
                self.hand_val+=card
            if card[0]=='J' or card[0]=='K' or card[0]=='Q':
                card=10
                self.hand_val+=card

You set card to number instead of string and if card[0] does not work.

You could value in Ace case without changing the card value. Also it would make sense to have the second check as elif instead of if:

if card[0] == 'A':
                self.hand_val += 11
            elif card[0] in 'JKQ':
                self.hand_val += 10

Actually it woul be cleaner to have the card values from the type of card set from dictionary to avoid many conditions, like discussed in previous posts.

Ok, that actually makes sense to me now!
Oerhaps I'm being naive, but it seems like it would be easy to modify that code to create a rule for the Ace, so that if the current hand <= 10, the Ace is worth 11, but if the hand > 10, the Ace would only be worth 1. Is that do-able?

Ok, here is my version of the part of function from version I prepared yesterday:

# if we are busted, but have Ace, we try to save situation
        while self.hand_val > 21 and any(card.startswith('A') for card in self.cards):
            ind = next(ind for ind, card in enumerate(self.cards) if card.startswith('A'))
            self.cards[ind] = '1'+ self.cards[ind][1:]
            self.hand_val -= 10

Ok, here is my version of the part of function from version I prepared yesterday:

# if we are busted, but have Ace, we try to save situation
        while self.hand_val > 21 and any(card.startswith('A') for card in self.cards):
            ind = next(ind for ind, card in enumerate(self.cards) if card.startswith('A'))
            self.cards[ind] = '1'+ self.cards[ind][1:]
            self.hand_val -= 10
This article has been dead for over six months. Start a new discussion instead.