使用 类 和函数在 python 上创建纸牌游戏 - 编辑
Creating a card game on python by using Classes and Functions - EDIT
我正在学习 Python 编程,并且正在尝试制作一款流行的纸牌游戏。
我从骨架开始,所以我写了一些代码来创建牌组、发牌和洗牌。
现在我想创建 2 个 "have" 手牌的玩家,他们最多可以保留 3 张牌,并且可以 "draw" 牌。
我想到了一个玩家 class,其中定义了每个不同玩家的名称和手牌属性,但是当我尝试用玩家 1 抽牌时,它也会将牌添加到玩家 2 的手上。我怎样才能改变它以便将卡片添加到玩家并且只添加到他,然后将它们从牌组中移除?我的解决方案有什么问题?
输出:
['10 di Denari', '1 di Coppe']
['10 di Denari', '1 di Coppe', '6 di Denari', '5 di Denari']
你能帮我理解如何让它工作吗?
编辑:是的,我粘贴了错误的代码,这是我需要帮助的代码:
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)
另一个编辑:
谢谢大家的回答!现在我对整个事情有了更好的理解,我正在以不同的方式重写它!
您使用的 class 不正确。制作玩家 class 就像定义玩家身份,这是成为纸牌游戏玩家的想法。您不能仅凭玩家的 想法 来玩纸牌游戏;您需要能够体现玩家身份的真实玩家。在编程术语中,玩家将 实例化 玩家 class。
您正在尝试使用 class 本身玩游戏,而不是 class 的实例。您需要实例化 Giocatore
两次(每个玩家一次)并使用实例进行游戏。要实例化你需要做这样的事情:
player1 = Giocatore('Pietro')
player2 = Giocatore('Toni')
在底部,您已经使用以玩家命名的新 class 子classed Giocatore
。除非每个玩家都有不同的能力(即属性 and/or 方法),否则这是不必要的。它与实例化 Giocatore
.
不是一回事
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?
有两个原因。首先,正如我上面所描述的,您正在玩 class 本身。但即使你没有这样做,还有一个额外的问题,那就是你已经将手 mano
设为 class 属性而不是 实例 属性。这意味着所有实例都将共享该属性;因此所有玩家将分享完全相同的手牌。在 draw
方法中,应该是 self.mano.append(pesco)
而不是 Giocatore.mano.append(pesco)
。这样您就可以将新卡仅放在该玩家的手上,而不是所有玩家共同分享的手上。
要使手成为实例属性,您应该在 __init__
中定义它。该方法应如下所示:
def __init__(self, nome):
self.nome = nome
self.mano = []
此处self
指实例
至于从牌组中移除卡片,如果您在开始时已经使用 random.shuffle
将它们随机化,则无需在抽取新卡片时使用 random.choice
。我建议只从列表中弹出一个,如下所示:
def draw(self, n):
for _ in range(n):
self.mano.append(mazzo.pop())
我认为主要问题是您误解了 class 变量和实例变量之间的区别。我将使用一个简单的例子:
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()
现在,如果我在 p1
的手上加点东西:
p1.hand.append(1)
p2.hand
# [1]
这是因为我在class级别定义了hand
,所以p1.hand
和p2.hand
都是真的Player.hand
。要更改此设置,您需要使用 self.hand
和 __init__
dunder 方法将 hand
附加到一个实例,该方法的作用类似于 class 个实例的构造函数。
class Player():
def __init__(self): # self is always passed as the first argument
self.hand = []
p1 = Player()
p2 = Player()
现在,p1.hand
是一个与 p2.hand
完全不同的对象,因为它们是通过每次调用 __init__
创建的。现在,如果我向 p1.hand
添加内容:
p1.hand.append(1)
p1.hand
# [1]
p2.hand
# []
它们都没有被修改。现在,谈谈 class 功能。默认情况下,classes 中的函数是实例级别的,这意味着 self
或 class 实例 将作为第一个隐式传递争论。如果你没有 self
的占位符,你会得到错误:
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
计划
幸运的是,您已经确定了此程序正常运行所需的条件、两名玩家、一副牌和轮流机制。因为您正在使用 random.choice
来挑选卡片,所以我认为您实际上不需要一个函数来洗牌。您可以像之前一样通过随机选择一张卡片来获得卡片:
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]
要抽一张牌,您可以使用以下方法:
# Use random.choice as you've done before
idx = random.coice(mazzo)
mazzo.remove(drawn_card)
class 方法 remove
将从列表中删除一个值。搭配您的 class.hand
方法:
Toni = Player()
Toni.hand.append(drawn_card)
或者,作为 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']
尽管您可能认为这有点冗长。如果你想保留你的洗牌方法,那么你可以每次洗牌并使用 pop
随机抓取一张牌,正如@ibonyun 建议的那样
我正在学习 Python 编程,并且正在尝试制作一款流行的纸牌游戏。
我从骨架开始,所以我写了一些代码来创建牌组、发牌和洗牌。 现在我想创建 2 个 "have" 手牌的玩家,他们最多可以保留 3 张牌,并且可以 "draw" 牌。 我想到了一个玩家 class,其中定义了每个不同玩家的名称和手牌属性,但是当我尝试用玩家 1 抽牌时,它也会将牌添加到玩家 2 的手上。我怎样才能改变它以便将卡片添加到玩家并且只添加到他,然后将它们从牌组中移除?我的解决方案有什么问题?
输出:
['10 di Denari', '1 di Coppe']
['10 di Denari', '1 di Coppe', '6 di Denari', '5 di Denari']
你能帮我理解如何让它工作吗?
编辑:是的,我粘贴了错误的代码,这是我需要帮助的代码:
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)
另一个编辑:
谢谢大家的回答!现在我对整个事情有了更好的理解,我正在以不同的方式重写它!
您使用的 class 不正确。制作玩家 class 就像定义玩家身份,这是成为纸牌游戏玩家的想法。您不能仅凭玩家的 想法 来玩纸牌游戏;您需要能够体现玩家身份的真实玩家。在编程术语中,玩家将 实例化 玩家 class。
您正在尝试使用 class 本身玩游戏,而不是 class 的实例。您需要实例化 Giocatore
两次(每个玩家一次)并使用实例进行游戏。要实例化你需要做这样的事情:
player1 = Giocatore('Pietro')
player2 = Giocatore('Toni')
在底部,您已经使用以玩家命名的新 class 子classed Giocatore
。除非每个玩家都有不同的能力(即属性 and/or 方法),否则这是不必要的。它与实例化 Giocatore
.
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?
有两个原因。首先,正如我上面所描述的,您正在玩 class 本身。但即使你没有这样做,还有一个额外的问题,那就是你已经将手 mano
设为 class 属性而不是 实例 属性。这意味着所有实例都将共享该属性;因此所有玩家将分享完全相同的手牌。在 draw
方法中,应该是 self.mano.append(pesco)
而不是 Giocatore.mano.append(pesco)
。这样您就可以将新卡仅放在该玩家的手上,而不是所有玩家共同分享的手上。
要使手成为实例属性,您应该在 __init__
中定义它。该方法应如下所示:
def __init__(self, nome):
self.nome = nome
self.mano = []
此处self
指实例
至于从牌组中移除卡片,如果您在开始时已经使用 random.shuffle
将它们随机化,则无需在抽取新卡片时使用 random.choice
。我建议只从列表中弹出一个,如下所示:
def draw(self, n):
for _ in range(n):
self.mano.append(mazzo.pop())
我认为主要问题是您误解了 class 变量和实例变量之间的区别。我将使用一个简单的例子:
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()
现在,如果我在 p1
的手上加点东西:
p1.hand.append(1)
p2.hand
# [1]
这是因为我在class级别定义了hand
,所以p1.hand
和p2.hand
都是真的Player.hand
。要更改此设置,您需要使用 self.hand
和 __init__
dunder 方法将 hand
附加到一个实例,该方法的作用类似于 class 个实例的构造函数。
class Player():
def __init__(self): # self is always passed as the first argument
self.hand = []
p1 = Player()
p2 = Player()
现在,p1.hand
是一个与 p2.hand
完全不同的对象,因为它们是通过每次调用 __init__
创建的。现在,如果我向 p1.hand
添加内容:
p1.hand.append(1)
p1.hand
# [1]
p2.hand
# []
它们都没有被修改。现在,谈谈 class 功能。默认情况下,classes 中的函数是实例级别的,这意味着 self
或 class 实例 将作为第一个隐式传递争论。如果你没有 self
的占位符,你会得到错误:
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
计划
幸运的是,您已经确定了此程序正常运行所需的条件、两名玩家、一副牌和轮流机制。因为您正在使用 random.choice
来挑选卡片,所以我认为您实际上不需要一个函数来洗牌。您可以像之前一样通过随机选择一张卡片来获得卡片:
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]
要抽一张牌,您可以使用以下方法:
# Use random.choice as you've done before
idx = random.coice(mazzo)
mazzo.remove(drawn_card)
class 方法 remove
将从列表中删除一个值。搭配您的 class.hand
方法:
Toni = Player()
Toni.hand.append(drawn_card)
或者,作为 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']
尽管您可能认为这有点冗长。如果你想保留你的洗牌方法,那么你可以每次洗牌并使用 pop
随机抓取一张牌,正如@ibonyun 建议的那样