# Blackjack card game

It's been a long while since I've done any Python programming so I thought I'd start with a simple Blackjack game. Any comments on how I can make this more readable? Use more methods perhaps?

from sys import exit
from random import randint

class Game(object):

def __init__(self, start):
self.quips = [
" you kinda suck at this.",
"Such a loser."
]
self.start = start

#main method to start playing
def play(self):
next = self.start
action = "y"

#start playing
while True:
print "\n-------"
print "Beginning blkjk"
print "Dealing.. \n"

#deal user's cards
unum1 = randint(1,10)
unum2 = randint(1,10)
utotal = unum1 + unum2
print "Ur cards are: %d & %d totalling %d \n" % (unum1, unum2,utotal)

#hit until user says stop
while action == "y":
action = raw_input("Hit? > ")
if action == "y":
utotal = utotal + self.hit()
print "ur new total is %d" % utotal

print "Ur total is %d " % utotal

#deal dealer's cards
dnum1 = randint(1,10)
dnum2 = randint(1,10)
dtotal = dnum1 + dnum2
print "Dealer's cards are %d & %d totalling %d \n" % (dnum1, dnum2, dtotal)

#dealer keeps hitting until close/more than 21
while dtotal < 21:
print"    Dealer hits\n"
dtotal = dtotal + self.hit()

if dtotal <= 21:
print "Dealer's total is %d " % dtotal
if utotal > dtotal:
print "you win!"
exit(1)
else:
print "dealer wins"
self.death()
else:
print "Dealer busts, u win!"
exit(1)

def death(self):
print self.quips[randint(0, len(self.quips)-1)]
exit(1)

def hit(self):
nextcard = randint(1,9)
print "ok, next card is %d " % nextcard
return nextcard

a_game = Game("deal")
a_game.play()


I don't think that having a huge "Game" class that contains the flow of the entire game is the way you want to do it. Why don't you break the game into some manageable chunks? Here's what I came up with after a little thinking:

import random
DEFAULT_CHIPS = 20

class Card(object):
card_to_name = {1:"Ace", 2:"Two", 3:"Three", 4:"Four", 5:"Five", 6:"Six", 7:"Seven",
8:"Eight", 9:"Nine", 10:"Ten", 11:"Jack", 12:"Queen", 13:"King"}

def __init__(self, value, suit):
self.name = self.card_to_name[value]
self.suit = suit
self.title = "%s of %s" % (self.name, self.suit)
self.score = min(value, 10)

def __repr__(self):
return self.title

class Hand(object):
def __init__(self, cards):
self.hand = cards

def get_scores(self):
num_aces = sum(card.name == "Ace" for card in self.hand)
score = sum(card.score for card in self.hand)
return [score + i*10 for i in range(num_aces+1)]

def possible_scores(self):
return [s for s in self.get_scores() if s <= 21]

def __repr__(self):
return str(self.hand)

class Deck(object):
unshuffled_deck = [Card(card, suit) for card in range(1, 14) for suit in ["Clubs", "Diamonds", "Hearts", "Spades"]]
def __init__(self, num_decks=1):
self.deck = self.unshuffled_deck * num_decks
random.shuffle(self.deck)

def deal_card(self):
return self.deck.pop()

def deal_hand(self):
return Hand([self.deal_card(), self.deal_card()])

class Player(object):
def __init__(self, name="Player 1", chips=DEFAULT_CHIPS):
self.name = name
self.chips = chips
self.current_bet = 0

def new_hand(self, hand):
self.hand = hand

def hit(self, card):
self.hand.hand.append(card)

def is_busted(self):
return len(self.hand.possible_scores()) == 0

def scores(self):
return self.hand.get_scores() if self.is_busted() else self.hand.possible_scores()

def __repr__(self):
player_str = self.name + "(BUSTED)" if self.is_busted() else self.name
return "Player: {}\nChips: {}\nCurrent Bet: {}\nCards: {}\nScore: {}".format(
player_str, self.chips, self.current_bet, self.hand, self.scores())

if __name__ == "__main__":
d = Deck()
print d.deck
h = d.deal_hand()
p = Player()
p.new_hand(h)
print p
p.hit(d.deal_card())
print p


