The Playing Cards Program 3.0

This is an example from:

Chapter 9: Python Programming for the Absolute Beginner, Third Edition - Michael Dawson.

It is a simple program that extends the previous playing cards program using inheritance and overriding methods.

We now introduce two extra card classes that extend from Card - UnprintableCard, PositionableCard

Both of these override the base (Card) class __str__() method.

PositionableCard also manages an attribute is_face_up that keeps track of which way up a card is, face up or face down. It also has a method called flip(), that allows us to change is_face_up to True or False.

Copy the following into main.py.

import random


# Playing Cards 3.0
# Demonstrates inheritance - overriding methods
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):
        self.rank = rank
        self.suit = suit

    def __str__(self):
        rep = self.rank + self.suit
        return rep


class UnprintableCard(Card):
    """ A Card that won't reveal its rank or suit when printed. """

    def __str__(self):
        return "<unprintable>"


class PositionableCard(Card):
    """ A Card that can be face up or face down. """

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

    def __str__(self):
        if self.is_face_up:
            rep = super().__str__()
        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):
        random.shuffle(self.cards)

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


def main():
    card_one = Card("A", "c")
    card_two = UnprintableCard("A", "d")
    card_three = PositionableCard("A", "h")
    print("Printing a Card object:")
    print(card_one)
    print("\nPrinting an UnprintableCard object:")
    print(card_two)
    print("\nPrinting a PositionableCard object:")
    print(card_three)
    print("Flipping the PositionableCard object.")
    card_three.flip()
    print("Printing the PositionableCard object:")
    print(card_three)
    input("\n\nPress the enter key to exit.")


if __name__ == "__main__":
    main()