CS212 - poker程序
poker程序文档 by huangke
基于 https://www.udacity.com/wiki/cs212/unit-1
Unit 1: 决胜扑克游戏
内容
-
S212 - Unit 1: Winning Poker Hands
-
1.1 Outlining the Problem
- 1.1.1 练习: Representing Hands
-
1.2 Wild West Poker
- 1.2.1 练习: Poker 函数
- 1.2.2 练习: 掌握 Max
- 1.2.3 练习: 使用 Max
- 1.2.4 练习: 测试函数
- 1.2.5 练习: Extreme Values
- 1.2.6 练习: Hand Rank Attempt
- 1.2.7 练习: Representing Rank
-
1.3 Back to Hand Rank
- 1.3.1 练习: Testing Hand Rank
- 1.3.2 练习: Writing Hand Rank
- 1.3.3 练习: Testing Card Rank
- 1.3.4 练习: Fixing Card Rank
- 1.3.5 练习: Straight and Flush
- 1.3.6 练习: Kind Function
- 1.3.7 练习: Two Pair Function
- 1.3.8 练习: Making Changes
- 1.3.9 练习: What to Change
- 1.3.10 Ace Low Straight
- 1.3.11 练习: Handling Ties
- 1.3.12 练习: Allmax
-
1.4 Deal
- 1.4.1 练习: Hand Frequencies
- 1.5 Dimensions of Programming
- 1.6 Refactoring
- 1.7 Summary
- 1.8 Bonus - Shuffling
- 1.9 Complete Code For Poker Problem
- 1.10 Complete Code For Homeworks (Warning: Refer this only after submitting homework)
-
归纳和描述问题
Unit1- 2
写poker程序是一个很好的示例,程序设计从普遍意义上来说主要分为三步:
- 理解问题
- 准确描述
- 设计程序
这个设计过程需要你从一个对问题的模糊理解开始,提炼出正式和准确的问题描述,然后将问题分解为更小的部分,你进一步细化描述你对这些部分的理解,直到可以将其代码化,当设计过程结束后,最后一项工作就是编写代码。
Step 1: 理解问题
从对问题的模糊理解开始. 在这一步我们要列出一个概念清单出来,谈到写一个poker程序,应该从“一手牌”(hand)这个概念开始,a hand表示有5张牌,而且,每张牌有不同的数字和花色。
另一个需要定义的概念是“hand rank”,每一hand 对应的rank,它针对不同的hand返回代表此hand的细节表示
Step 2: 准备描述
明确这个问题应该如何以代码来描述,这个你要明确的主函数叫poker,它应该以一个hands列表作为输入,以highest rank的hand作为输出。
highest hand描述如下:
http://en.wikipedia.org/wiki/List_of_poker_hands
这些规则指明了hands之间的比较规则。
There are three concepts that make up the hand rank:
为了完成hand rank,需要3个概念:
- Kind表示有多少张数字一样的牌,'n-kind',n可以为1,2,3,4
- Straight表示5张牌数字相连,花色不重要
- Flush表示5张牌花色一样,数字不重要
现在你明确了你要处理的数据类型,"hands","ranks","suits",你也知道了他们对应的函数 n-kind, straight, flush,现在我们可以进入第3步了,程序设计阶段
Step 3: Design working code
Unit1-3/
Quiz: Representing Hands
Which of the possible representations for a hand makes the most sense. There may be more than one.
a. ['JS', 'JD', '2S', '2C', '7H']
b. [(11, 'S'), (11, 'D'), (2, 'S'), (2, 'C'), (7, 'H')]
c. set (['JJ', 'JD', '2S', '2C', '7H')])
d. "JS JD 2S 2C 7H"
Wild West Poker
答案:
正确答案: 1、2
set 为什么不行? 因为有百搭牌的存在(大小王)
str 为为什么不行? 因为还有split一次,不直观
Unit1-11/
A poker player will call out his hand when he has to reveal it. With this information you will know how to rank and assign the hand.
一个扑克玩家会在他必须展示牌的时候call out他的牌,由此你可以知道这手牌的rank和其他信息。
"Straight flush, Jack high!"
这手牌的信息:一个straight,最大牌是J.
Here is a ranking table of the possible hands:
这些是所有手牌对应的ranking:
- 0- High Card
- 1- One Pair
- 2- Two Pair
- 3- Three of a Kind
- 4- Straight
- 5- Flush
- 6- Full House
- 7- Four of a Kind
- 8- Straight Flush
当你写程序的时候使用这些手牌对应的数字
"Straight flush, Jack high!" 可以写成下面这样表示:
(8, 11)
Here the eight stands for straight flush and the number 11 stands for the Jack.
这里8代表了straight flush的rank, 11代表了Jack
Here are a few examples of what a player might say and how you would write their hand:
这里是一些手牌的叫法和对应的写法:
Four aces and a queen kicker?
(7, 14, 12)
注意,当你有1对,2对,3张一样的,4张一样的牌的时候,就会有一个单独的参数来表明你拥有的kind。
7 - rank , 14 - ace , 12 - extra
Full house, eights over kings?
(6, 8, 13)
即使K比8大,但是8有三张,所以8更重要,排前面
Flush, 10-8!
一般来说,只需要最大的前两张牌就可以区分开不同的flush, 但是极端情况下你需要全部5张,从大到小排列以方便比较。
(5, [10, 8, 7, 5, 3])
Straight, Jack high
对于straight,你只需要知道最大的就可以了
(4, 11)
Three sevens!
3-kind 极端情况下需要把另外两张也写出来以分胜负
(3, 7, [7, 7, 7, 5, 2])
Two pairs, Jacks and threes
先写高的一对牌的值,然后是低的一对,然后是所有牌的sorted(list)
(2, 11, 3, [13, 11, 11, 3, 3])
Pair of twos, Jack high
先写对牌数值,再写sorted(list)
(1, 2, [11, 6, 3, 2, 2])
Got nothing
high card, 5张牌排序即可
(0, 7, 5, 4, 3, 2)
Quiz: Poker Function
Unit1-4/
对于一列hands,我们希望poker程序返回 the highest-ranking hand,你知道Python中哪个内建函数返回一个列表中的最大值吗?
Given:
def poker(hands):
"return the best hand: poker([hand,...]) => hand"
return ???
答案: max
小测试: Understanding Max
print(max([3, 4, 5, 0]), max([3, 4, -5, 0], key=abs))
答案: 5, 5
Unit1-5/
What will the two max calls return?
def poker(hands):
"Return the best hand: poker ([hand, ...]) => hand"
return max
Quiz: Using Max
Unit1-6/
Assume that you have defined a function hand_rank, which takes a hand as input and returns some sort of a rank. Given this, how would you write the definition of the function poker to return the maximum hand according to the highest ranked?
def poker(hands):
"Return the best hand: poker([hand, ...]) => hand"
return max
def hand_rank(hand):
return ???
print max([3, 4, 5, 0]), max ([3, 4, -5, 0], key = abs)
Quiz: Testing
Unit1-7/
Modify the test() function to include two new test cases:
- four of a kind (fk) vs. full house (fh) returns fk.
- full house (fh) vs. full house (fh) returns fh.
def poker(hands): "Return the best hand: poker([hand,...]) => hand" return max(hands, key=hand_rank)
def test(): "Test cases for the functions in poker program" sf = "6C 7C 8C 9C TC".split() # => ['6C', '7C', '8C', '9C', 'TC'] fk = "9D 9H 9S 9C 7D".split() fh = "TD TC TH 7C 7D".split() assert poker([sf, fk, fh]) == sf assert poker([fk, fh]) == fk assert poker([fh, fh]) == fh
-
Add 2 new assert statements here. The first
-
should check that when fk plays fh, fk
-
is the winner. The second should confirm that
-
fh playing against fh returns fh.
print test()
Quiz: Extreme Values
Unit1-8/
Quiz: Hand Rank Attempt
Unit1-9/
Quiz: Representing Rank
Unit1-10/
Back to Hand Rank
Unit1-12/
Quiz: Testing Hand Rank
Unit1-13/
Quiz: Writing Hand Rank
Unit1-14/
Quiz: Testing Card Rank
Unit1-15/
Quiz: Fixing Card Rank
Unit1-16/
Quiz: Straight and Flush
Unit1-17/
Quiz: Kind Function
Unit1-18/
Quiz: Two Pair Function
Unit1-19/
Quiz: Making Changes
Unit1-20/
Quiz: What to Change
Unit1-21/
Ace Low Straight
Unit1-22/
Quiz: Handling Ties
Unit1-23/
Quiz: Allmax
Unit1-24/
Deal
Unit1-25/
Quiz: Hand Frequencies
Unit1-26/
This is the procedure Peter gave us to calculate hand frequencies:
def hand_percentages(n=7001000):
counts = [0]9
for i in range(n/10):
for hand in deal(10):
ranking = hand_rank(hand)[0]
counts[ranking] += 1
for i in reversed(range(9)):
print "%15s: %6.3f %%" % (hand_names[i], 100.*counts[i]/n)
Dimensions of Programming
Unit1-27/
Refactoring
Unit1-28/
The two alternative versions of hand_rank that Peter gave in the refactoring class are:
def hand_rank_alt(hand):
"Return a value indicating how high the hand ranks."
# count is the count of each rank; ranks lists corresponding ranks
# E.g. '7 T 7 9 7' => counts = (3, 1, 1) ranks = (7, 10, 9)
groups = group(['--23456789TJQKA'.index(r) for r,s in hand])
counts, ranks = unzip(groups)
if ranks == (14, 5, 4, 3, 2): # Ace low straight
ranks = (5, 4, 3, 2, 1)
straight = len(ranks) == 5 and max(ranks) - min(ranks) == 4
flush = len(set([s for r,s in hand])) == 1
return (9 if (5,) == counts else
8 if straight and flush else
7 if (4, 1) == counts else
6 if (3, 2) == counts else
5 if flush else
4 if straight else
3 if (3, 1, 1) == counts else
2 if (2, 2, 1) == counts else
1 if (2, 1, 1, 1) == counts else
0), ranks
def group(items):
"Return a list of [(count, x), ...], highest count first, then highest x first"
groups = [(items.count(x), x) for x in set(items)]
return sorted(groups, reverse = True)
def unzip(iterable):
"Return a tuple of lists from a list of tuples : e.g. [(2, 9), (2, 7)] => ([2, 2], [9, 7])"
return zip(*iterable)
The table-based lookup version:
count_rankings = {(5,): 10, (4, 1): 7, (3, 2): 6, (3, 1, 1): 3, (2, 2, 1): 2,
(2, 1, 1, 1): 1, (1, 1, 1, 1, 1): 0}
def hand_rank_table(hand):
"Return a value indicating how high the hand ranks."
# count is the count of each rank; ranks lists corresponding ranks
# E.g. '7 T 7 9 7' => counts = (3, 1, 1) ranks = (7, 10, 9)
groups = group(['--23456789TJQKA'.index(r) for r,s in hand])
counts, ranks = unzip(groups)
if ranks == (14, 5, 4, 3, 2): # Ace low straight
ranks = (5, 4, 3, 2, 1)
straight = len(ranks) == 5 and max(ranks) - min(ranks) == 4
flush = len(set([s for r,s in hand])) == 1
return max(count_rankings[counts], 4straight + 5flush), ranks
Summary
Unit1-29/
Bonus - Shuffling
Bad Shuffle/
Shuffle Runtime/
Good Shuffle/
Is it Random/
Testing Shuffles/
Comparing Shuffles/
Computing or Doing/
The shuffling procedures from the bonus videos are:
def shuffle1(p):
n = len(p)
swapped = [False]*n
while not all(swapped):
i, j = random.randrange(n), random.randrange(n)
swap(p, i, j)
swapped[i] = swapped[j] = True
def shuffle2(p):
n = len(p)
swapped = [False]*n
while not all(swapped):
i, j = random.randrange(n), random.randrange(n)
swap(p, i, j)
swapped[i] = True
def shuffle3(p):
n = len(p)
for i in range(n):
swap(p, i, random.randrange(n))
def knuth(p):
n = len(p)
for i in range(n-1):
swap(p, i, random.randrange(i, n))
def swap(p, i, j):
p[i], p[j] = p[j], p[i]
The procedures for testing the different shuffles were:
def test_shuffle(shuffler, deck = 'abcd', n = 10000):
counts = defaultdict(int)
for _ in range(n):
input = list(deck)
shuffler(input)
counts[''.join(input)] += 1
e = n * 1./factorial(len(deck))
ok = all((0.9 <= counts[item]/e <= 1.1) for item in counts)
name = shuffler.name
print '%s(%s) %s' % (name, deck, ('ok' if ok else '*** BAD ***'))
print ' ',
for item, count in sorted(counts.items()):
print "%s:%4.1f" % (item, count * 100. / n),
print
def test_shufflers(shufflers = [knuth, shuffle1, shuffle2, shuffle3], decks = ['abc', 'ab']):
for deck in decks:
print
for f in shufflers:
test_shuffle(f, deck)
def factorial(n):
return 1 if n<= 1 else n * factorial(n-1)
Complete Code For Poker Problem
The complete code given by Peter in this unit including some additional test cases:
! /usr/bin/env python
import random
def poker(hands):
"Return a list of winning hands: poker([hand,...]) => [hand,...]"
return allmax(hands, key=hand_rank)
def allmax(iterable, key=None):
"Return a list of all items equal to the max of the iterable."
iterable.sort(key=key,reverse=True)
result = [iterable[0]]
maxValue = key(iterable[0]) if key else iterable[0]
for value in iterable[1:]:
v = key(value) if key else value
if v == maxValue: result.append(value)
else: break
return result
def card_ranks(hand):
"Return a list of the ranks, sorted with higher first."
ranks = ['--23456789TJQKA'.index(r) for r, s in hand]
ranks.sort(reverse = True)
return [5, 4, 3, 2, 1] if (ranks == [14, 5, 4, 3, 2]) else ranks
def flush(hand):
"Return True if all the cards have the same suit."
suits = [s for r,s in hand]
return len(set(suits)) == 1
def straight(ranks):
"Return True if the ordered ranks form a 5-card straight."
return (max(ranks)-min(ranks) == 4) and len(set(ranks)) == 5
def kind(n, ranks):
"""Return the first rank that this hand has exactly n-of-a-kind of.
Return None if there is no n-of-a-kind in the hand."""
for r in ranks:
if ranks.count(r) == n: return r
return None
def two_pair(ranks):
"If there are two pair here, return the two ranks of the two pairs, else None."
pair = kind(2, ranks)
lowpair = kind(2, list(reversed(ranks)))
if pair and lowpair != pair:
return (pair, lowpair)
else:
return None
def hand_rank(hand):
"Return a value indicating the ranking of a hand."
ranks = card_ranks(hand)
if straight(ranks) and flush(hand):
return (8, max(ranks))
elif kind(4, ranks):
return (7, kind(4, ranks), kind(1, ranks))
elif kind(3, ranks) and kind(2, ranks):
return (6, kind(3, ranks), kind(2, ranks))
elif flush(hand):
return (5, ranks)
elif straight(ranks):
return (4, max(ranks))
elif kind(3, ranks):
return (3, kind(3, ranks), ranks)
elif two_pair(ranks):
return (2, two_pair(ranks), ranks)
elif kind(2, ranks):
return (1, kind(2, ranks), ranks)
else:
return (0, ranks)
def hand_rank_alt(hand):
"Return a value indicating how high the hand ranks."
# count is the count of each rank; ranks lists corresponding ranks
# E.g. '7 T 7 9 7' => counts = (3, 1, 1) ranks = (7, 10, 9)
groups = group(['--23456789TJQKA'.index(r) for r,s in hand])
counts, ranks = unzip(groups)
if ranks == (14, 5, 4, 3, 2): # Ace low straight
ranks = (5, 4, 3, 2, 1)
straight = len(ranks) == 5 and max(ranks) - min(ranks) == 4
flush = len(set([s for r,s in hand])) == 1
return (9 if (5,) == counts else
8 if straight and flush else
7 if (4, 1) == counts else
6 if (3, 2) == counts else
5 if flush else
4 if straight else
3 if (3, 1, 1) == counts else
2 if (2, 2, 1) == counts else
1 if (2, 1, 1, 1) == counts else
0), ranks
count_rankings = {(5,): 10, (4, 1): 7, (3, 2): 6, (3, 1, 1): 3, (2, 2, 1): 2,
(2, 1, 1, 1): 1, (1, 1, 1, 1, 1): 0}
def hand_rank_table(hand):
"Return a value indicating how high the hand ranks."
# count is the count of each rank; ranks lists corresponding ranks
# E.g. '7 T 7 9 7' => counts = (3, 1, 1) ranks = (7, 10, 9)
groups = group(['--23456789TJQKA'.index(r) for r,s in hand])
counts, ranks = unzip(groups)
if ranks == (14, 5, 4, 3, 2): # Ace low straight
ranks = (5, 4, 3, 2, 1)
straight = len(ranks) == 5 and max(ranks) - min(ranks) == 4
flush = len(set([s for r,s in hand])) == 1
return max(count_rankings[counts], 4straight + 5flush), ranks
def group(items):
"Return a list of [(count, x), ...], highest count first, then highest x first"
groups = [(items.count(x), x) for x in set(items)]
return sorted(groups, reverse = True)
def unzip(iterable):
"Return a list of tuples from a list of tuples : e.g. [(2, 9), (2, 7)] => [(2, 2), (9, 7)]"
return zip(*iterable)
mydeck = [r+s for r in '23456789TJQKA' for s in 'SHDC']
def deal(numhands, n=5, deck=mydeck):
random.shuffle(mydeck)
return [mydeck[ni:n(i+1)] for i in range(numhands)]
hand_names = ["Straight flush", "Four of a kind", "Full house", "Flush", "Straight",
"Three of a kind", "Two pair", "One pair", "High card"]
def hand_percentages(n=7001000):
counts = [0]9
for i in range(n/10):
for hand in deal(10):
ranking = hand_rank(hand)[0]
counts[ranking] += 1
for i in reversed(range(9)):
print "%15s: %6.3f %%" % (hand_names[i], 100.*counts[i]/n)
def test():
"Test cases for the functions in poker program."
sf1 = "6C 7C 8C 9C TC".split() # Straight Flush
sf2 = "6D 7D 8D 9D TD".split() # Straight Flush
fk = "9D 9H 9S 9C 7D".split() # Four of a Kind
fh = "TD TC TH 7C 7D".split() # Full House
tp = "5D 2C 2H 9H 5C".split() # Two Pair
# Testing allmax
assert allmax([2,4,7,5,1]) == [7]
assert allmax([2,4,7,5,7]) == [7,7]
assert allmax([2]) == [2]
assert allmax([0,0,0]) == [0,0,0]
# Testing card_ranks
assert card_ranks(sf1) == [10, 9, 8, 7, 6]
assert card_ranks(fk) == [9, 9, 9, 9, 7]
assert card_ranks(fh) == [10, 10, 10, 7, 7]
# Testing flush
assert flush([]) == False
assert flush(sf1) == True
assert flush(fh) == False
# Testing straight
assert straight(card_ranks(sf1)) == True
assert straight(card_ranks(fk)) == False
# Testing kind
assert kind(3, card_ranks(sf1)) == None
assert kind(4, card_ranks(fk)) == 9
# Tesing two pair
assert two_pair(card_ranks(sf1)) == None
assert two_pair(card_ranks(tp)) == (5,2)
# Testing group
assert group([2,3,4,6,2,1,9]) == [(2,2),(1,9),(1,6),(1,4),(1,3),(1,1)]
assert group([8,8,8,8]) == [(4,8)]
assert group([2,6,1]) == [(1,6),(1,2),(1,1)]
# Testing unzip
assert unzip([(2,2),(1,9),(1,6),(1,4),(1,3),(1,1)]) == [(2,1,1,1,1,1),(2,9,6,4,3,1)]
assert unzip([(1,6),(1,2),(1,1)]) == [(1,1,1),(6,2,1)]
assert unzip([(2, 9), (2, 7)]) == [(2, 2), (9, 7)]
# Testing hand rank
assert hand_rank(sf1) == (8,10)
assert hand_rank(fk) == (7,9,7)
assert hand_rank(fh) == (6,10,7)
# Testing hand rank alt
assert hand_rank_alt(sf1) == (8, (10,9,8,7,6))
assert hand_rank_alt(fk) == (7,(9,7))
assert hand_rank_alt(fh) == (6,(10,7))
# Testing hand rank table
assert hand_rank_table(sf1) == (9, (10,9,8,7,6))
assert hand_rank_table(fk) == (7,(9,7))
assert hand_rank_table(fh) == (6,(10,7))
# Testing poker
assert poker([sf1, fk, fh]) == [sf1]
assert poker([fk, fh]) == [fk]
assert poker([fh, fh]) == [fh, fh]
assert poker([fh]) == [fh]
assert poker([sf2] + 99*[fh]) == [sf2]
assert poker([sf1, sf2, fk, fh]) == [sf1, sf2]
return 'tests pass'
Complete Code For Homeworks (Warning: Refer this only after submitting homework)
The complete homework solution code given by Peter in this unit.
Homework 1:
CS 212, hw1-1: 7-card stud
-----------------
User Instructions
Write a function best_hand(hand) that takes a seven
card hand as input and returns the best possible 5
card hand. The itertools library has some functions
that may help you solve this problem.
-----------------
Grading Notes
Muliple correct answers will be accepted in cases
where the best hand is ambiguous (for example, if
you have 4 kings and 3 queens, there are three best
hands: 4 kings along with any of the three queens).
import itertools
def best_hand(hand):
"From a 7-card hand, return the best 5 card hand."
return max(itertools.combinations(hand, 5), key=hand_rank)
------------------
Provided Functions
You may want to use some of the functions which
you have already defined in the unit to write
your best_hand function.
def hand_rank(hand):
"Return a value indicating the ranking of a hand."
ranks = card_ranks(hand)
if straight(ranks) and flush(hand):
return (8, max(ranks))
elif kind(4, ranks):
return (7, kind(4, ranks), kind(1, ranks))
elif kind(3, ranks) and kind(2, ranks):
return (6, kind(3, ranks), kind(2, ranks))
elif flush(hand):
return (5, ranks)
elif straight(ranks):
return (4, max(ranks))
elif kind(3, ranks):
return (3, kind(3, ranks), ranks)
elif two_pair(ranks):
return (2, two_pair(ranks), ranks)
elif kind(2, ranks):
return (1, kind(2, ranks), ranks)
else:
return (0, ranks)
def card_ranks(hand):
"Return a list of the ranks, sorted with higher first."
ranks = ['--23456789TJQKA'.index(r) for r, s in hand]
ranks.sort(reverse = True)
return [5, 4, 3, 2, 1] if (ranks == [14, 5, 4, 3, 2]) else ranks
def flush(hand):
"Return True if all the cards have the same suit."
suits = [s for r,s in hand]
return len(set(suits)) == 1
def straight(ranks):
"""Return True if the ordered
ranks form a 5-card straight."""
return (max(ranks)-min(ranks) == 4) and len(set(ranks)) == 5
def kind(n, ranks):
"""Return the first rank that this hand has
exactly n-of-a-kind of. Return None if there
is no n-of-a-kind in the hand."""
for r in ranks:
if ranks.count(r) == n: return r
return None
def two_pair(ranks):
"""If there are two pair here, return the two
ranks of the two pairs, else None."""
pair = kind(2, ranks)
lowpair = kind(2, list(reversed(ranks)))
if pair and lowpair != pair:
return (pair, lowpair)
else:
return None
def test_best_hand():
assert (sorted(best_hand("6C 7C 8C 9C TC 5C JS".split()))
== ['6C', '7C', '8C', '9C', 'TC'])
assert (sorted(best_hand("TD TC TH 7C 7D 8C 8S".split()))
== ['8C', '8S', 'TC', 'TD', 'TH'])
assert (sorted(best_hand("JD TC TH 7C 7D 7S 7H".split()))
== ['7C', '7D', '7H', '7S', 'JD'])
return 'test_best_hand passes'
print test_best_hand()
Homework 2:
CS 212, hw1-2: Jokers Wild
-----------------
User Instructions
Write a function best_wild_hand(hand) that takes as
input a 7-card hand and returns the best 5 card hand.
In this problem, it is possible for a hand to include
jokers. Jokers will be treated as 'wild cards' which
can take any rank or suit of the same color. The
black joker, '?B', can be used as any spade or club
and the red joker, '?R', can be used as any heart
or diamond.
The itertools library may be helpful. Feel free to
define multiple functions if it helps you solve the
problem.
-----------------
Grading Notes
Muliple correct answers will be accepted in cases
where the best hand is ambiguous (for example, if
you have 4 kings and 3 queens, there are three best
hands: 4 kings along with any of the three queens).
import itertools
Deck adds two cards:
'?B': black joker; can be used as any black card (S or C)
'?R': red joker; can be used as any red card (H or D)
allranks = '23456789TJQKA'
redcards = [r+s for r in allranks for s in 'DH']
blackcards = [r+s for r in allranks for s in 'SC']
def best_wild_hand(hand):
"Try all values for jokers in all 5-card selections."
hands = set(best_hand(h)
for h in itertools.product(*map(replacements, hand)))
return max(hands, key=hand_rank)
def replacements(card):
"""Return a list of the possible replacements for a card.
There will be more than 1 only for wild cards."""
if card == '?B': return blackcards
elif card == '?R': return redcards
else: return [card]
def best_hand(hand):
"From a 7-card hand, return the best 5 card hand."
return max(itertools.combinations(hand, 5), key=hand_rank)
def test_best_wild_hand():
assert (sorted(best_wild_hand("6C 7C 8C 9C TC 5C ?B".split()))
== ['7C', '8C', '9C', 'JC', 'TC'])
assert (sorted(best_wild_hand("TD TC 5H 5C 7C ?R ?B".split()))
== ['7C', 'TC', 'TD', 'TH', 'TS'])
assert (sorted(best_wild_hand("JD TC TH 7C 7D 7S 7H".split()))
== ['7C', '7D', '7H', '7S', 'JD'])
return 'test_best_wild_hand passes'
------------------
Provided Functions
You may want to use some of the functions which
you have already defined in the unit to write
your best_hand function.
def hand_rank(hand):
"Return a value indicating the ranking of a hand."
ranks = card_ranks(hand)
if straight(ranks) and flush(hand):
return (8, max(ranks))
elif kind(4, ranks):
return (7, kind(4, ranks), kind(1, ranks))
elif kind(3, ranks) and kind(2, ranks):
return (6, kind(3, ranks), kind(2, ranks))
elif flush(hand):
return (5, ranks)
elif straight(ranks):
return (4, max(ranks))
elif kind(3, ranks):
return (3, kind(3, ranks), ranks)
elif two_pair(ranks):
return (2, two_pair(ranks), ranks)
elif kind(2, ranks):
return (1, kind(2, ranks), ranks)
else:
return (0, ranks)
def card_ranks(hand):
"Return a list of the ranks, sorted with higher first."
ranks = ['--23456789TJQKA'.index(r) for r, s in hand]
ranks.sort(reverse = True)
return [5, 4, 3, 2, 1] if (ranks == [14, 5, 4, 3, 2]) else ranks
def flush(hand):
"Return True if all the cards have the same suit."
suits = [s for r,s in hand]
return len(set(suits)) == 1
def straight(ranks):
"""Return True if the ordered
ranks form a 5-card straight."""
return (max(ranks)-min(ranks) == 4) and len(set(ranks)) == 5
def kind(n, ranks):
"""Return the first rank that this hand has
exactly n-of-a-kind of. Return None if there
is no n-of-a-kind in the hand."""
for r in ranks:
if ranks.count(r) == n: return r
return None
def two_pair(ranks):
"""If there are two pair here, return the two
ranks of the two pairs, else None."""
pair = kind(2, ranks)
lowpair = kind(2, list(reversed(ranks)))
if pair and lowpair != pair:
return (pair, lowpair)
else:
return None
print test_best_wild_hand()
This page was last edited on 2014/04/25 08:51:12.
Udacity
POPULAR NANODEGREE PROGRAMS