一副纸牌上的随机迭代

时间:2018-11-24 10:02:25

标签: python python-3.x

我正在尝试无重复地遍历一副纸牌。

以下是代码:

import random

class Cards:

    # Where prefix d is Diamonds, h is Hearts, s is Spades and c is Clubs
    total_cards = [{2: 'd2', 3: 'd3', 4: 'd4', 5: 'd5', 6: 'd6', 7: 'd7', 8: 'd8', 9: 'd9', 10: 'd10', 11: 'dJack',
              12: 'dQueen', 13: 'dKing', 14: 'dAce'},
             {2: 'h2', 3: 'h3', 4: 'h4', 5: 'h5', 6: 'h6', 7: 'h7', 8: 'h8', 9: 'h9', 10: 'h10', 11: 'hJack',
              12: 'hQueen', 13: 'hKing', 14: 'hAce'},
             {2: 's2', 3: 's3', 4: 's4', 5: 's5', 6: 's6', 7: 's7', 8: 's8', 9: 's9', 10: 's10', 11: 'sJack',
              12: 'sQueen', 13: 'sKing', 14: 'sAce'},
             {2: 'c2', 3: 'c3', 4: 'c4', 5: 'c5', 6: 'c6', 7: 'c7', 8: 'c8', 9: 'c9', 10: 'c10', 11: 'cJack',
              12: 'cQueen', 13: 'cKing', 14: 'cAce'}]

    def random_pick(self): # Method to randomly pick a card from the deck

        choice = random.choice(random.choice(self.total_cards))

        for v in self.total_cards:    # to retrieve the corresponding `key` for `choice` 
            for i in v.values():
                if choice == i:
                    k = v[i]
                    v.pop(k)

        print(choice)    # To print the random card picked from the deck
        print(self.total_cards)    # To print the updated Deck after picking the card


c = Cards()
c.random_pick()

我要尝试的想法是,一旦拿起卡,就应将其从卡座中取出。

这是错误:

Traceback (most recent call last):
  File "F:/Blackjack/Base/Cards.py", line 30, in <module>
    c.random_pick()
  File "F:/Blackjack/Base/Cards.py", line 17, in random_pick
    choice = random.choice(random.choice(self.total_cards))
  File "C:\Users\Python\Python37-32\lib\random.py", line 262, in choice
    return seq[i]
KeyError: 0

据我了解,KeyError是在现有键集中找不到映射(字典)键时引发的异常。但是我的 IF LOOP 仅在条件choice == i下才是 TRUE ,只有在这种情况下,才应该启动pop()。

我尝试了上面的代码,但没有在代码中使用pop()方法,并且代码运行正常,每次运行后都会生成随机卡片。

4 个答案:

答案 0 :(得分:3)

如果您多次尝试执行代码,则会发现您不会每次都收到此错误。有时它会越过终点线

        choice = random.choice(random.choice(self.total_cards))

,然后在代码中再次遇到另一个错误。

那是怎么回事?我假设random.choice(self.total_cards)可以正常工作,并返回total_cards列表中的四个卡片组之一。您将该卡组表示为字典。

在一个更简单的示例上,让我们看看random.choice对词典的作用:

>>> import random
>>>
>>> random.seed(0)  # for reproducability
>>> random.choice({1:2, 3:4})
2

嗯,很奇怪,它返回了其中一个值。我曾期望其中一个键,例如在不调用.items().values()的情况下遍历字典时。

>>> [i for i in {1:2, 3:4}]
[1, 3]

让我们再试一次:

>>> random.seed(42)  # for reproducability
>>> random.choice({1:2, 3:4})
KeyError: 0

奇怪,不是吗? 0既不在值中也不在键中。它是哪里来的?

让我们看看如何实现random.choice。在IPython中,我可以这样获得其源代码:

In [1]: import random

In [2]: random.choice??

要获取系统上的代码,您还可以查看错误消息中提到的文件:第C:\Users\Python\Python37-32\lib\random.py行第262行。