Here is some test output:

[Two of Spades, Two of Diamonds, Three of Clubs, Ten of Hearts, Ace of
Diamonds, Eight of Diamonds, Seven of Diamonds, King of Hearts, Seven
of Hearts, Queen of Diamonds, Six of Clubs, Nine of Diamonds, Seven of
Spades, Four of Spades, Four of Diamonds, Ten of Clubs, Four of Clubs,
Jack of Hearts, Ace of Clubs, Six of Spades, Eight of Spades, Seven of
Clubs, Eight of Hearts, Three of Diamonds, Jack of Clubs, King of
Diamonds, Five of Clubs, King of Clubs, Ace of Spades, King of Spades,
Six of Diamonds, Ten of Diamonds, Queen of Clubs, Two of Hearts, Eight
of Clubs, Nine of Hearts, Ace of Hearts, Five of Spades, Jack of
Diamonds, Nine of Spades, Four of Hearts, Six of Hearts, Two of Clubs,
Three of Spades, Jack of Spades, Five of Diamonds, Three of Hearts, Ten
of Spades, Five of Hearts, Queen of Hearts, Nine of Clubs, Queen of
Player: Player 1
Chips: 20
Current Bet: 0
Cards: [Queen of Spades, Nine of Clubs]
Score: [19]
Player: Player 1(BUSTED)
Chips: 20
Current Bet: 0
Cards: [Queen of Spades, Nine of Clubs, Queen of Hearts]
Score: [29]

From there, implementing the game in a clean fashion wouldn't be too tough.

Nolen Royalty has an excellent example of a well-structured version. Here are some comments on your version.

from sys import exit
from random import randint

class Game(object):

def __init__(self, start):
self.quips = [
" you kinda suck at this.",


Why the space?

            "don't quit your day job.",
"Such a loser."


Why is only this one capitalized?

        ]


This seems to be a constant list, as such its better as a global constant or a class attribute then a object attribute.

        self.start = start

#main method to start playing
def play(self):
next = self.start
action = "y"


assign this closer to where you actually use it

        #start playing
while True:
print "\n-------"


I suggest using an empty print to produce new lines for consistency

            print "Beginning blkjk"
print "Dealing.. \n"

#deal user's cards
unum1 = randint(1,10)
unum2 = randint(1,10)


Give variables names that hint at their usage, unum1 doesn't really.

            utotal = unum1 + unum2

print "Ur cards are: %d & %d totalling %d \n" % (unum1, unum2,utotal)

#hit until user says stop
while action == "y":
action = raw_input("Hit? > ")
if action == "y":
utotal = utotal + self.hit()
print "ur new total is %d" % utotal


You should put this block after the loop as it'll do the same thing.

            print "Ur total is %d " % utotal

#deal dealer's cards
dnum1 = randint(1,10)
dnum2 = randint(1,10)


With all this different instances of getting a card, perhaps you should have a function to do it.

            dtotal = dnum1 + dnum2
print "Dealer's cards are %d & %d totalling %d \n" % (dnum1, dnum2, dtotal)


The same logic is being repeated again for the dealer as there was for the player. This suggest a class to represent a Hand of cards might be in order

            #dealer keeps hitting until close/more than 21
while dtotal < 21:
print"    Dealer hits\n"
dtotal = dtotal + self.hit()

if dtotal <= 21:
print "Dealer's total is %d " % dtotal
if utotal > dtotal:
print "you win!"
exit(1)


Don't use exit to close your programs. Just break out of any loops

                else:
print "dealer wins"


What if you tied?

                    self.death()
else:
print "Dealer busts, u win!"
exit(1)

def death(self):
print self.quips[randint(0, len(self.quips)-1)]


use random.choice to select a random element from a list

        exit(1)

def hit(self):
nextcard = randint(1,9)


Why 9 when the rest were 10?

        print "ok, next card is %d " % nextcard
return nextcard

a_game = Game("deal")


You seem to be ignoring the parameter

a_game.play()


One problem I see is that your dealing may result in card repetition, which would be illegal. You are going to need to track which card has already been played and not to use them again.