博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
thinkpython2的扑克牌系列练习最终解读
阅读量:3924 次
发布时间:2019-05-23

本文共 12579 字,大约阅读时间需要 41 分钟。

首先放上Card的代码

"""This module contains a code example related toThink Python, 2nd Editionby Allen Downeyhttp://thinkpython2.comCopyright 2015 Allen DowneyLicense: http://creativecommons.org/licenses/by/4.0/"""from __future__ import print_function, divisionimport randomclass Card:    """Represents a standard playing card.    Attributes:      suit: integer 0-3      rank: integer 1-13    """    suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]    rank_names = [None, "Ace", "2", "3", "4", "5", "6", "7",                  "8", "9", "10", "Jack", "Queen", "King"]    def __init__(self, suit=0, rank=2):        self.suit = suit        self.rank = rank    def __str__(self):        """Returns a human-readable string representation."""        return '%s of %s' % (Card.rank_names[self.rank],                             Card.suit_names[self.suit])    def __eq__(self, other):        """Checks whether self and other have the same rank and suit.        returns: boolean        """        return self.suit == other.suit and self.rank == other.rank    def __lt__(self, other):        """Compares this card to other, first by suit, then rank.        returns: boolean        """        t1 = self.suit, self.rank        t2 = other.suit, other.rank        return t1 < t2class Deck:    """Represents a deck of cards.    Attributes:      cards: list of Card objects.    """    def __init__(self):        """Initializes the Deck with 52 cards.        """        self.cards = []        for suit in range(4):            for rank in range(1, 14):                card = Card(suit, rank)                self.cards.append(card)    def __str__(self):        """Returns a string representation of the deck.        """        res = []        for card in self.cards:            res.append(str(card))        return '\n'.join(res)    def add_card(self, card):        """Adds a card to the deck.        card: Card        """        self.cards.append(card)    def remove_card(self, card):        """Removes a card from the deck or raises exception if it is not there.        card: Card        """        self.cards.remove(card)    def pop_card(self, i=-1):        """Removes and returns a card from the deck.        i: index of the card to pop; by default, pops the last card.        """        return self.cards.pop(i)    def shuffle(self):        """Shuffles the cards in this deck."""        random.shuffle(self.cards)    def sort(self):        """Sorts the cards in ascending order."""        self.cards.sort()    def move_cards(self, hand, num):        """Moves the given number of cards from the deck into the Hand.        hand: destination Hand object        num: integer number of cards to move        """        for i in range(num):            hand.add_card(self.pop_card())class Hand(Deck):    """Represents a hand of playing cards."""    def __init__(self, label=''):        self.cards = []        self.label = labeldef find_defining_class(obj, method_name):    """Finds and returns the class object that will provide    the definition of method_name (as a string) if it is    invoked on obj.    obj: any python object    method_name: string method name    """    for ty in type(obj).mro():        if method_name in ty.__dict__:            return ty    return Noneif __name__ == '__main__':    deck = Deck()    deck.shuffle()    hand = Hand()    print(find_defining_class(hand, '__init__'))    deck.move_cards(hand, 5)    hand.sort()    print(hand)

然后是相应的最后的进行分类等等操作的文件

