我是python的新手,可以从书籍,论坛和开发人员那里学习。最近,我尝试在扑克程序中实现各种手排名类别。目的是计算概率,看看它是否与理论扑克手概率相符?
Source: https://en.wikipedia.org/wiki/Poker_probability?oldformat=true
请在下面找到我到目前为止用来构建它的代码和逻辑。该代码包含Card和Deck类,它们共同实现了所使用的一系列标准扑克牌,以及一个示例PyTest测试函数test_xxx()。
到目前为止,我已经编写了hasOnePair,hasTwoPairs,hasThreeOfAKind,hasFullHouse和hasFourOfaKind()函数,并且运行良好,但是我在Straight,flush,StraightFlush方面苦苦挣扎。
有人可以提出建议或给出有关如何处理平直,同花,皇家同花顺,同花顺案例的指南吗?此外,任何更新此代码的建议都将是很好的。
import random
SUITS = ["Clubs", "Diamonds", "Hearts", "Spades"]
RANKS = ["", "Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King"]
# here's two Python classes whose objects represent playing cards and decks thereof
class Card():
"""
Represents a single playing card,
whose rank internally is int _rank: 1..13 => "Ace".."King"
and whose suit internally is int _suit 0..3 => "Clubs".."Spades"
"""
def __init__(self, rank=1, suit=3): # this is the constructor!
'''
Initialize card with given int suit and int rank
:param rank:
:param suit:
:return:
'''
self._rank = rank
self._suit = suit
def __str__(self): # this is the "stringifier"
"""
Return the string name of this card:
"Ace of Spades": translates int fields to strings
:return:
"""
# "Ace of Spades" is string for self._rank==1, self._suit==3
toreturn = RANKS[self._rank] + " of " + SUITS[self._suit]
return toreturn
class Deck():
"""
Represents a deck of 52 standard playing cards,
as a list of Card refs
"""
def __init__(self): # constructor
"""
Initialize deck: field _cards is list containing
52 Card refs, initially
:return: nothing
"""
self._cards = []
for rank in range(1, 14):
for suit in range(4):
c = Card(rank, suit) # create next Card with given value
self._cards.append(c) # add it to this Deck
def __str__(self):
"""
"Stringified" deck: string of Card named,
with \n for easier reading
:return:
"""
toreturn = ''
# for index in range(len(self._cards)):
# self._cards[index]
for c in self._cards:
temp = str(c) # temp is the stringified card
toreturn = toreturn + temp + "\n" # note \n at end
return toreturn
def shuffle(self):
random.shuffle(self._cards) # note random function to do this
def dealCard(self):
toreturn = self._cards.pop(0) # get and remove top card from deck
return toreturn
def buildDict(hand):
dict = {}
for card in hand:
dict[card._rank] = dict.get(card._rank, 0) + 1
return dict
def hasOnePair(dict):
twocount = 0
threecount = 0
for v in dict.values():
if v == 2:
twocount += 1
elif v == 3:
threecount += 1
if twocount==1 and threecount != 1:
return True
else:
return False
def hasTwoPairs(dict):
twocount1 = 0
threecount1 = 0
for v in dict.values():
if v ==2:
twocount1 += 1
elif v == 3:
threecount1 +=1
if twocount1 == 2 and threecount1 != 1:
return True
else:
return False
def hasThreeOfAKind(dict):
twocount = 0
threecount = 0
for v in dict.values():
if v == 2:
twocount += 1
elif v == 3:
threecount += 1
if twocount != 1 and threecount == 1:
return True
else:
return False
def hasFullHouse(dict):
twocount = 0
threecount = 0
for v in dict.values():
if v == 2:
twocount += 1
elif v == 3:
threecount += 1
if twocount == 1 and threecount == 1:
return True
else:
return False
def hasFourOfAKind(dict):
fourcount = 0
onecount = 0
for v in dict.values():
if v ==4:
fourcount += 1
elif v == 1:
onecount +=1
if fourcount == 1 and onecount == 1:
return True
else:
return False
def hasStraight(hand):
return False
def hasFlush(dict):
return False
def hasStraightFlush(dict):
return False
def hasRoyalFlush(dict):
return False
def main():
TRIALS = 1000 # int(input ("Input number of hands to test: "))
hand = [] # list of Card in hand
# accumulators for different counts
onepairCount = 0
twopairCount = 0
threeCount = 0
fourCount = 0
fullHouseCount = 0
StraightCount = 0
for num in range(TRIALS):
# create new Deck and shuffle
d = Deck()
d.shuffle()
# initialize hand as empty list
hand = []
# deal top 5 cards of deck, adding to hand
for count in range(5):
hand.append(d.dealCard())
# build the dictionary of card ranks in hand
dict = buildDict(hand)
# use dictionary to make hand checking easier
if hasOnePair(dict):
onepairCount += 1
elif hasTwoPairs(dict):
twopairCount += 1
elif hasThreeOfAKind(dict):
threeCount += 1
elif hasFourOfAKind(dict):
fourCount += 1
elif hasFullHouse(dict):
fullHouseCount += 1
elif hasStraight(dict):
StraightCount +=1
# add more if needed...
# print out results...
print("Number of one pair hands is: ", onepairCount)
print("% of hands: ", 100.0 * onepairCount / TRIALS)
print("Number of two pair hands is: ", twopairCount)
print("% of hands: ", 100.0 * twopairCount / TRIALS)
print("Number of trips hand is: ", threeCount)
print("% of hands: ", 100.0 * threeCount / TRIALS)
print("Number of quads hand is: ", fourCount)
print("% of hands: ", 100.0 * fourCount / TRIALS)
print("Number of trips hand is: ", fullHouseCount)
print("% of hands: ", 100.0 * fullHouseCount / TRIALS)
print("Number of trips hand is: ", StraightCount)
print("% of hands: ", 100.0 * StraightCount / TRIALS)
def card_example():
card1 = Card() # Card(1,3) => Ace of Clubs
card2 = Card(12, 2) # Card (12,2) => Queen of Hearts
card1._newfield = 47 # we can add new fields to any Python object!
# three ways of printing a Card
#
print(card1.__str__()) # calling the methods against card
print(str(card2)) # type-casting
print(card2) # short-cut: passing obj ref to print does str() automagically
print(card1._newfield) # see the new field value?
print(card1._rank) # see the rank (1..13)
print(card1._suit) # see the suit (0..3)
def deck_example():
"""
Test Deck: create, print then shuffle, print again
Then deal first two cards and print, along with bottom card
"""
deck = Deck()
print(str(deck)) # see entire deck before shuffling
print("Now we shuffle:\n")
deck.shuffle()
print(str(deck)) # see entire deck after shuffling
card1 = deck.dealCard()
card2 = deck.dealCard()
print("The first card dealt is", str(card1), "and the second is", str(card2))
print("Bottom of deck is", deck._cards[-1]) # can't hide the implementation!
if __name__ == "__main__": # only run this if this .py is NOT imported
# pass
# card_example() # uncomment to test creating & calling Card methods
# deck_example() # uncomment to test Deck: create, print, shuffle, print
main() # uncomment to run general poker odds calculations
#
# -------------------------------------------------------------------------
#
#pytest follows...
def test_one_pair():
testhand = [Card(2, 3), Card(1, 2),
Card(3, 1), Card(13, 2),
Card(2, 0)]
dict = buildDict(testhand)
assert hasOnePair(dict) #hasTwoPairs
def test_two_pair():
testhand = [Card(2, 3), Card(1, 2),
Card(3, 1), Card(3, 2),
Card(2, 0)]
dict = buildDict(testhand)
assert hasTwoPairs(dict)
def test_three_pair():
testhand = [Card(1, 3), Card(1, 2),
Card(1, 1), Card(13, 2),
Card(2, 0)]
dict = buildDict(testhand)
assert hasThreeOfAKind(dict)
def has_Four_Of_A_Kind():
testhand = [Card(1, 3), Card(1, 2),
Card(1, 1), Card(1, 0),
Card(2, 0)]
dict = buildDict(testhand)
assert hasFourOfAKind(dict)
def test_full_house():
testhand = [Card(1, 3), Card(1, 2),
Card(1, 1), Card(13, 2),
Card(13, 2)]
dict = buildDict(testhand)
assert hasFullHouse(dict)
def test_Straight():
testhand = [Card(11, 1), Card(10, 3),
Card(9, 2), Card(8, 1),
Card(7, 3)]
dict = buildDict(testhand)
assert hasStraight(dict)
答案 0 :(得分:1)
顺子的条件是您的五张牌具有相邻的等级,这样就不会有两张牌具有相同的等级。您可以使用两种不同的检查来确认这一点:
以下是该示例的实现:
def hasStraight(hand):
# account for both low-ace and high-ace
ranks_low = sorted([card._rank for card in hand])
ranks_high = sorted([(14 if card._rank == 1 else card._rank) for card in hand])
return (
(
ranks_low[-1] - (len(hand) - 1) == ranks_low[0]
or ranks_high[-1] - (len(hand) - 1) == ranks_high[0]
) # condition 1
and len(set(hand)) == len(hand) # condition 2
)
您还必须考虑低位和高位。例如,您可以通过两次类似的检查来完成此操作,一次检查正常的卡片等级,一次执行类似“ if card._rank == 1:card._rank == 14
同花顺的条件是,所有牌都是相同的花色。这很容易验证,只需简单地手工制作所有set
中所有独特的花色,然后返回true
(如果该花色只有一个元素(因此所有花色必须相同)):>
def hasFlush(hand):
suits_set = set(*[card._suit for card in hand])
return len(suits_set) == 1
一旦有了这些,同花顺和皇家同花顺就很容易了:
def hasStraightFlush(hand):
return hasStraight(hand) and hasFlush(hand)
def hasRoyalFlush(hand):
ranks = sorted([14 if card._rank == 1 else card._rank for card in hand])
return (
hasStraightFlush(hand)
and ranks[0] == 10 and ranks[-1] == 14
) # royal flush starts at 10, ends at high-ace