精确计算二十一点庄家手牌概率的递归实现问题
二十一点庄家概率计算的递归实现问题
我正在编写一个精确推导二十一点基本策略的程序,需要计算庄家拿到17、18、19、20、21点或爆牌的概率。以下是计算庄家概率的代码,但无法实现正确递归调用,仅支持首张牌场景:
Odds = [0] * 33 Odds[dealerTotal] = 100 def getDealerOdds(dealerTotal): branchScenario = [] if dealerTotal < 17: for card in values: branchScenario.append(dealerTotal + int(card)) redistribute = Odds[dealerTotal] Odds.pop(dealerTotal) for num in branchScenario: if num != dealerTotal + 10: Odds[num] += redistribute / 13 else: Odds[num] += (redistribute * 4) / 13 # 递归调用此处无法正常工作 if num < 17: getDealerOdds(num) return Odds
问题分析
- 全局变量污染:递归调用直接修改全局
Odds数组,不同分支的概率计算会相互覆盖,导致结果错误。 - 数组操作错误:
Odds.pop(dealerTotal)会删除数组元素,破坏索引与点数的对应关系(索引应对应庄家总点数),正确做法是将该位置概率置为0。 - 递归状态传递错误:未为每个递归分支传递独立的概率分布,依赖全局状态导致无法正确累积各分支概率。
修复后的代码
改用局部概率分布传递递归状态,避免全局变量干扰,同时模拟真实牌库消耗逻辑:
def get_dealer_odds(dealer_total, remaining_cards=None): # 初始化一副牌的分布:10/J/Q/K共4张,其余点数各1张,A暂按11计算 if remaining_cards is None: remaining_cards = {2:1, 3:1, 4:1, 5:1, 6:1, 7:1, 8:1, 9:1, 10:4, 11:1} total_cards = sum(remaining_cards.values()) # 初始化概率结果,索引32代表爆牌 odds = [0.0] * 33 if dealer_total >= 22: odds[32] = 100.0 return odds if dealer_total >= 17: odds[dealer_total] = 100.0 return odds # 遍历所有可能的牌,计算分支概率 for card, count in remaining_cards.items(): card_prob = (count / total_cards) * 100 new_total = dealer_total + card if new_total > 21: # 抽牌后直接爆牌 odds[32] += card_prob else: # 复制当前牌库,模拟抽走一张牌 new_remaining = remaining_cards.copy() new_remaining[card] -= 1 if new_remaining[card] == 0: del new_remaining[card] # 递归获取后续概率并叠加 sub_odds = get_dealer_odds(new_total, new_remaining) for idx in range(33): odds[idx] += card_prob * (sub_odds[idx] / 100) return odds # 示例调用:计算庄家初始手牌16点的最终概率分布 result = get_dealer_odds(16) print("庄家各点数概率:") print(f"17点: {result[17]:.2f}%") print(f"18点: {result[18]:.2f}%") print(f"19点: {result[19]:.2f}%") print(f"20点: {result[20]:.2f}%") print(f"21点: {result[21]:.2f}%") print(f"爆牌: {result[32]:.2f}%")
关键改进点
- 用局部概率分布传递递归状态,每个分支独立计算,避免全局变量干扰。
- 模拟真实牌库消耗逻辑,支持多副牌场景(调整
remaining_cards初始值即可)。 - 明确处理爆牌情况,递归叠加后续分支的概率结果。
- 可根据赌场规则调整软牌(如A+6=17)的停牌逻辑,修改
dealer_total >=17的判断条件即可。
内容的提问来源于stack exchange,提问作者Einsneins
相关产品推荐
相关产品推荐