"""This module contains a code example related toThink Python, 2nd Editionby Allen Downeyhttp://thinkpython2.comCopyright 2015 Allen DowneyLicense: http://creativecommons.org/licenses/by/4.0/"""from __future__ import print_function, divisionfrom Card import Hand, Deckclass Hist(dict):    """A map from each item (x) to its frequency."""    def __init__(self, seq=[]):        "Creates a new histogram starting with the items in seq."        for x in seq:            self.count(x)    def count(self, x, f=1):        "Increments (or decrements) the counter associated with item x."        self[x] = self.get(x, 0) + f        if self[x] == 0:            del self[x]class PokerHand(Hand):    """Represents a poker hand."""    #继承了hand的一个类    all_labels = ['straightflush', 'fourkind', 'fullhouse', 'flush',                  'straight', 'threekind', 'twopair', 'pair', 'highcard']    def make_histograms(self):        """Computes histograms for suits and hands.        # 对手牌进行统计        Creates attributes:          suits: a histogram of the suits in the hand.花色          ranks: a histogram of the ranks.牌序          sets: a sorted list of the rank sets in the hand.排好序的牌        """        self.suits = Hist()        self.ranks = Hist()        # 注意这里开始使用hist        for c in self.cards:            self.suits.count(c.suit)            self.ranks.count(c.rank)        self.sets = list(self.ranks.values())        self.sets.sort(reverse=True)    def has_highcard(self):        """Returns True if this hand has a high card."""        return len(self.cards)    def check_sets(self, *t):        """Checks whether self.sets contains sets that are        at least as big as the requirements in t.        t: list of int        """        for need, have in zip(t, self.sets):            if need > have:                return False        return True    def has_pair(self):        """Checks whether this hand has a pair."""        return self.check_sets(2)    def has_twopair(self):        """Checks whether this hand has two pair."""        return self.check_sets(2, 2)    def has_threekind(self):        """Checks whether this hand has three of a kind."""        return self.check_sets(3)    def has_fourkind(self):        """Checks whether this hand has four of a kind."""        return self.check_sets(4)    def has_fullhouse(self):        """Checks whether this hand has a full house."""        return self.check_sets(3, 2)    def has_flush(self):        """Checks whether this hand has a flush."""        for val in self.suits.values():            if val >= 5:                return True        return False    def has_straight(self):        """Checks whether this hand has a straight."""        # make a copy of the rank histogram before we mess with it        ranks = self.ranks.copy()        ranks[14] = ranks.get(1, 0)        # see if we have 5 in a row        return self.in_a_row(ranks, 5)    def in_a_row(self, ranks, n=5):        """Checks whether the histogram has n ranks in a row.        hist: map from rank to frequency        n: number we need to get to        """        count = 0        for i in range(1, 15):            if ranks.get(i, 0):                count += 1                if count == n:                    return True            else:                count = 0        return False    def has_straightflush(self):        """Checks whether this hand has a straight flush.        Clumsy algorithm.        """        # make a set of the (rank, suit) pairs we have        s = set()        for c in self.cards:            s.add((c.rank, c.suit))            if c.rank == 1:                s.add((14, c.suit))        # iterate through the suits and ranks and see if we        # get to 5 in a row        for suit in range(4):            count = 0            for rank in range(1, 15):                if (rank, suit) in s:                    count += 1                    if count == 5:                        return True                else:                    count = 0        return False    def has_straightflush(self):        """Checks whether this hand has a straight flush.        Better algorithm (in the sense of being more demonstrably        correct).        """        # partition the hand by suit and check each        # sub-hand for a straight        d = {
} for c in self.cards: d.setdefault(c.suit, PokerHand()).add_card(c) # see if any of the partitioned hands has a straight for hand in d.values(): if len(hand.cards) < 5: continue hand.make_histograms() if hand.has_straight(): return True return False def classify(self): """Classifies this hand. Creates attributes: labels: """ self.make_histograms() self.labels = [] for label in PokerHand.all_labels: f = getattr(self, 'has_' + label) if f(): self.labels.append(label)class PokerDeck(Deck): """Represents a deck of cards that can deal poker hands.""" def deal_hands(self, num_cards=5, num_hands=10): """Deals hands from the deck and returns Hands. num_cards: cards per hand num_hands: number of hands returns: list of Hands """ hands = [] for i in range(num_hands): hand = PokerHand() self.move_cards(hand, num_cards) hand.classify() hands.append(hand) return handsdef main(): # the label histogram: map from label to number of occurances lhist = Hist() # loop n times, dealing 7 hands per iteration, 7 cards each n = 10000 for i in range(n): if i % 1000 == 0: print(i) deck = PokerDeck() deck.shuffle() hands = deck.deal_hands(7, 7) for hand in hands: for label in hand.labels: lhist.count(label) # print the results total = 7.0 * n print(total, 'hands dealt:') for label in PokerHand.all_labels: freq = lhist.get(label, 0) if freq == 0: continue p = total / freq print('%s happens one time in %.2f' % (label, p))if __name__ == '__main__': main()

