【Puzzle】双骰子赌博

  |  

摘要: 《概率50题》双骰子赌博

【对算法,数学,计算机感兴趣的同学,欢迎关注我哈,阅读更多原创文章】
我的网站:潮汐朝夕的生活实验室
我的公众号:算法题刷刷
我的知乎:潮汐朝夕
我的github:FennelDumplings
我的leetcode:FennelDumplings


这是概率面试题连载第 11 期,我们继续看 《Fifty challenging problems in probability with solutions》 中的一道题。

往期的内容整理在这篇文章里;或者看这个 github 仓库


问题描述

Craps

The game of craps, played with two dice, is one of America’s fastest and most popular gambling games

Calculating the odds associated with it is an instructive exercise

The rules are these:

Only totals for the two dice count
The player throws the dice and wins at once if the total for the first throw is 7 or 11, loses at once if it is 2, 3, or 12
Any other throw is called his “point”
If the first throw is a point, the player throws the dice repeatedly until he either wins by throwing his point again, or loses by throwing 7
What is the player’s chance to win?

双骰子赌博是美国的一个流行的游戏。规则如下:

每次投掷只看两个骰子的点数和
第一次投掷的点数和记为 x,如果 x 是 7 或 11,则立即获胜,如果 x 是2、3或12,则立即输掉,其它情况则需要进行后续的投掷。
从第二次投掷开始,如果投掷出第一次的点数和 x,则获胜,如果投掷出 7,则输掉。重复投掷直至获胜或输掉。

问:获胜的概率是多少。


思路参考

首先考虑第一次投掷

第一次投掷一共有直接输,直接赢,需要继续投掷三种可能性。

(1) 直接输的情况是两枚骰子的和为 2、3、12,两个骰子各自的点数情况有 (1, 1), (2, 1), (1, 2), (6, 6) 这 4 中可能性。而两个骰子各自点数共有 6 * 6 = 36 种可能性,因此第一次投掷直接输的概率为 1/9。

(2) 直接赢的情况是两枚骰子的和为 7, 11,两个骰子各自的点数情况有 (1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (5, 6), (6, 5) 共 8 种可能性,概率 2/9。

(3) 剩下 2/3 概率的情况,需要继续投掷,我们记此前的第 1 次投掷的点数和为 x。

考虑第二次以及后续可能的投掷

从第 2 次开始,以后每次投掷的输、赢、继续投掷的条件都一样。因此我们可以只考虑第 2 次投掷,如果投掷结果是需要继续投掷,递归处理即可。

记某次投掷直接赢的概率为 p,直接输的概率为 q,则需要继续投掷的概率为 (1 - p - q),下面我们看输和赢的具体条件:

(1) 输的情况是投掷出 7,两个骰子各自的点数情况共有 (1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1) 共 6 种情况,概率 q = 1 / 6。

(2) 赢的情况是投掷出 x。两个骰子各自的点数情况需要看 x 具体的值才能确定。下面我们对每个 x 的可能取值(4, 5, 6, 8, 9, 10)分别考虑:

x = 4: (1, 3), (2, 2), (3, 1), 概率 1/12
x = 5: (1, 4), (2, 3), (3, 2), (4, 1), 概率 1/9
x = 6: (1, 5), (2, 4), (3, 3), (2, 4), (1, 5), 概率 5/36
x = 8: (2, 6), (3, 5), (4, 4), (5, 3), (6, 2), 概率 5/36
x = 9: (3, 6), (4, 5), (5, 4), (6, 3), 概率 1/9
x = 10: (4, 6), (5, 5), (6, 4), 概率 1/12

直接赢的概率与 x 有关, 具体的对应关系如下

1
2
3
4
5
6
7
p = mapping[x], 其中
mapping[4] = 1/12
mapping[5] = 1/9
mapping[6] = 1/36
mapping[8] = 1/36
mapping[9] = 1/9
mapping[10] = 1/12

(3) 剩下的情况是需要继续投掷的,概率为 (1 - p(x) - q)

综合以上 3 条,从第二次投掷开始,最终能赢有两种情况,一种是第二次投掷直接赢,另一种是需要继续投掷,并在后续投掷中赢了。记第二次投掷最终会赢的概率为 P(x)

将第一次投掷直接赢和进入第二次投掷并最终赢这两种情况合起来,就是最终能赢的两种情况,概率记为 prob

下面编程计算 prob 这个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mapping = {
4: 1/12,
5: 1/9,
6: 5/36,
8: 5/36,
9: 1/9,
10: 1/12,
}

q = 1/6

prob = 2/9
for x, p in mapping.items():
P = p / (p + q)
prob += p * P
print("Probability of win: {:.6f}".format(prob))

计算结果

1
Probability of win: 0.492929

蒙特卡洛模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from multiprocessing import Pool
import numpy as np

def throw2(x0):
# 第二次以后的投掷
x1 = np.random.randint(1, 7)
x2 = np.random.randint(1, 7)
x = x1 + x2
if x == 7:
return 0
elif x == x0:
return 1
else:
return throw2(x0)

def throw1():
# 第一次投掷
x1 = np.random.randint(1, 7)
x2 = np.random.randint(1, 7)
x = x1 + x2
if x == 7 or x == 11:
return 1
elif x == 2 or x == 3 or x == 12:
return 0
else:
return throw2(x)

def test(T):
np.random.seed()
n = 0
for _ in range(T):
n += throw1()
return n / T

T = int(1e7)
args = [T] * 8
pool = Pool(8)
probs = pool.map(test, args)
for prob in probs:
print("Probability of win: {:.6f}".format(prob))

模拟结果

1
2
3
4
5
6
7
8
Probability of win: 0.492935
Probability of win: 0.492876
Probability of win: 0.492793
Probability of win: 0.492726
Probability of win: 0.493062
Probability of win: 0.493019
Probability of win: 0.493142
Probability of win: 0.492961

Share