15. 应用案例:扑克游戏
简单起见,我们的扑克只有52张牌(没有大小王),游戏需要将 52 张牌发到 4 个玩家的手上,每个玩家手上有 13 张牌,按照黑桃、红心、草花、方块的顺序和点数从小到大排列。
步骤1:定义花色枚举
如果一个变量的取值只有有限多个选项,我们可以使用枚举。Python 中没有声明枚举类型的关键字,但是可以通过继承 enum 模块的 Enum 类来创建枚举类型。
python
from enum import Enum
class Suite(Enum):
"""花色(枚举)"""
SPADE, HEART, CLUB, DIAMOND = range(4)
定义枚举类型其实就是定义符号常量,如 SPADE、HEART 等。使用符号常量优于使用字面常量,因为能够读懂英文就能理解符号常量的含义,代码的可读性会提升很多。
步骤2:定义牌类 Card
python
class Card:
"""牌"""
def __init__(self, suite, face):
self.suite = suite
self.face = face
def __repr__(self):
suites = '♠♥♣♦'
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
return f'{suites[self.suite.value]}{faces[self.face]}'
步骤3:定义扑克类 Poker
python
import random
class Poker:
"""扑克"""
def __init__(self):
self.cards = [Card(suite, face)
for suite in Suite
for face in range(1, 14)] # 52张牌构成的列表
self.current = 0 # 记录发牌位置的属性
def shuffle(self):
"""洗牌"""
self.current = 0
random.shuffle(self.cards) # 通过random模块的shuffle函数实现随机乱序
def deal(self):
"""发牌"""
card = self.cards[self.current]
self.current += 1
return card
@property
def has_next(self):
"""还有没有牌可以发"""
return self.current < len(self.cards)
步骤4:定义玩家类 Player
python
class Player:
"""玩家"""
def __init__(self, name):
self.name = name
self.cards = [] # 玩家手上的牌
def get_one(self, card):
"""摸牌"""
self.cards.append(card)
def arrange(self):
"""整理手上的牌"""
self.cards.sort()
步骤5:运算符重载 __lt__
执行 player.arrange() 时,排序需要比较两个 Card 对象的大小,而 < 运算符不能直接作用于 Card 类型。为解决这个问题,需要对 Card 类进行运算符重载,添加 __lt__ 魔法方法:
python
class Card:
"""牌"""
def __init__(self, suite, face):
self.suite = suite
self.face = face
def __repr__(self):
suites = '♠♥♣♦'
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
return f'{suites[self.suite.value]}{faces[self.face]}'
def __lt__(self, other):
if self.suite == other.suite:
return self.face < other.face # 花色相同比较点数的大小
return self.suite.value < other.suite.value # 花色不同比较花色对应的值
魔术方法 __lt__ 中的 lt 是 "less than" 的缩写。同理:__gt__ 对应 >,__le__ 对应 <=,__ge__ 对应 >=,__eq__ 对应 ==,__ne__ 对应 !=。
步骤6:发牌与输出
python
poker = Poker()
poker.shuffle()
players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]
# 将牌轮流发到每个玩家手上每人13张牌
for _ in range(13):
for player in players:
player.get_one(poker.deal())
# 玩家整理手上的牌输出名字和手牌
for player in players:
player.arrange()
print(f'{player.name}: ', end='')
print(player.cards)