《Design of Computer Programs》学习笔记(1 - 4)Winning Poker Hands - Problem Set 1

本文探讨了在七张牌游戏中找出最佳五张牌组合的算法实现,利用Python的itertools库来生成所有可能的手牌组合,并通过排序选出最优解。此外,还介绍了如何处理包含百搭牌(Jokers)的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Winning Poker Hands

Problem Set 1

视频链接:
Problem Set 1 - Udacity

1. Seven Card Stud

补充知识:itertools.combinations(iterable, r)

combinations(iterable, r)方法,创建一个迭代器,返回iterable中所有长度为r的子序列,返回的子序列中的项按输入iterable中的顺序排序 (不带重复)

>>> from itertools import combinations
>>> combinations('ABCD', 2)
<itertools.combinations object at 0x7f3e6dd81050>
>>> for item in combinations('ABCD', 2):
...     print item
...
('A', 'B')
('A', 'C')
('A', 'D')
('B', 'C')
('B', 'D')
('C', 'D')

1手牌(a hand)里面有7张牌(7 cards),返回最好的5张牌的1手牌(the best 5 card hand)。

# 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."
    """
    先谈下我的思路:
    从7张牌中,取出任意5章牌,
    所有的任意5张牌的情况,全部遍历,
    比较所有的hand_rank(hand为5张牌)的情况,
    返回最大的hand_rank值。
    不知道能不能写出来代码,先把思路列出来。
    貌似算法效率有点低。

    result = []
    for i in range(7):
        hand2 = hand[:]
        hand2.pop(i)
        for j in range(6):
            hand3 = hand[:]
            hand3.pop(j)
            result.append(hand_rank(hand))
    return max(result)

    按理说,我的代码的逻辑是没问题的,但是测试不通过。。
    print best_hand("6C 7C 8C 9C TC 5C JS".split())的输出是
    (0, [11, 10, 9, 8, 7, 6, 5])
    WTF!!!
    """
    # 还是来看看Peter的代码吧。。
    '''
    Peter的思路跟我的差不多,
    首先,生成7张牌的所有的5张牌的组合
    (使用了itertools.combinations方法),
    然后,按照key=hand_rank排序。
    '''
    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'])
            # 5C 6C 7C 8C 9C TC JS,返回了
            # 6到J的同花顺。
    assert (sorted(best_hand("TD TC TH 7C 7D 8C 8S".split()))
            == ['8C', '8S', 'TC', 'TD', 'TH'])
            # 3带1对儿,返回了
            # 较大的那1对儿,并且
            # 似乎对花色进行了排序
    assert (sorted(best_hand("JD TC TH 7C 7D 7S 7H".split()))
            == ['7C', '7D', '7H', '7S', 'JD'])
            # 4个7加1对儿10,再加1张J,返回了
            # 4个7加1张J,并且
            # 似乎对花色进行了排序
    return 'test_best_hand passes'

print test_best_hand()

2. Jokers Wild

jokers n.纸牌中可当任何点数用的一张(金山词霸)

关于Peter的解法的一点预备知识:product函数

对map的复习:
map(func, alist)是对一个列表alist中的每1个元素,应用函数func,返回新的列表。

>>> def f(x):
...     return x + 1
...
>>> map(f, [55, 66, 88])
[56, 67, 89]
## Poker Homework 1, problem 2: Jokers

## Deck adds two cards:
## '?B': black joker; can be used as any black card (S or C)
## '?B': black joker; 可以被用作任何黑色的卡牌(S或者C)
## '?R': red joker; can be used as any red card (H or D)
## '?R': red joker;可以被用作任何红色的卡牌(H或者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."
    # Peter的答案
    hands = set(best_hand(h)
                for h in itertools.product(*map(replacements, hand)))
    '''map(replacements, hand)做了什么?
    它是对一手牌hand中的每1张牌card,应用了replacements函数,
    返回每1张卡牌的可能的情况的1个列表。
    如果card不是1个joker,这个列表会是1。
    (我的理解是,原样返回一个列表[hand])
    如果card是1个joker,这个列表会是所有的red cards或者black cards。
    '''
    return max(hand, 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."""
    '''
    如果card是black joker,即'?B',
    则返回前面定义的blackcards列表
    '''
    if card == '?B': return blackcards
    '''
    如果card是red joker,即'?R',
    则返回前面定义的redcards列表
    '''
    elif card =='?R': return redcards
    '''
    如果都不是,则原样返回[card]。
    '''
    else: return [card]

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 7C 7D ?R ?B".split()))
            == ['7C', 'TC', 'TD', 'TH', 'TS'])
    assert (sorted(best_wild_hand("TD TC TH 7C 7D 7S 7H".split()))
            == ['7C', '7D', '7H', '7S', 'TD'])
    return 'test_best_wild_card passes'

print test_best_wild_hand()

参考文献:

  1. Design of Computer Programs - 英文介绍 - Udacity
  2. Design of Computer Programs - 中文介绍 - 果壳
  3. Design of Computer Programs - 视频列表 - Udacity
  4. Design of Computer Programs - 视频列表 - YouTube
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值