下面献上我一点点啃出来的结果

必须承认只看是不可能会的,首先定义好了一个类叫做Card,给定参数会返回你一个叫Card的类,这个类包含了一下及各个方面
首先,包含了所有的名字,存在rank_names,和suit_names这两个专门存储所有纸牌特征的list,直接把Card这么一个量存在list里面
存下来的实际是地址,但是对于print如果打印的是cards里面的某个元素(就是地址),却又显示正常了考虑了一下原因是那些含有下划线
也就是__**(self)的初始化方法,在一开始就被创建,所以当我调动的时候就会产生,我搜了所有的类型,发现初始化具体做什么是
完全可以由我们自己定义的,只要定义了就可以按照我们想法操作,甚至连进行比较的对象都不一定要在初始化函数里面,虽然我也不知道如何实现比较的
可能自动发现是同一类的,然后检测到我的初始化里面含有这种在同类不同元素之间的比较,然后就按照里面的进行了操作。
以上就是Card类的全部
Deck类,Deck当然首先因为是桌上的一套牌,所以在初始化的时候给了自己一个属性就是cards,含有了所有的Card类别,当然有个小细节就是rank
是从1开始的,方便了我们自己后面序号对应牌序,但是注意,虽然你打印某个card元素时结果是可视化的那个字符串,但是实际上它的rank,suit等属性
依旧是他们自己,依然是int。里面的方法add_card当然就是增加卡牌,不过要注意,cards是一个list,存储了所有的card元素,存储方式是存地址
不过调用依旧显元素的特征,不受影响。这里面的字符串初始化是把吗,每个元素的字符串用换行符连在一起,这样就可以生成一个字符串了。
remove_card也是直接在list里面用list的方法移除,shuffle是洗牌,会把牌重新洗一遍,需要用到random库。
move_cards是把Deck里面含有的n张牌转移到hand对象里,使用n次pop把末尾的n张转移出去
hand类,是Deck的子类,除非改动,否则一切按照Deck来生成,所以理所当然的就首先把cards清空,然后添加了一个默认空的label标签,label倒是一个
新属性,
最后还有一个新函数,find__defining_class,这个方法是对现有的某个东西,在程序中搜索这个方式是哪个具体方法名下的方法,比如说hand里面的__init
在这个函数的搜索下就返回了是来自’文件名.类别名’。关于这个话题有一篇博客讲的比较透彻,https://www.cnblogs.com/gandoufu/p/9634914.html
利用mro对含有这个方法的序列文件,当然因为可能存在很复杂的继承关系,因此可能是多个子列的,而一旦我们的子列中出现了我们所搜索的方法名,就返回那个
子列,这样我们就可以轻松的读取方法的来龙去脉。
好了继续回到我们的主程序
现在经过反复试验终于搞懂了这个Hist是怎么计数的,首先函数开头就提示我们这将会是一个字典,初始化是对一个list进行计数,就用pokerhand里面的进行
解释,首先给他suits和rank两个用Hist的属性,然后因为我们这个pokerhand这个类里面是含有cards的,Hist里面本来有或没有那个元素作为key不管,取得他的值,
然后加上一,就相当于检测到一次,原来检测到的次数加一,就是说我给你一系列suit,你去记下每一个suit,并且记一次加一,所以说这是对单个card进行
计数的,无法对cards直接算因为cards是list。这样下载这些Hist类里面就逐渐增加了我们需要的suit等标签的统计。紧接着又把rank的统计值作为一个list
单独保存,并且按照降序排列。
下面一个has_haghcard直接返回cards含有多少card
接下来check_sets检查我们所含有的相同rank最大数量是不是满足大于等于我们需要的数量,用来判断对子等等情况,注意这里使用了
t,从后文看
估计是可以不限制我们的变量数。这里的判断逻辑是如果我们要判断是否同时有两个对子,一个飞机一个对子等,输入的t也是降序,这样就保证只有满足情况猜
才能返回真,否则就是假的
后面的has什么什么都是一样的意思,想通了这里就没有问题了
在has_flash这里有一点不同,同花的意思是五个suit相同的card,这样就只需要检测suit的值是否存在大于等于5的,有就为真
has_straight这个算是困扰我一会了,一直没有想出来好的方法解决他,这里首先复制了一个rank。且慢,我突然发现这副牌没有大小飞机。然后再最后
补上了一个A的值,这是因为jqkA这样子的连牌是可以的,然后具体是否在一个连续的序列
in_a_row和是通过假设手里的牌啥都有,那么就在上面给出了一个ranks的末尾加一字典,这个字典数有没有连续的5个字符,这里我之所不敢用这种方式
是以为如果某个key不存在的时候我去求它的值会出现错误,当然如果直接采用a[i]i超过了范围就报错,不过可以使用a.get(i,0)来得到i这个key的值,即便没有
也只是返回0,所以后面的连续监测的代码就显而易见了,检测到一个就加一,如果等于我们需要的长度就可以返回真,否则完成循环之后返回假
下面一个就是加入一个条件的straight了,同花顺,还要花色相同。首先建立一个set()类,这个类可以忽略重复的元素,我们把每个元素都存到这个类中
同时也要注意边界条件,a可以和k连起来,所以一旦检测到存在a,那么就把k之后的14位填上同花色的卡牌,可以把a看成两张suit相同的卡,一旦出现就头
尾都要有。后面开始检测,因为反正元素组合也不大,就可以遍历一遍所有的组合,最外围的循环是花色,在同一个花色下进行straight的检测循环。
emmm原来这只是一个比较笨的算法
下面来说更好的一个
这一个的结构就比较复杂,首先定义一个字典,循环所有的card,然后把suit取出来作为key,对应新创建的pokerhand的类作为这个值,然后这个值
里面就可以把对应的card存下来,这样就保证了所有的每一对item,里面的值都是拥有相同的suit,那么对每一个value使用之前写好的has_straight
就可以了。
下一个类是classify,是用来对自身进行检测然后给自己加上标签的,所以一开始先给label打空,后面对每一个label都检测一次,当然不可能手打这么多重复
的字符串,所以就用getattr(x,name),x是对象,name是字符串,也就是说返回一个x.name然后字符串采用has_+'label’就完美的完成了循环,如果检测
成功,就在label里面加上这个label
下面就到了pokerDeck,这个是专门用来处理牌的,从牌堆里发牌然后还牌,所以继承自deck,第一个内置函数,处理来自deck的一桌子牌
第一个函数就是deal_hands,根据hands数量,然后对于每一个hand,从自己里面取出相应number的卡移动到hand里面,最后返回发完了所有牌的hands
的list
终于讲完了,算是搞懂了

你可能感兴趣的文章
设计模式之享元模式
查看>>
单例模式最佳实践
查看>>
.NET Core + Spring Cloud:服务注册与发现
查看>>
今天你内卷了吗?
查看>>
设计模式之代理模式
查看>>
结构型设计模式总结
查看>>
dotNET:怎样处理程序中的异常(实战篇)?
查看>>
What is 测试金字塔?
查看>>
.Net Core HttpClient处理响应压缩
查看>>
十分钟搭建自己的私有NuGet服务器-BaGet
查看>>
efcore 新特性 SaveChanges Events
查看>>
龙芯3A5000初样顺利交付流片
查看>>
用了Dapper之后通篇还是SqlConnection,真的看不下去了
查看>>
ABP快速开发一个.NET Core电商平台
查看>>
[NewLife.Net]单机400万长连接压力测试
查看>>
使用Azure人脸API对图片进行人脸识别
查看>>
快醒醒,C# 9 中又来了一堆关键词 init,record,with
查看>>
【招聘(深圳)】轻岁 诚聘.NET Core开发
查看>>
欢迎来到 C# 9.0(Welcome to C# 9.0)
查看>>
Dapr微服务应用开发系列1:环境配置
查看>>