跳到主要内容

21点游戏开发:实现玩家出牌逻辑(Hit / Stand)

在上一篇中,我们已经完成了发牌的基础逻辑。本篇继续完善游戏的核心交互:玩家回合。玩家在回合中可以选择继续要牌(Hit)或停手(Stand),如果点数超过 21 点则直接爆牌,游戏结束。

下面按照「目标 → 代码实现 → 测试 → 结果 → 小结」的完整链路来讲解。

一、目标​

在 player_turn 方法中实现以下逻辑:

  1. 使用 while 循环让玩家可以持续要牌;
  2. 提示玩家输入 h(Hit,继续要牌)或 s(Stand,停手);
  3. 对输入统一转小写,兼容大小写输入;
  4. 输入 h 时调用已有的 hit 方法给玩家发一张牌,并判断是否爆牌(>21 点);
  5. 输入 s 时跳出循环,结束玩家回合;
  6. 输入其他内容时提示「输入有误」。

二、代码实现​

1. 搭建 while 循环与输入提示​

在 player_turn 中加入 while True 循环,并提示用户输入 h 或 s:

while True:
choice = input("请选择:Hit(h) 还是 Stand(s)? ")

2. 统一大小写并分支判断​

用户可能输入大写字母,因此用 choice.lower() 统一转换:

if choice.lower() == 's':
break
elif choice.lower() == 'h':
self.hit(self.player_hand)

3. 复用 hit 方法并判断爆牌​

前面已经定义过 hit 方法,这里直接调用即可,无需重复写发牌逻辑。发牌后通过 get_value() 计算玩家手牌点数,超过 21 点则调用 game_over:

    if self.player_hand.get_value() > 21:
self.game_over("玩家爆掉了,庄家赢")

4. 处理非法输入​

其他输入统一提示错误:

else:
print("输入有误,请输入 h 或者是 s")

5. 完善 game_over 输出格式​

在 game_over 方法中接收 message 参数,并用星号包裹输出,让结束信息更醒目:

def game_over(self, message):
print(f"*** {message} ***")
exit()

6. 修复点数计算的类型错误​

首次运行测试时出现报错:int 与 str 不能相加。原因是 card.rank 是字符串,需要转换为整数后再累加:

value += int(card.rank)

至此,玩家出牌的核心代码完成:

player_turn 中 while 循环、h/s 分支判断与爆牌检测代码

三、测试​

运行程序,每人发两张牌。本次测试中玩家拿到 4 和 A,庄家是 K 和问号。玩家输入 h 继续要牌。

测试中发现两个问题并逐一处理:

  • 报错问题:int 和 str 相加报错,已在 card.rank 处加 int() 转换修复;
  • 体验问题:追加牌后没有展示新牌面,玩家无法判断是否继续。于是补充一段遍历 self.player_hand.cards 并打印每张牌的逻辑,在每次要牌后显示完整牌面信息。

补充的牌面展示代码:

print("玩家牌面信息:")
for card in self.player_hand.cards:
print(card)

追加牌后遍历打印玩家所有手牌的代码

四、结果​

再次运行并输入 h:

  • 程序正确追加了一张牌(本次为 8),并完整展示了玩家的所有牌面(Q、10、8);
  • 由于点数超过 21 点,程序输出「玩家爆掉了,庄家赢」并退出,逻辑符合预期;
  • 输入 s 时,循环通过 break 正常退出,玩家回合结束。

追加牌后展示全部牌面并触发爆牌结束的运行结果

五、小结​

本篇完成了玩家回合的交互逻辑,要点如下:

功能点实现方式
持续要牌while True 循环
输入兼容choice.lower() 统一小写
要牌复用 self.hit(self.player_hand)
爆牌判断get_value() > 21 时调用 game_over
停手输入 s 后 break
非法输入提示「输入有误」
类型修复int(card.rank) 转换后累加

下一篇将继续完善庄家回合与最终胜负判定,敬请期待。

课程推荐

想系统学习这门课程?

你已阅读完本文。需要更完整的知识体系,可以继续了解「Vibe Coding 实战课程」。

查看课程详情