Jam
Jam

Reputation: 223

Blackjack game reshuffling problem-edited

I am trying to make a blackjack game where before each new round, the program checks to make sure that the deck has 7 cards per player. And if it doesn't, the deck clears, repopulates, and reshuffles. I have most of the problem down, but for some reason at the start of every deal it reshuffles the deck more than once, and I can't figure out why. Help, please. Here's what I have so far: (P.S. the imported cards and games modules aren't part of the problem, I'm fairly sure my problem lies in the deal() function of my BJ_Deck class.)

import cards, games     

class BJ_Card(cards.Card):
    """ A Blackjack Card. """
    ACE_VALUE = 1

    def get_value(self):
        if self.is_face_up:
            value = BJ_Card.RANKS.index(self.rank) + 1
            if value > 10:
                value = 10
        else:
            value = None
        return value

    value = property(get_value)


class BJ_Deck(cards.Deck):
    """ A Blackjack Deck. """
    def populate(self):
        for suit in BJ_Card.SUITS: 
            for rank in BJ_Card.RANKS: 
                self.cards.append(BJ_Card(rank, suit))

    def deal(self, hands, per_hand=1):
        for rounds in range(per_hand):
            if len(self.cards)>=7*(len(hands)):
                    print "Reshuffling the deck."
                    self.cards=[]
                    self.populate()
                    self.shuffle()
            for hand in hands:
                    top_card=self.cards[0]
                    self.give(top_card, hand)


class BJ_Hand(cards.Hand):
    """ A Blackjack Hand. """
    def __init__(self, name):
        super(BJ_Hand, self).__init__()
        self.name = name

    def __str__(self):
        rep = self.name + ":\t" + super(BJ_Hand, self).__str__()  
        if self.total:
            rep += "(" + str(self.total) + ")"        
        return rep

    def get_total(self):
        # if a card in the hand has value of None, then total is None
        for card in self.cards:
            if not card.value:
                return None

        # add up card values, treat each Ace as 1
        total = 0
        for card in self.cards:
              total += card.value

        # determine if hand contains an Ace
        contains_ace = False
        for card in self.cards:
            if card.value == BJ_Card.ACE_VALUE:
                contains_ace = True

        # if hand contains Ace and total is low enough, treat Ace as 11
        if contains_ace and total <= 11:
            # add only 10 since we've already added 1 for the Ace
            total += 10   

        return total

    total = property(get_total)

    def is_busted(self):
        return self.total > 21


class BJ_Player(BJ_Hand):
    """ A Blackjack Player. """
    def is_hitting(self):
        response = games.ask_yes_no("\n" + self.name + ", do you want a hit? (Y/N): ")
        return response == "y"

    def bust(self):
        print self.name, "busts."
        self.lose()

    def lose(self):
        print self.name, "loses."

    def win(self):
        print self.name, "wins."

    def push(self):
        print self.name, "pushes."


class BJ_Dealer(BJ_Hand):
    """ A Blackjack Dealer. """
    def is_hitting(self):
        return self.total < 17

    def bust(self):
        print self.name, "busts."

    def flip_first_card(self):
        first_card = self.cards[0]
        first_card.flip()


class BJ_Game(object):
    """ A Blackjack Game. """
    def __init__(self, names):      
        self.players = []
        for name in names:
            player = BJ_Player(name)
            self.players.append(player)

        self.dealer = BJ_Dealer("Dealer")

        self.deck = BJ_Deck()
        self.deck.populate()
        self.deck.shuffle()

    def get_still_playing(self):
        remaining = []
        for player in self.players:
            if not player.is_busted():
                remaining.append(player)
        return remaining

    # list of players still playing (not busted) this round
    still_playing = property(get_still_playing)

    def __additional_cards(self, player):
        while not player.is_busted() and player.is_hitting():
            self.deck.deal([player])
            print player
            if player.is_busted():
                player.bust()

    def play(self):
        # deal initial 2 cards to everyone
        self.deck.deal(self.players + [self.dealer], per_hand = 2)
        self.dealer.flip_first_card()    # hide dealer's first card
        for player in self.players:
            print player
        print self.dealer

        # deal additional cards to players
        for player in self.players:
            self.__additional_cards(player)

        self.dealer.flip_first_card()    # reveal dealer's first 

        if not self.still_playing:
            # since all players have busted, just show the dealer's hand
            print self.dealer
        else:
            # deal additional cards to dealer
            print self.dealer
            self.__additional_cards(self.dealer)

            if self.dealer.is_busted():
                # everyone still playing wins
                for player in self.still_playing:
                    player.win()                    
            else:
                # compare each player still playing to dealer
                for player in self.still_playing:
                    if player.total > self.dealer.total:
                        player.win()
                    elif player.total < self.dealer.total:
                        player.lose()
                    else:
                        player.push()

        # remove everyone's cards
        for player in self.players:
            player.clear()
        self.dealer.clear()


