class Deck(object):
'''Deck: An object that represents a deck of cards. Subclass of object.
Defaults to a standard poker deck.'''
# attributes
cards = []
numberOfSuits = 4
suitNames = {3:'Spades', 2:'Hearts', 1:'Diamonds', 0:'Clubs'}
suitLowCard = 2
suitHighCard = 14
suitCardNames = {14:'Ace', 13:'King', 12:'Queen', 11:'Jack'}
specialCards = 0
specialCardNames = {}
# populate the deck with cards
def __init__(self):
for suit in range(self.numberOfSuits):
for num in range(self.suitLowCard, (self.suitHighCard + 1)):
self.cards.append([num, suit])
if self.specialCards:
for num in range(self.specialCards):
self.cards.append([num, self.numberOfSuits])
print 'Deck made.'
# shuffle the deck
def shuffle(self):
if self.cards:
import random
random.shuffle(self.cards)
print 'Deck shuffled.'
else:
print 'Sorry, dude. No cards to shuffle. Must use deck.__init__ first.'
# empties the deck
def clearDeck(self):
self.cards = []
print 'Deck cleared.'
# draws, by default, the top card
def draw(self, card=0):
return self.cards.pop(card)
# draws the bottom card
def drawFromBottom(self):
return self.cards.pop()
# cuts the deck at the location given, defaults to middle
def cut(self, loc=26):
self.cards = self.cards[loc:] + self.cards[:loc]
return 'Deck cut.'
# reorganize the deck
def order(self):
# flip num and suit so the sort will order by suit
for card in self.cards:
card.reverse()
self.cards.sort()
self.cards.reverse()
# flip back num and suit
for card in self.cards:
card.reverse()
return 'Deck reorganized.'
# stack the deck
def stackDeck(self, card, new_loc):
self.insert(self.draw(card), new_loc)
return 'Nothing to see here.'
# find a card, returning its index
def findCard(self, card_num=14, card_suit=3):
if type(card_num) == type(int()):
if type(card_suit) == type(str()):
for suit in self.suitNames.iteritems():
if suit[1].lower() == card_suit.lower():
return self.cards.index([card_num, suit[0]])
elif suit[1][:-1].lower() == card_suit.lower():
return self.cards.index([card_num, suit[0]])
else:
return "Suit doesn't exist."
elif type(card_suit) == type(int()):
return self.cards.index([card_num, card_suit])
else:
return "Suit must be either an int or string."
else:
return "Card number must be an int."
class TarotDeck(Deck):
'''TarotDeck: An object that represents a deck of tarot cards. Subclass
of Deck.'''
# attributes
cards = []
reverseRate = .5
numberOfSuits = 4
suitNames = {3:'Swords', 2:'Wands', 1:'Pentacles', 0:'Cups'}
suitLowCard = 1
suitHighCard = 14
suitCardNames = {14:'King',
13:'Queen',
12:'Knight',
11:'Page',
10:'Ten',
9:'Nine',
8:'Eight',
7:'Seven',
6:'Six',
5:'Five',
4:'Four',
3:'Three',
2:'Two',
1:'Ace'}
specialCards = 22
specialCardNames = {0: 'The Fool',
1: 'The Magician',
2: 'The High Priestess',
3: 'The Empress',
4: 'The Emperor',
5: 'The Hierophant',
6: 'The Lovers',
7: 'The Chariot',
8: 'Strength',
9: 'The Hermit',
10: 'Wheel of Fortune',
11: 'Justice',
12: 'The Hanged Man',
13: 'Death',
14: 'Temperance',
15: 'The Devil',
16: 'The Tower',
17: 'The Star',
18: 'The Moon',
19: 'The Sun',
20: 'Judgement',
21: 'The World'}
# draw is overridden to give each card a reverse attribute
def draw(self, card=0):
import random
if random.random() < self.reverseRate:
rev = 0
else:
rev = 1
aCard = self.cards.pop(card)
aCard.append(rev)
return aCard
# returns description of the card
def describe(self, card):
if card[1] < self.numberOfSuits:
name = self.suitCardNames[card[0]] + ' of ' + self.suitNames[card[1]]
else:
name = self.specialCardNames[card[0]]
if card[2] == 1:
name = name + ' Reversed'
return name
class Hand(object):
'''Hand: A object to represent a hand of cards. Subclass
of object. Defaults to a Texas Hold 'em hand.'''
# attributes
cards = []
overflowCards = []
sleeve = []
size = 2
# init built-in
def __init__(self):
if self.cards: self.cards = []
return None
# take a card into the hand
def take(self, card=0):
if card:
if len(self.cards) < self.size:
self.cards.append(card)
print card, 'taken'
else:
self.overflowCards.append(card)
print 'Yo, I can only have ' + str(self.size) + ' cards in my hand.'
else:
print 'Um, there is no card to take.'
# order cards, defaults to by num
def order(self, orderBy=0):
if self.cards:
if orderBy: self.swapCardInfo()
self.cards.sort()
self.cards.reverse()
if orderBy: self.swapCardInfo()
print 'Hand ordered.'
else:
print 'Sorry, man, but there is no hand to order. You need to have one delt to you.'
# swaps the order of the num and the suit
# on the cards in the hand
def swapCardInfo(self):
if self.cards:
for card in self.cards:
card.reverse()
return 0
else:
return "Dude, gotta have cards to swap card's info."
# order cards by suit
def orderBySuit(self):
if self.cards:
self.swapCardInfo()
self.order()
self.swapCardInfo()
return 0
else:
return "Hey, no cards, dangit!"
# get number of each card as list
def getNums(self):
self.numList = [card[0] for card in self.cards]
# get the suits of each card as list
def getSuits(self):
self.suitList = [card[1] for card in self.cards]
# discard a card from the hand
def discard(self, card=0):
return self.cards.pop(card)
# discard all
def discardHand(self):
discards = []
while self.cards:
discards.append(self.cards.pop())
return discards
# discard a card from the overflow
def discardOverflow(self, card=0):
return self.cards.pop(card)
# put a card up your sleeve
def upSleeve(self, card=[14, 's']):
self.sleeve.append(card)
return 'Shhhh!'
# drop a card from your sleeve into your hand
def sleeveSwap(self, handCard, sleeveCard):
buff = self.cards[handCard]
self.cards[handCard] = self.sleeve[sleeveCard]
self.sleeve[sleeveCard]
return "Didn't see nothin'!"
class DiscardPile(Hand):
'''DiscardPile: An object that represents a discard pile used
in most card games. Subclass of Hand. Size defaults to
being large enough to discard an entire standard poker deck.'''
cards = []
size = 52
class UpPile(Hand):
'''UpPile: An object that represents the face up cards in a card
game like Texas Hold 'Em, but could represent something like a
Tarot reading. Subclass of Hand. Size defaults for Texas
Hold 'Em'''
cards = []
size = 5
class PokerHand(Hand):
'''PokerHand: An object that represents and evaluates a poker
hand. Subclass of Hand. Defaults to a best five of seven
game like Seven Card Stud or Texas Hold 'Em.'''
# attributes
size = 7
handsDict = {0: 'Straight flush',
1: 'Four of a kind',
2: 'Full house',
3: 'Straight',
4: 'Flush',
5: 'Three of a kind',
6: 'Two pair',
7: 'Pair',
8: 'High'}
# overrides x = y
def __eq__(self, other):
scoreSelf, cardsSelf = self.eval(self.cards[:])
scoreOther, cardsOther = other.eval(other.cards[:])
if scoreSelf != scoreOther:
return False
else:
for i in range(len(cardsSelf)):
if cardsSelf[i][0] != cardsOther[i][0]:
return False
else:
return True
# overrides x >= y
def __ge__(self, other):
if self.__gt__(other) or self.__eq__(other):
return True
else:
return False
# overrides x > y
def __gt__(self, other):
scoreSelf, cardsSelf = self.eval(self.cards[:])
scoreOther, cardsOther = other.eval(other.cards[:])
# remember lower score is better
if scoreSelf < scoreOther:
return True
elif scoreSelf > scoreOther:
return False
else:
for i in range(len(cardsSelf)):
if cardsSelf[i][0] > cardsOther[i][0]:
return True
elif cardsSelf[i][0] < cardsOther[i][0]:
return False
else:
return False
# overrides x <= y
def __le__(self, other):
if self.__lt__(other) or self.__eq__(other):
return True
else:
return False
# overrides x < y
def __lt__(self, other):
scoreSelf, cardsSelf = self.eval(self.cards[:])
scoreOther, cardsOther = other.eval(other.cards[:])
# remember lower score is better
if scoreSelf > scoreOther:
return True
elif scoreSelf < scoreOther:
return False
else:
for i in range(len(cardsSelf)):
if cardsSelf[i][0] < cardsOther[i][0]:
return True
elif cardsSelf[i][0] > cardsOther[i][0]:
return False
else:
return False
# overrides x != y
def __ne__(self, other):
if self.__eq__(other):
return False
else:
return True
# evaluates the hand, returning the best and it's score
def eval(self, hand):
# returns indices of cards that match match in a list
def match(match=14, hand=[], attr=0):
result = []
for i in range(len(hand)):
if hand[i][attr] == match[attr]:
result.append(i)
return result
# given a list of values, returns a list of runs
def runs(numList, inc=1):
buff = numList.pop()
if numList:
result = runs(numList, inc)
if result[-1][-1] + inc != buff:
result.append([])
result[-1].append(buff)
else:
result =[[buff],]
return result
# returns a list of the sets
def getSets(hand=[], attr=0):
result = {}
for card in hand:
if not result.has_key(card[attr]):
result[card[attr]] = match(match=card, hand=hand[:], attr=attr)
return result
# returns a list of the cards of the runs
def getRuns(hand=[], attr=0):
# handle the variable ace
for card in hand:
if card[0] == 14:
hand.append([1, card[1]])
# find the runs in the hand
result = []
setsDict = getSets(hand, attr)
if setsDict:
uniqNums = setsDict.keys()
uniqNums.sort()
runsList = runs(uniqNums[:], 1)
# return the cards in the run
result = []
for run in runsList:
result.append([],)
for num in run:
iList = setsDict[num]
# if multiple permutations of the run, put a list
# of the card that can fit in a slot in that slot
if len(iList)==1:
result[-1].append(hand[iList[0]])
else:
result[-1].append([],)
for card in iList:
result[-1][-1].append(hand[card])
for run in result: run.reverse()
result.reverse()
return result
# returns list of suits
def getSuits(hand, attr=1):
return getSets(hand, attr)
# given a dict of lists and an int, removes dict
# members when len of list doesn't = int
def filterLen(theDict, size):
for k in theDict.keys():
if len(theDict[k]) != size:
theDict.pop(k)
return theDict
# given of dict of lists and an int, removes dict
# members when len < int
def filterLenLT(theDict, size):
for k in theDict.keys():
if len(theDict[k]) < size:
theDict.pop(k)
return theDict
# returns the hand there is a size of a kind
def isOfAKind(hand, size, handSize=5):
hand.sort()
hand.reverse()
setsDict = getSets(hand[:])
setsDict = filterLen(setsDict, size)
if setsDict:
sets = setsDict.keys()
sets.sort()
result = []
setsDict[sets[-1]].sort()
setsDict[sets[-1]].reverse()
for i in setsDict[sets[-1]]:
result.insert(0, hand.pop(i))
result.extend(hand)
return result[:handSize]
else:
return None
# when all else fails, returns the high card hand
def isHigh(hand, size=5):
hand.sort()
hand.reverse()
return hand[:size]
# returns hand if there is a pair
def isPair(hand, size=5):
result = isOfAKind(hand[:], 2)
return result
# returns hand if there are two pair
def is2Pair(hand, size=5):
hand.sort()
setsDict = getSets(hand[:])
setsDict = filterLen(setsDict, 2)
if len(setsDict) >= 2:
result = []
popList = []
pairs = setsDict.keys()
pairs.sort()
for i in setsDict[pairs[-1]]:
result.insert(0, hand[i])
popList.append(i)
for j in setsDict[pairs[-2]]:
result.insert(0, hand[j])
popList.append(j)
result.reverse()
hand.reverse()
for x in range(len(hand)):
if not popList.count(x):
result.insert(0, hand[x])
break
result.reverse()
return result[:size]
else:
return None
# returns hand if there are trips
def isTrip(hand, size=5):
result = isOfAKind(hand[:], 3)
return result
# returns hand if a straight
def isStraight(hand, size=5):
result = []
theRuns = getRuns(hand[:])
for aRun in theRuns:
if len(aRun) >= size:
for theNum in aRun:
if type(theNum[0]) == type(list()):
result.append(theNum[0])
else:
result.append(theNum)
break
return result[:size]
# returns hand if a flush
def isFlush(hand, size=5):
hand.sort()
hand.reverse()
setsDict = getSets(hand[:], 1)
setsDict = filterLenLT(setsDict, size)
if setsDict:
sets = setsDict.keys()
sets.sort()
# compare the sets to find the highest
compSet = setsDict.pop(sets.pop())
while setsDict:
buff = setsDict.pop(sets.pop())
for card in range(size):
if hand[compSet[card]][0] > hand[buff[card]][0]:
break
elif hand[compSet[card]][0] < hand[buff[card]][0]:
compSet = buff
break
# construct the best hand
compSet.reverse()
result = []
for i in compSet:
result.insert(0, hand.pop(i))
if len(result) < size: result.extend(hand)
return result[:size]
else:
return None
# returns hand if full house
def isBoat(hand, size=5):
hand.sort()
setsDict = getSets(hand[:])
tripsDict = filterLen(setsDict.copy(), 3)
pairsDict = filterLen(setsDict.copy(), 2)
if (len(tripsDict) >= 2) or (tripsDict and pairsDict):
result = []
popList = []
trips = tripsDict.keys()
trips.sort()
# add the trip to the hand
for i in tripsDict.pop(trips.pop()):
result.append(hand[i])
popList.append(i)
# add the pair to the hand
for k in trips:
pairsDict[k] = tripsDict[k]
pairs = pairsDict.keys()
pairs.sort()
thePair = pairsDict.pop(pairs.pop())
for j in range(2):
result.append(hand[thePair[j]])
popList.append(thePair[j])
# construct rest of hand
if len(result) < size:
print result
[hand.pop(x) for x in popList]
hand.reverse()
result.extend(hand)
return result[:size]
else:
return None
# returns hand if quads
def isQuads(hand, size=5):
result = isOfAKind(hand[:], 4)
return result
# returns hand if straight flush
def isStraightFlush(hand, size=5):
result = None
flushDict = getSuits(hand[:])
flushDict = filterLenLT(flushDict.copy(), size)
if flushDict:
flushHand = []
for suit in flushDict.iterkeys():
[flushHand.append(hand[card]) for card in flushDict[suit]]
result = isStraight(flushHand[:])
return result
# module main line
result = None
handTypes = [isStraightFlush,
isQuads,
isBoat,
isFlush,
isStraight,
isTrip,
is2Pair,
isPair,
isHigh]
for i in range(len(handTypes)):
result = handTypes[i](hand[:])
if result: break
return i, result
class Test(PokerHand):
size = 10
cards = [[14, 0],
[2, 0],
[3, 0],
[4, 0],
[5, 0],
[14, 2],
[2, 2],
[3, 2],
[4, 2],
[5, 2]]
def __init__(self): pass
class TarotHand(Hand):
'''TarotHand: This represents a traditional tarot spread used for
divination. It defaults to the Celtic Cross. Subclass of Hand.
Note: This object in no way claims any supernatural ability.'''
size = 10
cardPosition = {0: 'Signifier',
1: 'Problem',
2: 'Problem Foundation',
3: 'Immediate Past',
4: 'Best Outcome',
5: 'Immediate Future',
6: 'Querent Approach',
7: 'Querent Surrounding',
8: 'Hopes and Fears',
9: 'Final Outcome'}
def take5(hand, deck, x=5):
'''take5: a function that quickly fills a hand from a deck.
defaults to taking 5 cards, hence the name.'''
for i in range(x):
hand.take(deck.draw())