How to randomly shuffle a deck of cards among players?

前端 未结 3 1434
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-28 02:33

I am having trouble using one function in another to deal cards. Here is what I have so far.

import random as rand 

def create(): 
     ranks = [\'2\', \'3\',          


        
相关标签:
3条回答
  • 2021-01-28 03:01

    Forget about your two functions, since they're both correct, and look at your top-level code:

    import random as rand
    def ...
    def ...
    print(cards_dealt(5, 3, deck)) 
    

    Where does deck come from? Nowhere. Hence the exception.

    It's pretty obvious where you intended it to come from—you have a create function that ends with a return deck. You just aren't calling it anywhere.

    So you want:

    import random as rand
    def ...
    def ...
    deck = create()
    print(cards_dealt(5, 3, deck)) 
    

    … or, if you want to make it clearer that the global variable is unrelated to the two locals:

    import random as rand
    def ...
    def ...
    mydeck = create()
    print(cards_dealt(5, 3, mydeck)) 
    

    … or, if you want to make things more concise:

    import random as rand
    def ...
    def ...
    print(cards_dealt(5, 3, create())) 
    

    Beyond this problem, cards_dealt doesn't have a return, so it just returns None. When your function is complete, there might be something worth printing out, but for now, while you're debugging what you have so far, it's not very useful.

    Meanwhile, if you want to print the shuffled deck, which could be useful, you'd do something like this:

    import random as rand
    def ...
    def ...
    mydeck = create()
    cards_dealt(5, 3, mydeck)
    print(mydeck)
    

    When you later finish the function so it returns, say, a tuple of 3 lists of 5 cards, you'll probably want to store those return values for later as well as printing them, so it might go something like this:

    import random as rand
    def ...
    def ...
    mydeck = create()
    hands = cards_dealt(5, 3, mydeck)
    for hand in hands:
        print(hand)
    
    0 讨论(0)
  • 2021-01-28 03:07

    Let me suggest an object-oriented approach where we will define the classes Card, Deck and Player.

    Using objects instead of lists of cards will provide a neat API to implement games. As you implement game logic, it will also make it easier to keep a single source of truth as to where each card is and which player has each card.

    Deck API

    import random
    
    
    class Card:
        def __init__(self, kind, rank, deck):
            self._kind = kind
            self._rank = rank
            self.deck = deck
            self.where = None
    
        def __repr__(self):
            return 'Card(kind={}, rank={}'.format(self.kind, self.rank)
    
        @property
        def kind(self):
            return self._kind
    
        @property
        def rank(self):
            return self._rank
    
    
    class Deck:
        def __init__(self):
            ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
            kinds = ['H', 'C', 'D', 'S']
            self.cards = [Card(kind, rank, self) for kind in kinds for rank in ranks]
    
        def deal(self, players, n=None):
            if any(p.deck is not self for p in players):
                raise RuntimeError('Player {} is not playing the deck'.format(p.id))
    
            n = n if n is not None else len(self.cards)
            random.shuffle(self.cards)
    
            for i, card in enumerate(self.cards[:n * len(players)]):
                card.where = players[i % len(players)]
    
    
    class Player:
        def __init__(self, id, deck):
            self.id = id
            self.deck = deck
    
        @property
        def hand(self):
            return [card for card in deck.cards if card.where is self]
    

    Dealing cards

    deck = Deck()
    players = [Player(id, deck) for id in range(3)]
    
    deck.deal(players, n=4)
    
    for p in players:
        print(p.hand)
    

    Output

    [Card(kind=D, rank=A), Card(kind=D, rank=2), Card(kind=S, rank=5), Card(kind=S, rank=K)]
    [Card(kind=S, rank=9), Card(kind=D, rank=5), Card(kind=C, rank=A), Card(kind=C, rank=Q)]
    [Card(kind=C, rank=9), Card(kind=S, rank=J), Card(kind=D, rank=3), Card(kind=H, rank=9)]
    

    Playing a card

    The card.where attribute can be updated to indicate the position of a card. Since it is the single source of truth for card position, this updates the player.hand property.

    deck = Deck()
    players = [Player(id, deck) for id in range(2)]
    
    deck.deal(players, n=1)
    
    players[0].hand[0].where = players[1]
    
    for p in players:
        print(p.hand)
    

    Output

    []
    [Card(kind=H, rank=K), Card(kind=D, rank=2)]
    

    More features

    The above API provides the basics to deal cards and move cards from hand to hand, but can be extended to implement new features.

    0 讨论(0)
  • 2021-01-28 03:10

    There are certainly other ways to do it, but you could complete your function as so, in order to return a dictionary of your players and their hands:

    def cards_dealt(num_cards, num_players, deck):
        rand.shuffle(deck)
        return {player:[deck.pop() for _ in range(num_cards)] for player in range(num_players)}
    

    Then, create your deck (that is where your "deck is not defined" problem comes in) and call your function:

    my_deck = create()
    
    print(cards_dealt(5, 3, my_deck))
    

    Which returns:

    {0: [['10S'], ['8S'], ['7D'], ['6S'], ['4C']], 
     1: [['JD'], ['AC'], ['QD'], ['2D'], ['JS']], 
     2: [['6D'], ['4H'], ['AS'], ['4S'], ['9S']]}
    

    The equivalent cards_dealt function, but with loops instead of the dict and list comprehensions is:

    def cards_dealt (num_cards, num_players, deck): 
         rand.shuffle(deck)
         player_hands = {i:[] for i in range(num_players)}
         for player in range(num_players):
             for num in range(num_cards):
                 player_hands[player].append(deck.pop())
         return player_hands
    
    0 讨论(0)
提交回复
热议问题