#!/usr/bin/python

from random import randint

class Card:
    """represents a standard playing card.  
    """

    # rankList starts with a dummy element so that we can use
    # card ranks as indices into the list (could be avoided by
    # using a dictionary)
    suitList = ["Clubs", "Diamonds", "Hearts", "Spades"]
    rankList = ["narf", "Ace", "2", "3", "4", "5", "6", "7", 
              "8", "9", "10", "Jack", "Queen", "King"]

    def __init__(self, suit=0, rank=0):
        self.suit = suit
        self.rank = rank

    def __str__(self):
        return '%s of %s' % (Card.rankList[self.rank],
                             Card.suitList[self.suit])

    def __cmp__(self, other):
        """return a positive value if self outranks other,
        a negative value if other outranks self, and 0 if
        they are equivalent.
        """
        return self.suit - other.suit or cmp_rank(self.rank, other.rank)

def cmp_rank(r1, r2):
    """compare two ranks, considering Aces to be high (rank 14)
    """
    if r1==1: r1=14
    if r2==1: r2=14
    return r1-r2
    

class Deck:
    def __init__(self, deck=None, start=0, stop=None):
        """if you don't provide a deck, the initializer creates
        a new deck and 52 cards.  If you do provide a deck,
        the initializer makes a copy that refers to the same
        set of cards as the original.  start and stop let you
        copy part of a deck."""
        if deck == None:
            self.full_deck()
        else:
            self.cards = deck.cards[start:stop]

    def full_deck(self):
        """create a complete deck of cards"""
        self.cards = []
        for suit in range(4):
            for rank in range(1, 14):
                self.cards.append(Card(suit, rank))

    def __str__(self):
        """print the deck"""
        res = []
        for card in self.cards:
            res.append(str(card))
        return '\n'.join(res)

    def add_card(self, card):
        """add a card to the deck"""
        self.cards.append(card)

    def pop_card(self, i=-1):
        """remove and return a card from the deck.
        By default, pop the last card."""
        return self.cards.pop(i)

    def deal(self, hand, num):
        """move the given number of cards from the deck into the Hand"""
        for i in range(num):
            hand.add_card(self.pop_card())

    def shuffle(self):
        """shuffle the deck using a simple algorithm.  An alternative
        is to use random.shuffle
        """
        n = len(self.cards)
        for i in range(n):
            j = randint(i, n-1)
            swap_items(self.cards, i, j)

def swap_items(seq, i, j):
    """swap two items in a mutable sequence"""
    seq[i], seq[j] = seq[j], seq[i]


class Hand(Deck):
    def __init__(self, label=''):
        self.label = label
        self.cards = []


