0

I have a program (blackjack.py) and it accesses another program's (cards.py and games.py) within its code. Most of this is from a book, so I'm having trouble understanding how it works.

Heres the code for cards.py:

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 round 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.")

I'm writing an error check for the blackjack.py and I need to gather the number of cards that have been used so far. I think I can do that by accessing the number of values in cards[]. The problem is, I am not sure on how to do that.

This is all in theory though. I will include the `blackjack.py' code as well, so you all can see what I am trying to do, and help me determine if my logic is flawed.

blackjack.py code

Any and all input is appreciated.

Mat
  • 202,337
  • 40
  • 393
  • 406
mandelbug
  • 1,548
  • 5
  • 20
  • 32

1 Answers1

1

While I'm not entirely clear on your intended structure here, you have a couple of options.

First, in order to use any functions or classes from cards.py in your blackjack.py module, you can use the import statement to import them. There are two styles of doing this:

# blackjack.py
import cards

Would give you access to everything in the cards module, and you'd call each function/class by prefacing it with cards.<name>. So, if you wanted to initialize an instance of the Deck class,

# blackjack.py
import cards
mydeck = cards.Deck()

The other way is the from <X> import <Y>, which gives you access to the functions and classes without having to add the prefix. Example:

# blackjack.py
from cards import Deck  # or, to import everything, "from cards import *"
mydeck = Deck()

Either of these methods would give you an instance of the cards.Deck class.

Option 0

You can already tell this within your Deck class, since it subclasses from Hand, so every time you give a card it's taking out out of the Deck's cards attribute. Thus, the number of cards given out would simply be:

class Deck(Hand):
    # ...
    def number_cards_used(self):
         return 52 - len(self.cards)

Alternatively, if you can't edit cards.py, you can simply get the number of cards left from your given Deck by:

# blackjack.py
def get_number_cards_used_from_deck(deck):
    return 52 - len(deck.cards)

In use:

# blackjack.py
import cards
mydeck = cards.Deck()
# ...
# Do other operations with deck
# ...
cards_used = get_number_cards_used_from_deck(mydeck)

Option 1

If you can isolate all of and only those hands being played simultaneously, you can implement a method card_count:

class Hand(object):
   # ...
   # other code
   # ....

   def card_count(self):
       return len(self.cards)

Then, if you have a list of all the hands, for example, you could do something like:

sum(map(lambda h: h.card_count(), list_of_hands))

Option 2

Within your Deck class, since it subclasses Hand, you could simply keep another running list of the cards that have been given out that would often be refreshed. This would look like:

class Deck(Hand):
    # ...
    # other code
    # ...

    def __init__(self):
        self.populate()
        self.used_cards = []

    def give(self, card, other_hand):
        self.used_cards.append(card)
        super(Deck, self).give(card, other_hand)

    def number_cards_used(self):
        return len(self.used_cards)

There are other methods, of course.

jdotjdot
  • 16,134
  • 13
  • 66
  • 118
  • Is there anyway of doing this _without_ adding to `cards.py`? I thought of something similar as well. I think that's what I am supposed to do anyway. I was asking how to use what I have in `cards.py` and `blackjack.py` to gather how many cards were left / in use. I have no idea how to access the `cards.py` file, and thought that by accessing it, I could somehow get the number of cards left. Can I? – mandelbug Nov 25 '12 at 06:49
  • I'm not sure what you mean by "accessing" `cards.py`. You don't have to edit `cards.py` to use option 0--given a `Deck()` initialized in variable `mydeck`, you could at any time do `52 - len(mydeck.cards)` to find out how many cards were used. IS that what you mean? – jdotjdot Nov 25 '12 at 06:53
  • What I mean by "accessing" is exactly how it sounds. How do I _use_ a method or class from `cards.py` in `blackjack.py`? How would I get a `Deck()` initialized variable? – mandelbug Nov 25 '12 at 13:39
  • No need to get all agitated. "Accessing" isn't a technical term, and as such is ill-defined. Using a method or class from `cards.py` can be done using the `import` statement, and it was not made clear earlier that that was your question. I've updated my answer to reflect this. – jdotjdot Nov 25 '12 at 19:55
  • I'm not agitated. That wasn't meant in a sarcastic manner, I'm sorry you saw it as such; that's not what I intended. I'm new to all this method and class lingo; I've never had to use either of them. Anyway thank you for your help so far, I think I am getting closer. I have `cards.py` imported properly, but the rest still doesn't seem to work as I want it to. I have a function (or what I believe is a function) at the very top of the page that goes something like: `myDeck = cards.Deck()` `def get_num_cards(myDeck):` `return 52 - len(myDeck.cards)` – mandelbug Nov 25 '12 at 22:05
  • Ok, that did not format the way I wished, but I hope you get the general idea. But every time I call that function(or method?) it returns 52. So I guess I am closer, but not yet there. – mandelbug Nov 25 '12 at 22:06
  • 1
    Well, that means that `myDeck.cards` right now has no cards in it at all. That's because when you're just doing `myDeck = cards.Deck()`, the `Deck` class starts of with `self.cards = []`. You have to do `myDeck = cards.Deck()`, and then call the method `myDeck.populate()` in order to actually populate `myDeck.cards` with all of the cards. If you do that, and then try calling `get_num_cards(myDeck)`, you'll probably find it returns `0`. – jdotjdot Nov 25 '12 at 22:15
  • I thought that it would already call the `populate()` in normal gameplay. I'll look through it and try it. – mandelbug Nov 25 '12 at 22:35
  • 1
    It won't. When you instantiate a class, the `__init__` method is called upon instantiation, but the `Deck` class you've provided in `cards.py` does not have an `__init__` method. If you look at __Option 2__ that I provided, you'll see that I created an `__init__` method for `Deck` that calls `self.populate()`, so that upon creating any `Deck`, `Deck.cards` would automatically be populated. In the code you provided above, it won't be. – jdotjdot Nov 25 '12 at 22:38
  • Right at the beginning of the `BJ_Game` class in the `__init__` method it calls `self.deck.populate`. Under that I tried adding `numCards = len(self.deck)` but it says "TypeError: len() of unsized object". – mandelbug Nov 25 '12 at 22:40
  • I'm sorry if I'm making this a pain, or more complicated than it should be, I truly am. – mandelbug Nov 25 '12 at 23:08
  • 1
    Okay, well looking at your `BJ_Game` code, it does call `self.deck.populate`, so it should populate then. You shouldn't add `numCards = len(self.deck)` but you need to add `numCards = len(self.deck.cards)`. Alternatively, you could add somewhere in one of the deck classes `def __len__(self): return len(self.cards)` or something along those lines. – jdotjdot Nov 25 '12 at 23:32
  • It works! Haha! Ok, well I have that all sorted out and working. Then at each `play()` method, I have it checking if `numCards` is less than or equal to `numPlayers * 7`. If it is less I have it doing `self.deck = BJ_Deck()` `self.deck.populate()` `numCards = len(self.deck.cards)` `self.deck.shuffle()` – mandelbug Nov 26 '12 at 00:59
  • Sorry, keep pressing enter on accident and forgetting shift + enter. Anyway, it doesn't seem to reset the deck or the count like it should? Any idea why? I'm sure the `numCards` works properly, I checked it with strategically placed `print` statements. Just not sure why it won't start the deck over and shuffle it. – mandelbug Nov 26 '12 at 01:01
  • You should create a new question for that, as it's beyond the scope of this one. Also, this comment thread has really gone on too long as it is, anyway. – jdotjdot Nov 26 '12 at 02:19
  • Haha ok. Well thanks for your help man. Got it working anyway. – mandelbug Nov 26 '12 at 02:23