在Python 3.6.6(我系统上的版本)上,源代码为:

    def choice(self, seq):
        """Choose a random element from a non-empty sequence."""
        try:
            i = self._randbelow(len(seq))
        except ValueError:
            raise IndexError('Cannot choose from an empty sequence') from None
        return seq[i]

私有方法random._randbelow包含说明

  

返回范围为[0,n)的随机整数。如果n == 0,则引发ValueError。

虽然这对于序列(例如列表,集合或元组)很好用,但我想您会明白为什么当seq恰好是字典(或任何其他映射)时,它根本无法做正确的事情):

需要

  

序列的长度(len(seq)

(也适用于词典),然后

  

生成一个介于0(含)和该长度(不含)之间的随机整数(这就是self._randbelow的作用)

所以这将是

  

序列中随机元素的0索引位置

然后

  

使用该随机整数索引序列(seq[i])并返回该值(return

对字典不起作用,因为它们是

  

由其键索引。

这也是为什么我们有时没有收到错误,而是random.choice返回其中一个字典值的原因:当整数用作a

  

随机位置

也恰好是字典的键之一,它只会返回相应的值。如果碰巧不是我们的任何键(如果所有键都是非整数(例如字符串),那么b.t.w.总是这样),则会出现KeyError

答案 1 :(得分:1)

快速解答:random.choice()用于序列即列表,如文档中所述。

长答案:请参见das-g's answer

答案 2 :(得分:0)

我认为列表会更好,这是我的处理方式:

from random import shuffle

class Cards:

def __init__(self): #example deck with just some cards
    self.total_cards = ['c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'c10']
    shuffle(self.total_cards)  #shuffle the deck of cards

def random_pick(self): #Method to randomly pick a card from the deck

    print(self.total_cards[len(self.total_cards)-1])    #To print the last card from your deck, which will be removed by pop() command
    self.total_cards.pop()
    print(self.total_cards)    #To print the updated Deck after pop() the last card


c = Cards()
for _ in range(3): # picking 3 random cards for demostration
    c.random_pick()

答案 3 :(得分:0)

尝试我的解决方案:

import random
import numpy as np

class Cards:

    # Where prefix d is Diamonds, h is Hearts, s is Spades and c is Clubs
    total_cards = [{2: 'd2', 3: 'd3', 4: 'd4', 5: 'd5', 6: 'd6', 7: 'd7', 8: 'd8', 9: 'd9', 10: 'd10', 11: 'dJack',
          12: 'dQueen', 13: 'dKing', 14: 'dAce'},
         {2: 'h2', 3: 'h3', 4: 'h4', 5: 'h5', 6: 'h6', 7: 'h7', 8: 'h8', 9: 'h9', 10: 'h10', 11: 'hJack',
          12: 'hQueen', 13: 'hKing', 14: 'hAce'},
         {2: 's2', 3: 's3', 4: 's4', 5: 's5', 6: 's6', 7: 's7', 8: 's8', 9: 's9', 10: 's10', 11: 'sJack',
          12: 'sQueen', 13: 'sKing', 14: 'sAce'},
         {2: 'c2', 3: 'c3', 4: 'c4', 5: 'c5', 6: 'c6', 7: 'c7', 8: 'c8', 9: 'c9', 10: 'c10', 11: 'cJack',
          12: 'cQueen', 13: 'cKing', 14: 'cAce'}]
    _showed = 0

    def __init__(self):
        self._shuffle_cards()
        self.pointers = [0 for _ in range(len(self.total_cards))]

    def _shuffle_cards(self):
        for i, v in enumerate(self.total_cards):
            temp = list(v.items())
            self._showed += 1
            np.random.shuffle(temp)
            self.total_cards[i] = temp

    def random_pick(self):
        choice = random.choice(range(len(self.total_cards)))
        while self.pointers[choice] >= len(self.total_cards[choice]) and self._showed > 0: 
            choice = random.choice(self.total_cards)
            self.pointers[choice] += 1
        if self._showed == 0:
            print('Nothing cards to show')
        else:
            self._showed -= 1
            print(self.total_cards[choice][self.pointers[choice]][1])


c = Cards()
c.random_pick()