21点游戏开发:手牌点数计算(含A的软硬手处理)
在21点游戏中,玩家最终要比拼的是手牌点数。因此我们需要为手牌类(Hand)增加一个 get_value() 方法,用于计算当前手牌的总点数。
这个方法的难点在于 A 的特殊处理:A 既可以当作 1 点,也可以当作 11 点(即所谓的“软硬手”)。J、Q、K 统一按 10 点计算,2~10 按面值计算。
一、实现思路
- 初始化总点数
value = 0,并设置一个计数器记录 A 出现的次数。 - 遍历
self.cards中的每一张牌,取出card.rank:- 如果是数字(2~10),直接累加数值;
- 如果是 A,先按 1 点累加,并记录 A 的数量;
- 如果是 J/Q/K,直接加 10。
- 遍历结束后,单独处理 A 的情况:如果存在 A,判断“把所有 A 都当作 11 点”时总点数是否超过 21。超过则全部按 1 点计算;未超过则额外加 10(即把其中一张 A 当作 11 点)。
- 返回最终点数。
二、代码实现
在 Hand 类中新增 get_value 方法:
def get_value(self):
value = 0
ace_count = 0 # 记录 A 的数量
for card in self.cards:
if card.rank.isdigit():
# 2 到 10,直接计算
value += int(card.rank)
elif card.rank == 'A':
# A 先按 1 计算,并记录数量
value += 1
ace_count += 1
else:
# J Q K,直接加 10
value += 10
# 处理 A 的情况
if ace_count > 0:
if value + ace_count + 10 > 21:
# 当作 11 会超过 21 点,只能按 1 计算
value += ace_count
else:
# 未超过 21 点,可以当作 11 使用
value += 10
return value

三、逻辑说明
- 为什么先按 1 累加 A? 这样可以保证任何情况下都不会爆点,后续再根据总点数决定是否“升级”为 11。
- 判断条件
value + ace_count + 10 > 21:value中已经包含了每张 A 的 1 点,ace_count + 10表示把其中一张 A 从 1 点提升到 11 点(多出 10 点)后的增量。若提升后超过 21,则不能提升,全部保持 1 点。 - 多张 A 的情况:即使手中有多张 A,也最多只有一张能按 11 点计算(两张 A 按 11 算就是 22 点,必然爆点),因此只需加一次 10。
四、测试验证
代码写完后运行程序,发牌并调用 get_value() 查看手牌点数输出,确认数字牌、J/Q/K 以及含 A 的软硬手计算结果均正确。

五、小结
至此,Hand 类的核心方法已经完成:
- 判断是否可以继续加牌;
- 加一张牌;
- 计算手牌点数(
get_value)。
其中 get_value 包含了一点点算法逻辑,重点就是 A 的软硬手判断:先按 1 点保底累加,再根据是否超过 21 点决定是否把一张 A 提升为 11 点。理解了这个思路,后续比较玩家与庄家点数就非常直接了。
想系统学习这门课程?
你已阅读完本文。需要更完整的知识体系,可以继续了解「Vibe Coding 实战课程」。
查看课程详情