Python 简单纸牌游戏学习类
我正在尝试创建一个简单的纸牌游戏,以更好地理解面向对象编程(OOP)和类的概念。
这个游戏的规则是这样的:从一副牌中发两张牌。然后再发一张第三张牌。如果第三张牌的点数在前两张牌之间,那么玩家就赢了。如果第三张牌和前两张牌中的任意一张相等,或者点数在这两张牌之外,那么玩家就输了。
这是我目前的进展:
class Deck(object):
def __init__(self):
self.deck = []
def PopulateDeck(self):
suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
for suit in suits:
for rank in range(2, 15):
if rank == 11:
value = "Jack"
elif rank == 12:
value = "Queen"
elif rank == 13:
value = "King"
elif rank == 14:
value = "Ace"
self.deck.append(str(value) + " of " + suit)
class Card(object):
def __init__(self, rank, value):
self.rank = rank
self.value = value
self.card = self.rank + self.value
我在处理类和面向对象编程时遇到了困难,不确定这是否是一个好的开始,或者我接下来应该怎么做。很多内容都是通过阅读其他资料和示例创建的。有没有人能给我一些建议,告诉我还可以创建哪些其他类来运行我的游戏,以及这些类之间是如何互动或继承的?谢谢。
3 个回答
我也在学习面向对象编程(OOP),我发现用纸牌游戏来理解这些概念是最简单的方式。之前我遇到过这段代码,但不太确定它的来源。这里我把这段代码贴出来,并加了一些有用的注释,希望能对你们有所帮助。
from random import shuffle
class Card:
suits = ['spades', 'hearts', 'diamonds', 'clubs']
values = [None, None, '2','3','4','5','6','7','8','9','10','Jack', 'Queen', 'King', 'Ace']
def __init__(self, v, s):
'''suits + values are ints'''
self.value = v
self.suit = s
def __lt__(self, c2): # allows to compare two objects cards in this case
if self.value < c2.value:
return True
if self.value == c2.value: # value is what user is putting while creating object of class
if self.suit < c2.suit: # c2 is with what we are comapring
return True
else:
return False
return False
def __gt__(self, c2): # allows to compare two objects cards in this case,
if self.value > c2.value: # c2 is with what we are comapring
return True
if self.value == c2.value:
if self.suit > c2.suit: # suits comes into picture if values are same suit number is given importance
return True
else:
return False
return False
def __repr__(self):
v = self.values[self.value] + ' of ' + self.suits[self.suit]
return v
# defining the class which represent the deck of card
class Deck:
def __init__(self):
self.cards = []
for i in range(2,15):
for j in range(4):
self.cards.append(Card(i,j))
shuffle(self.cards)
def rm_card(self):
if len(self.cards) == 0:
return # if block it return to None object when condition is satisfied
return self.cards.pop()
class Player:
def __init__(self, name):
self.name = name # name of the player
self.card = None # current card player holding
self.wins = 0
class Game:
def __init__(self):
name1 = input('p1 name ')
name2 = input('p2 name ')
self.deck = Deck()
self.p1 = Player(name1)
self.p2 = Player(name2)
def wins(self, winner):
w = "{} wins this round"
w = w.format(winner)
print(w)
def draw(self, p1n, p1c, p2n, p2c):
d = "{} drew {} {} drew {}"
d = d.format(p1n, p1c, p2n, p2c)
print(d)
def play_game(self):
cards = self.deck.cards # self.deck = Deck() and cards = self.deck.cards is list of card
print('Beginning War!!!')
while len(cards) > 2:
m = 'q to quit. Any' + ' key to play'
response = input(m)
if response == 'q':
break
p1c = self.deck.rm_card() # removing first card from deck by player 1
p2c = self.deck.rm_card() # removing second card from deck by player 2
p1n = self.p1.name
p2n = self.p2.name
self.draw(p1n, p1c, p2n, p2c)
if p1c > p2c:
self.p1.wins +=1
self.wins(self.p1.name)
else:
self.p2.wins += 1
self.wins(self.p2.name)
win = self.winner(self.p1, self.p2)
print("War is over. {} wins".format(win))
def winner(self, p1, p2):
if p1.wins > p2.wins:
return p1.name
if p1.wins < p2.wins:
return p2.name
return 'Its Tie!'
game = Game()
game.play_game()
来源:https://thecleverprogrammer.com/2020/10/04/card-game-with-python/
正如 @tobias_k 在评论中提到的,还有我自己的一些想法
class Deck(object):
def __init__(self):
self.deck = []
self.dealt = [] #Prevents from dealing the same card
def PopulateDeck(self):
suits = ["Hearts", "Diamonds", "Clubs", "Spades"]
for suit in suits:
for rank in range(2, 15):
if rank == 11:
value = "Jack"
elif rank == 12:
value = "Queen"
elif rank == 13:
value = "King"
elif rank == 14:
value = "Ace"
else:
value = str(rank)
self.deck.append(Card(value, suit))
def deal(self):
#Randomly select card
remaining_cards = [card for card in self.deck if card not in self.dealt]
card_index = random.randrange(0, len(remaining_cards)-1)
card = remaining_cards[card_index]
self.dealt.append(card)
return card
def shuffle(self):
self.dealt = []
class Card(object):
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
self.card = str(self.rank) + " " + str(self.suit)
def __eq__(self, other):
return self.rank == other.rank and self.suit == other.suit
def play():
deck = Deck()
card1 = deck.deal()
card2 = deck.deal()
card3 = deck.deal()
#And here you will compare the cards to see if the player wins or not. Not sure
#what exact criterion you're using.
deck.shuffle() #And leave your deck nicely shuffled for next game
play()
我没有运行这段代码,可能里面有错误。不过这只是一个展示你可以做什么的例子。
这段内容主要是在讨论代码和方法的改进。对于一个纸牌游戏来说,应该用组合的方式来设计,而不是继承。也就是说,Deck
(牌堆)里包含了很多Card
(牌),但Deck
本身并不是一种Card
,反之亦然。
我觉得你在Card
里重复了一些信息。只需要存储花色和点数,然后用__str__
方法来生成像'x of y'
这样的字符串就可以了。你还可以实现一些比较的方法,这样可以让牌之间的比较更简单:
class Card(object):
FACES = {11: 'Jack', 12: 'Queen', 13: 'King', 14: 'Ace'}
def __init__(self, rank, suit):
self.suit = suit
self.rank = rank
def __str__(self):
value = self.FACES.get(self.rank, self.rank)
return "{0} of {1}".format(value, self.suit)
def __lt__(self, other):
return self.rank < other.rank
这样,比如说str(Card(13, 'Clubs'))
就会等于"King of Clubs"
。这样你就不需要在card
里重复存储rank
(点数)和value
(值)了。
接下来,我认为Deck
应该在__init__
方法里生成牌堆的内容;你可以提供一些可选参数来创建非标准的牌堆。我提供了两种实现方式;被注释掉的版本是用itertools
做的列表推导,可以在一行内完成同样的工作。我还提供了一个函数,可以从self.deck
中随机抽取n
张不同的牌。
from itertools import product
import random
class Deck(object):
def __init__(self, ranks=None, suits=None):
if ranks is None:
ranks = range(2, 15)
if suits is None:
suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
## self.deck = [Card(r, s) for r, s in product(ranks, suits)]
self.deck = []
for r in ranks:
for s in suits:
self.deck.append(Card(r, s))
def deal(self, n):
return random.sample(self.deck, n)
现在游戏就简单多了;你可以每手发三张牌,并且可以自然地比较这些牌(比如用<
)因为有了比较的方法。
deck = Deck()
hand = deck.deal(3)
print(" - ".join(map(str, hand)))
if min(hand[0], hand[1]) < hand[2] < max(hand[0], hand[1]):
print("Winner!")
else:
print("Loser.")