我正在Udacity中学习CS212,并具有以下代码。
用户说明: 编写一个函数best_wild_hand(hand) 输入7张牌并返回最佳5张牌。 在这个问题上,一只手可能会包括 说笑话者小丑将被视为“通配符”, 可以采用相同颜色的任何等级或西服。的 黑色小丑'?B'可以用作任何黑桃或棍棒 红色的小丑'?R'可以用作任何心脏 或钻石。
代码如下:
import itertools
def best_wild_hand(hand):
"Try all values for jokers in all 5-card selections."
if '?B' not in hand and '?R' not in hand:
return max(itertools.combinations(hand,5), key=hand_rank)
black = [ i+j for i in list('23456789TJQKA') for j in ['S','C']]
red = [ i+j for i in list('23456789TJQKA') for j in ['H','D']]
cards = []
hands = []
if '?B' in hand and '?R' not in hand:
for item in black:
temp = hand[:]
temp[temp.index('?B')] = item
cards.append(temp)
elif '?R' in hand and '?B' not in hand:
for item in red:
temp = hand[:]
temp[temp.index('?R')] = item
cards.append(temp)
else:
for i in black:
for j in red:
temp = hand[:]
temp[temp.index('?B')] = i
temp[temp.index('?R')] = j
cards.append(temp)
#cards = set(cards)
for card in cards:
hands += itertools.combinations(card, 5)
#print(len(hands))
#hands = set(hands)
#print(len(hands))
return max(hands, 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())
上面的代码工作正常。但是,当我将def best_wild_hand(hand)中的最后一行更改为
时 return max(set(hands), key=hand_rank)
结果错误。为什么我将list
转换为set
而max()
不起作用?谢谢
答案 0 :(得分:1)
max(set(hands))
的返回不稳定,有时返回错误答案,有时正确。经过大量挖掘,我认为我已经找到了错误的来源。首先,您的逻辑是正确的:通过调用set(),您删除了重复项,因此无论是否存在重复项,结果都应该相同。
在原始代码中,如果第二个测试用例被注释掉,则使用set(hands)
将通过其他用例(至少在我的环境中)。因此,问题可能出在第二个测试用例上。
如果您隔离出第二个测试用例,并使用set(hands)
运行该程序20次,那么棘手的事情就会发生:大多数情况下,测试用例失败,但实际上几次通过!
这太疯狂了!相同的代码给出不同的结果。第二个测试用例的正确输出是('TD', 'TC', '7C', 'TH', 'TS')
。但是max函数还将返回至少两个其他输出('TD', 'TC', '7C', 'TH', 'TC')
和('TD', 'TC', '7C', 'TD', 'TS')
。
如果在所有这三只指针上调用hand_rank()
时都检查了返回值,则结果是相同的(7, 10, 7)
。换句话说,这三只手的排名相同。因此,将哪个作为最大返回值取决于传递给max函数的是列表还是集合。
如果通过了列表(如hands
的情况),则返回第一次出现的最大值。在这种情况下,('TD', 'TC', '7C', 'TH', 'TS')
的索引是9081,('TD', 'TC', '7C', 'TH', 'TC')
的索引是9627,('TD', 'TC', '7C', 'TD', 'TS')
的索引是9102。因此,如果通过hands
,则正确答案始终返回('TD', 'TC', '7C', 'TH', 'TS')
。
如果传递了一个集合,则由于没有内部排序,因此返回的值可能会有所不同,这正是我们观察到的行为。为了进行进一步的测试,您可以尝试以下方法:
max([(2,'a'),(2,'b'),(2,'c')],key=lambda x:x[0]) # output (2, 'a')
max({(2,'a'),(2,'b'),(2,'c')},key=lambda x:x[0]) # output (2, 'c') or any of the other two depending on implementation
总而言之,通过set(hands)
时测试失败的原因是在多个元素具有相同排名时调用max on set的与实现有关的行为。但是,为了进一步推动这一问题,运气好的话,用hands
返回正确的答案可能是纯粹的运气,因为如果在组合步骤中将错误的答案附加在正确的答案之前,那么错误的答案将是最大功能。我想说测试用例应该修改为包括所有这三只手,作为潜在的正确答案。