Project Euler: Problem 54

class Card(object):
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit
        
    def getRank(self):
        return self.rank
    
    def getSuit(self):
        return self.suit
    
    def BJValue(self): #Rank of cards in game of Blackjack
        if self.rank == 'Ace':
            return 1
        elif self.rank == 'Jack' or self.rank == 'Queen' or self.rank == 'King':
            return 10
        else:
            return int(self.rank)
    
    def PokerValue(self):
        if self.rank == 'Ace':
            return 14
        elif self.rank == 'King':
            return 13
        elif self.rank == 'Queen':
            return 12
        elif self.rank == 'Jack':
            return 11
        else:
            return int(self.rank)
              
    def __str__(self):
        return ('{0} of {1}'.format(self.rank, self.suit))
    
    def __repr__(self):
        return repr((self.rank, self.suit, self.PokerValue()))
import inspect
import operator

class Hand(object):
    """Models a hand of cards as a list."""
    def __init__(self, cards=[]):
        self._list = cards
    
    def extend(self, cards):
        if isinstance(cards, list): #Only append lists of cards
            self._list.extend(cards)
        else:
            pass
        
    def append(self,card):
        if isinstance(card, Card): #Only append instances of the Class object "Card"
            self._list.append(card)
        else:
            pass
    
    def isStraight(self):
        
        """Tests if the hand is a straight.
        Returns True if yes, False if no."""
        
        values = [] #Initialize a list to hold the values of the cards
        for card in self._list:
            values.append(card.PokerValue())
        disvalues = set(values)
        values.sort()
        if max(values[0:4]) == 5 and max(values) == 14 and len(disvalues) == 5:
            return True
        elif (max(values) - min(values) == 4) and len(disvalues) == 5:
            return True
        else:
            return False
        
    def isFlush(self):
        """Tests if the hand is a flush. Returns True if yes, False if no."""
        
        suits = [] #Initialize a set to hold the suits of the cards
        for card in self._list:
            suits.append(card.getSuit())
        if len(set(suits)) == 1:
            return True
        else:
            return False
               
    def evaluate(self):
        """Evaluates the poker hand."""
        
        #Create a dictionary to store the number of times
        #each rank-value appears in the hand
        _d = {2 : 0, 
        3 : 0,
        4 : 0,
        5 : 0,
        6 : 0,
        7 : 0,
        8 : 0,
        9 : 0,
        10 : 0,
        11 : 0,
        12 : 0,
        13 : 0,
        14 : 0}
        
        for card in self._list:
            _d[card.PokerValue()] += 1 #Count the number of ranks
            
        rank = sum(1 for x in _d.values() if x > 0) #Count the number of distinct rands in the hand
        d = sorted(_d.iteritems(), key = operator.itemgetter(1,0), reverse = True)      
        
        straight = self.isStraight() #Test if the hand is a straight
        flush = self.isFlush() #Test if the hand is a flush
    
        if rank == 2:
            if max(_d.values()) == 4:
                base_val = 8 #Four of a kind
            elif max(_d.values()) == 3:
                base_val = 7 #Full House
        elif rank == 3:
            if max(_d.values()) == 3:
                base_val = 4 #Three of a Kind
            elif max(_d.values()) == 2:
                base_val = 3 #Two Pair
        elif rank == 4:
            base_val = 2 #One Pair
        elif rank == 5:
            base_val = 1 #High Card
    
        if straight and flush:
            base_val = max(base_val, 9) #Straight flush
        elif straight and (not flush):
            base_val = max(base_val, 5) #Non-Flush Straight
        elif (not straight) and flush:
            base_val = max(base_val, 6) #Non-Straight Flush
        
        value = base_val
        for x in d:
            if x[1] != 0: #Only append ranks with nonzero counts
                value = int(str(value) + (x[1]*str(x[0]).zfill(2))) #Pad the string with leading zero, if one digit             
        return value 
    
    def __repr__(self):
        return repr(self._list)
#This function converts a two-character string representation of a card to a tuple
def vectorize_card(card):
    #The rank is the first character of the string block
    if card[0] == 'T':
        rank = '10' #The text file represents the rank 10 by the letter T
    elif card[0] == 'J':
        rank = 'Jack'
    elif card[0] == 'Q':
        rank = 'Queen'
    elif card[0] == 'K':
        rank = 'King'
    elif card[0] == 'A':
        rank = 'Ace'
    else:
        rank = card[0]
    suit = card[1] #The suit is the second character of the string block
    return Card(rank, suit)

def get_hands(line):
    card_strings = line.split(' ') #Each card is separated by a space
    card_list = []
    for i in range(0,10):
        x = vectorize_card(card_strings[i])
        card_list.append(x)
    _hand1 = Hand(card_list[0:5]) #The first five cards form the first hand
    _hand2 = Hand(card_list[5:10]) #The last five cards form the second hand
    return _hand1, _hand2

def get_winner(hand1, hand2):
    """Determines the winner of two poker hands."""
    
    #Evaluate each hand 
    value1 = hand1.evaluate()
    value2 = hand2.evaluate()
    
    if value1 > value2: 
        return 'player 1' #Return 1 for hand1
    if value1 < value2:
        return 'player 2' #Return 2 for hand2
    else: 
        return '' #Return 0 in the event of a tie
#Initialize a dictionary to count each player's number of wins
wins = {'player 1' : 0, 'player 2' : 0, '' : 0}

#Initialiaze a list to hold the hands for each round 
gamehands = []

file_path = "YOUR_FILE_PATH" 
f = open(file_path,'r') #Create a file object in read-mode
for line in f: #loop through the lines of the text file
    gamehands.append(get_hands(line)) #Append the hands to the list gamehands
f.close() #Close the file object 
for round in gamehands:
    winner = get_winner(round[0],round[1])
    wins[winner] += 1
print wins
Advertisements
This entry was posted in Problem Solving, Progamming, Python and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s