不公平掷币代码与Gambler's ruin理论结果不符问题排查
问题分析与解决方案
1. 代码错误原因
你的核心问题在于unfair_flip函数的逻辑完全不符合赌徒破产的规则:
- 原问题是单次掷币:正面(0.6概率)则玩家1赢1便士、玩家2输1便士;反面(0.4概率)则玩家2赢1便士、玩家1输1便士。
- 但你的代码里每次调用
unfair_flip会掷两次硬币,分别判断玩家1和玩家2的胜负,这会导致四种混乱情况:- 玩家1掷正面、玩家2掷反面:双方分数抵消,无变化
- 玩家1掷正面、玩家2掷正面:玩家1+1,玩家2-1
- 玩家1掷反面、玩家2掷反面:玩家1-1,玩家2+1
- 玩家1掷反面、玩家2掷正面:双方分数抵消,无变化
这直接篡改了游戏的概率模型,导致玩家1的实际获胜概率被错误放大,和理论值偏差巨大。
2. 修正后的代码
把unfair_flip改成单次掷币判断即可,修正后结果会接近理论值0.8703:
import random as rd def unfair_flip(sc1, sc2): # 单次掷币,0.6概率正面(玩家1赢),0.4概率反面(玩家2赢) if rd.random() < 0.6: sc1 += 1 sc2 -= 1 else: sc1 -= 1 sc2 += 1 return sc1, sc2 def proba_check(it): wins_p1 = 0 total_pennies = 5 + 10 # 总便士数,用来判断终止条件 for _ in range(it): player1, player2 = 5, 10 while player1 > 0 and player2 > 0: player1, player2 = unfair_flip(player1, player2) if player1 == total_pennies: wins_p1 += 1 return round(wins_p1/it, 4) print(f"玩家1获胜概率: {proba_check(10000)}")
3. 更高效的不公平掷币实现方式
方式1:使用random.choices指定权重
无需构建冗余列表,直接通过权重参数指定概率,简洁高效:
def player1_wins(): # 直接按权重返回胜负结果 return rd.choices(['win', 'lose'], weights=[0.6, 0.4])[0] == 'win' def unfair_flip(sc1, sc2): if player1_wins(): sc1 += 1 sc2 -= 1 else: sc1 -= 1 sc2 += 1 return sc1, sc2
方式2:直接用数学公式计算理论值(无需模拟)
对于不公平赌徒破产问题,理论获胜概率可以直接用公式计算,完全不需要模拟,结果精确且效率极高:
设玩家1初始资金为i,总资金为N,玩家1每轮获胜概率为p,失败概率q=1-p(p≠q),则玩家1最终获胜概率为:
$$
P = \frac{1 - (q/p)^i}{1 - (q/p)^N}
$$
代入参数i=5、N=15、p=0.6、q=0.4,代码实现如下:
p = 0.6 q = 1 - p i = 5 N = 15 probability = (1 - (q/p)**i) / (1 - (q/p)**N) print(f"玩家1理论获胜概率: {round(probability, 4)}")
方式3:优化模拟循环
如果必须做模拟,可减少函数调用开销,把掷币逻辑直接嵌入循环:
def proba_check(it): wins_p1 = 0 p = 0.6 total = 15 for _ in range(it): p1 = 5 p2 = 10 while p1 > 0 and p2 > 0: if rd.random() < p: p1 += 1 p2 -= 1 else: p1 -= 1 p2 += 1 if p1 == total: wins_p1 += 1 return round(wins_p1/it, 4)
内容的提问来源于stack exchange,提问作者yasper99
相关产品推荐
相关产品推荐