def main():
    print "\t\tWelcome to Blackjack!\n"

    names = []
    number = games.ask_number("How many players? (1 - 7): ", low = 1, high = 8)
    for i in range(number):
        name = raw_input("Enter player name: ")
        names.append(name)
    print

    game = BJ_Game(names)

    again = None
    while again != "n":
        game.play()
        again = games.ask_yes_no("\nDo you want to play again?: ")


main()
raw_input("\n\nPress the enter key to exit.")

Since someone decided to call this 'psychic-debugging', I'll go ahead and tell you what the modules are then. Here's the cards module:

class Card(object):
""" A playing card. """
RANKS = ["A", "2", "3", "4", "5", "6", "7",
         "8", "9", "10", "J", "Q", "K"]
SUITS = ["c", "d", "h", "s"]

def __init__(self, rank, suit, face_up = True):
    self.rank = rank
    self.suit = suit
    self.is_face_up = face_up

def __str__(self):
    if self.is_face_up:
        rep = self.rank + self.suit
    else:
        rep = "XX"
    return rep

def flip(self):
    self.is_face_up = not self.is_face_up

class Hand(object): """ A hand of playing cards. """ def init(self): self.cards = []

def __str__(self):
    if self.cards:
       rep = ""
       for card in self.cards:
           rep += str(card) + "\t"
    else:
        rep = "<empty>"
    return rep

def clear(self):
    self.cards = []

def add(self, card):
    self.cards.append(card)

def give(self, card, other_hand):
    self.cards.remove(card)
    other_hand.add(card)

class Deck(Hand): """ A deck of playing cards. """ def populate(self): for suit in Card.SUITS: for rank in Card.RANKS: self.add(Card(rank, suit))

def shuffle(self):
    import random
    random.shuffle(self.cards)

def deal(self, hands, per_hand = 1):
    for rounds in range(per_hand):
        for hand in hands:
            if self.cards:
                top_card = self.cards[0]
                self.give(top_card, hand)
            else:
                print "Can't continue deal. Out of cards!"

if name == "main": print "This is a module with classes for playing cards." raw_input("\n\nPress the enter key to exit.")

And here's the games module:

class Player(object):
""" A player for a game. """
def __init__(self, name, score = 0):
    self.name = name
    self.score = score

def __str__(self):
    rep = self.name + ":\t" + str(self.score)
    return rep

def ask_yes_no(question): """Ask a yes or no question.""" response = None while response not in ("y", "n"): response = raw_input(question).lower() return response

def ask_number(question, low, high): """Ask for a number within a range.""" response = None while response not in range(low, high): response = int(raw_input(question)) return response

if name == "main": print "You ran this module directly (and did not 'import' it)." raw_input("\n\nPress the enter key to exit.")

Upvotes: 0

Views: 2698

Answers (3)

Corin
Corin

Reputation: 2467

Nosklo pointed out one problem (checking it inside the loop) but there is a second problem.

the condition

if len(self.cards)>=7*(len(hands)):

is checking if the number of cards is greater than the number needed and if so,clears the deck, populates and shuffles.

When combined with the check inside the loop, it will repopulate and shuffle the deck every time it starts another round.

So you probably want something like:

    if len(self.cards) <= 7*(len(hands)):
            print "Reshuffling the deck."
            self.cards=[]
            self.populate()
            self.shuffle()
    for rounds in range(per_hand):
        for hand in hands:
                top_card=self.cards[0]
                self.give(top_card, hand)

Upvotes: 1

user166390
user166390

Reputation:

for hand in hands:

Do you really want to run that logic for each hand?

Upvotes: 1

nosklo
nosklo

Reputation: 223062

You're checking it again and again, inside the loop, and while you distribute the cards, the deck is being reduced, I think (can't see the Deck.give method on your code to know for sure).

You probably want to check only once, move the check to outside the loop.

def deal(self, hands, per_hand=1):
    for rounds in range(per_hand):
        if len(self.cards) <= 7 * len(hands):
            print "Reshuffling the deck."
            self.cards = []
            self.populate()
            self.shuffle()
        for hand in hands:
            top_card=self.cards[0]
            self.give(top_card, hand)

Upvotes: 2

Related Questions