跳到主要内容

21点游戏开发:手牌点数计算(含A的软硬手处理)

在21点游戏中,玩家最终要比拼的是手牌点数。因此我们需要为手牌类(Hand)增加一个 get_value() 方法,用于计算当前手牌的总点数。

这个方法的难点在于 A 的特殊处理:A 既可以当作 1 点,也可以当作 11 点(即所谓的“软硬手”)。J、Q、K 统一按 10 点计算,2~10 按面值计算。

一、实现思路​

  1. 初始化总点数 value = 0,并设置一个计数器记录 A 出现的次数。
  2. 遍历 self.cards 中的每一张牌,取出 card.rank:
    • 如果是数字(2~10),直接累加数值;
    • 如果是 A,先按 1 点累加,并记录 A 的数量;
    • 如果是 J/Q/K,直接加 10。
  3. 遍历结束后,单独处理 A 的情况:如果存在 A,判断“把所有 A 都当作 11 点”时总点数是否超过 21。超过则全部按 1 点计算;未超过则额外加 10(即把其中一张 A 当作 11 点)。
  4. 返回最终点数。

二、代码实现​

在 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

image-20261028153222288

三、逻辑说明​

  • 为什么先按 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 实战课程」。

查看课程详情