21点游戏开发:实现玩家出牌逻辑(Hit / Stand)
在上一篇中,我们已经完成了发牌的基础逻辑。本篇继续完善游戏的核心交互:玩家回合。玩家在回合中可以选择继续要牌(Hit)或停手(Stand),如果点数超过 21 点则直接爆牌,游戏结束。
下面按照「目标 → 代码实现 → 测试 → 结果 → 小结」的完整链路来讲解。
一、目标
在 player_turn 方法中实现以下逻辑:
- 使用
while循环让玩家可以持续要牌; - 提示玩家输入
h(Hit,继续要牌)或s(Stand,停手); - 对输入统一转小写,兼容大小写输入;
- 输入
h时调用已有的hit方法给玩家发一张牌,并判断是否爆牌(>21 点); - 输入
s时跳出循环,结束玩家回合; - 输入其他内容时提示「输入有误」。
二、代码实现
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)
至此,玩家出牌的核心代码完成:

三、测试
运行程序,每人发两张牌。本次测试中玩家拿到 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 实战课程」。
查看课程详情