可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
suites = ['H', 'C', 'D', 'S']
deck = [[r + s] for s in suites for r in ranks]
return deck
def cards_dealt (num_cards, num_players, deck):
rand.shuffle(deck)
print(cards_dealt(5, 3, deck))
I understand that the function is incomplete. I need num_cards to be the number of cards that each player receives, num_players to be the number of players, and deck to be the list of card strings from the function create().
For example, the print statement would reveal the 5 cards each of the three players gets from the list deck that has been shuffled. My problem is that whenever I write something, it says that deck is not defined.
回答1:
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)
回答2:
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.
回答3:
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