import random

# module: playing_cards
# a module that contains two classes: Card and Deck

class Card:

    #
    # instance variables:
    #    self.rank - 1..13 (1=ace, 11=jack, 12=queen, 13=king)
    #    self.suit - 0..3  (0=diamonds, 1=clubs, 2=hearts, 3=spades)
    #

    def __init__(self, r, s):
        if r >= 1 and r <= 13:
            self.__rank = r
        else:
            self.__rank = 2  # rank is 2 if they give me a bad rank

        if s >= 0 and s <= 3:
            self.__suit = s
        else:
            self.__suit = 0

    # setter methods for instance variables

    def set_rank(self, r):
        if r >= 1 and r <= 13:
            self.__rank = r
        
    def set_suit(self, s):
        if s >= 0 and s <= 3:
            self.__suit = s
        # if s is a bad value, __suit remains what it was

    # getter methods for the instance variables
    def get_suit(self):
        return self.__suit
    
    def get_rank(self):
        return self.__rank

    # this is called by using str(____)
    def __str__(self):
        
        if self.__rank == 1:
            rank_str = 'Ace'
        elif self.__rank == 11:
            rank_str = 'Jack'
        elif self.__rank == 12:
            rank_str = 'Queen'
        elif self.__rank == 13:
            rank_str = 'King'
        else:
            rank_str = str(self.__rank)

        if self.__suit == 0:
            suit_str = 'Diamonds'
        elif self.__suit == 1:
            suit_str = 'Clubs'
        elif self.__suit == 2:
            suit_str = 'Hearts'
        else:
            suit_str = 'Spades'

        return rank_str + ' of ' + suit_str



    
        


class Deck:

    #
    # instance variable:
    #    self.__deck - a list of Card objects
    #
    
    def __init__(self):

        self.__deck = []

        for s in range(0,4):
            for r in range(1,14):
                self.__deck.append(Card(r,s))

    def cut(self):
        cutpoint = random.randint(0,51)
        self.__deck = self.__deck[cutpoint:] + self.__deck[:cutpoint]

    def shuffle(self):
        # self.__deck contains all the cards that need to be shuffled

        # an idea with random.choice is to
        # a bunch of times, get a Card using random.choice(self.deck)
        #          and remove that random Card and then append it

##        for _ in range(2000):
##            acard = random.choice(self.__deck)
##            self.__deck.remove(acard)
##            self.__deck.append(acard)

        # another idea is to get 2 random indices of self.deck
        # using this random.randint(0,51) twice
        # and swap the Cards at those two indices

        for _ in range(2000):
            idx1 = random.randint(0,51)
            idx2 = random.randint(0,51)
            temp = self.__deck[idx1]
            self.__deck[idx1] = self.__deck[idx2]
            self.__deck[idx2] = temp

    def deal(self):
        # grab the top card
        # remove it from self.deck
        # return that card
        cardtodeal = self.__deck[0]
        self.__deck.remove(cardtodeal)
        return cardtodeal
        
        

    # this is called by using str(____)
    def __str__(self):


        deck_str = ''
        for item in self.__deck:
            deck_str = deck_str + str(item) + '\n'
        return deck_str





                

                
        
        
