I'm learning Python programming and i'm trying to make a working popular card game.
I'm starting from the skeleton, so I wrote some code to create the deck and to deal cards and shuffle the deck. Now I want to create 2 players that "have" a hand, in which they can keep a maximum of 3 cards, and can "draw" cards from the deck. I thought about a player class, in which are defined the name and hand attributes for each different player, but when i tried to draw cards with player1 it also added the cards to player2's hand. How can i change it so it adds the cards to a a player and only to him, removing them from the deck? What is wrong with my solution?
Output:
['10 di Denari', '1 di Coppe']
['10 di Denari', '1 di Coppe', '6 di Denari', '5 di Denari']
Can you help me understanding how to get it to work?
EDIT: Yeah i pasted the wrong code, here is the one i need help in:
import random
semi = ['Bastoni','Spade','Coppe','Denari']
numeri = [1,2,3,4,5,6,7,8,9,10]
mazzo = []
for element in numeri:
for seme in semi:
carta = str(element) + ' di ' + seme
mazzo.append(carta)
Rimanenti = len(mazzo)
def mischia():
random.shuffle(mazzo)
class Giocatore:
nome = None
mano = []
tola = []
def __init__(self,nome):
self.nome=nome
def draw(q):
for n in range(0, q):
pesco = random.choice(mazzo)
Giocatore.mano.append(pesco)
mazzo.remove(pesco)
def turno():
Giocatore.draw('Toni',1)
Giocatore.draw('Piero',1)
def inizio():
Giocatore.draw('Toni', 3)
Giocatore.draw('Piero', 3)
class Piero(Giocatore):
nome = 'Piero'
class Toni(Giocatore):
nome = 'Toni'
Toni.draw(2)
print(Toni.mano)
Piero.draw(2)
print(Piero.mano)
ANOTHER EDIT:
Thank you all for your answers! Now I have a better understanding of the whole thing, I'm rewriting it differently!
I think the main problem is that you are misunderstanding the difference between class variables and instance variables. I'll use a simple example:
class Player():
hand = [] # hand is a class variable, as it is not tied to an instance
p1 = Player() # p1 is an instance of Player
p2 = Player() # p2 is a separate instance of Player()
Now, if I add something to the hand of p1
:
p1.hand.append(1)
p2.hand
# [1]
This is because I have defined hand
at the class level, and so both p1.hand
and p2.hand
are really Player.hand
. To change this, you will want hand
to be attached to an instance, using self.hand
and the __init__
dunder method, which acts like a constructor for class instances.
class Player():
def __init__(self): # self is always passed as the first argument
self.hand = []
p1 = Player()
p2 = Player()
Now, p1.hand
is a completely different object than p2.hand
because they were created through each call to __init__
. Now if I add something to p1.hand
:
p1.hand.append(1)
p1.hand
# [1]
p2.hand
# []
They aren't both modified. Now, to touch on class functions. By default, functions in classes are instance level, which means that self
, or the class instance, will be implicitly passed as the first argument. If you don't have a placeholder for self
, you will get errors:
class A():
def a():
print("did something")
inst = A()
a.a()
# TypeError: a() takes 0 positional arguments but 1 was given
# To fix this
class A():
def a(self):
print("did something")
inst = A()
a.a()
# did something
Fortunately, you've identified what you need for this program to function properly, two players, a deck of cards, and a mechanism to take turns. Because you are using random.choice
to pick cards, I'd argue that you don't actually need a function to shuffle the deck. You can get the card by choosing a random card as you've done before:
semi = ['Bastoni','Spade','Coppe','Denari']
numeri = [1,2,3,4,5,6,7,8,9,10]
mazzo = ['%d di %s' % (element, seme) for seme in semi for element in numeri]
To draw a card, you can use the following:
# Use random.choice as you've done before
idx = random.coice(mazzo)
mazzo.remove(drawn_card)
The class method remove
will remove a value from the list. Paired with your class.hand
approach:
Toni = Player()
Toni.hand.append(drawn_card)
Or, as a method in the Player
class:
class Player():
def __init__(self):
self.hand = []
def draw(self):
# Need to convert set to list to choose
drawn_card = random.choice(mazzo)
mazzo.remove(drawn_card)
self.hand.append(drawn_card)
print(self.hand) # If you want to see the hand
toni = Player()
toni.draw()
# ['8 di Spade']
Though you could view that as a bit verbose. If you wanted to keep your shuffle method, then you could shuffle the deck every time and use pop
to grab a random card as @ibonyun suggested