跳到主要内容

用 Python 实现 21 点游戏:庄家逻辑与胜负判定

前面我们已经完成了玩家部分的逻辑,玩家停牌之后,就该轮到庄家行动了。本文继续把庄家的发牌规则、爆牌判断以及最终的胜负比较补齐,并让游戏在结束时把双方牌面都展示出来。

一、庄家的加牌规则​

21 点里庄家的规则很固定:前两张牌点数小于 17 就必须继续加牌,16 也不行,必须追加。由于不知道要加几张,这里用一个 while 循环持续判断。

核心思路是调用 self.dealer_hand.get_value() 获取庄家当前牌面值,只要小于 17 就调用 self.hit 给庄家发牌:

while self.dealer_hand.get_value() < 17:
self.hit(self.dealer_hand)

如果记不清 hit 方法的参数,可以在编辑器里点进去查看——它接收一个 hand 对象,而 hand 正是实例化时定义的两个对象:玩家的和庄家的。所以这里传入 self.dealer_hand 即可。

当庄家点数达到或超过 17,循环结束,进入下一步判断。

庄家点数小于17时用while循环持续加牌的代码

二、判断庄家是否爆牌​

庄家同样可能超过 21 点。循环结束后,先取庄家牌面值判断是否爆掉:

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

一旦爆牌,直接调用 self.game_over 并传入提示信息,本局结束。

判断庄家点数大于21时调用game_over并提示庄家爆掉

三、双方都没爆时的胜负比较​

如果庄家没爆,就用 elif 继续比较庄家和玩家的点数。这里采用一个常见规则:点数相同时算庄家赢(各地规则不同,若你希望相同算平局,可以自行调整判断)。

elif self.dealer_hand.get_value() >= self.player_hand.get_value():
self.game_over("庄家点数大,庄家赢")
else:
self.game_over("玩家赢")

大于等于都归庄家,剩下的情况就是玩家赢。

庄家点数大于等于玩家时庄家赢否则玩家赢的elif分支

四、补上结果显示,让牌面可见​

把庄家方法接入主流程后测试:玩家拿到 4 和 5 共 9 点,追加一张 9 到 18 点后输入 s 停牌,流程顺利进入庄家环节。但此时直接弹出"庄家爆掉了,玩家赢",玩家根本看不到庄家的牌,体验很差。

于是我们在 show_result 里补充输出:分别打印玩家牌面信息和庄家牌面信息,再输出整体结果。玩家部分沿用之前写好的显示方法,庄家部分则遍历 self.dealer_hand.cards 输出,并用 * 乘 30 做分隔线:

def show_result(self):
# 玩家牌面信息
print("玩家牌面信息")
# ...(沿用已有显示逻辑)
# 庄家牌面信息
print("庄家牌面信息")
for card in self.dealer_hand.cards:
print(card)
print("*" * 30)

show_result方法中分别打印玩家和庄家牌面信息

五、在 game_over 前调用结果显示​

光写好方法还不够,需要在 game_over 之前调用 self.show_result(),否则结果页依旧看不到牌面:

self.show_result()
self.game_over(...)

在game_over调用前插入self.show_result()

六、测试验证​

重新运行游戏:

  • 第一把:玩家 6、3 共 9 点,追加 2 到 11 点,再追加 9 到 20 点,输入 s 停牌。进入庄家环节后,双方牌面正常显示。
  • 第二把:玩家 6、9、9 直接爆掉,游戏正确结束。
  • 第三把:玩家 19 点停牌,庄家翻开底牌为 10 和 A,合计 21 点,庄家赢,判定无误。

测试运行中庄家底牌为10和A合计21点判定庄家赢

小结​

本文完成了 21 点游戏的庄家逻辑:

  1. 用 while 循环实现"小于 17 必须加牌"的庄家规则;
  2. 循环结束后判断庄家是否爆牌,爆牌则直接结束并提示玩家赢;
  3. 双方都未爆牌时比较点数,相同或庄家大算庄家赢,否则玩家赢;
  4. 在 show_result 中补充庄家牌面输出,并在 game_over 前调用,保证结果页能看到双方手牌。

至此,玩家与庄家的完整对局流程已经跑通,游戏可以正常分出胜负了。

课程推荐

想系统学习这门课程?

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

查看课程详情