如何获得掷骰子的概率总和,其中一个是公平的,另一个是不公平的?

How to get sum of probabilities of rolling w dice where one is fair and the other one is unfair?

我正在写一个小程序,想问一下如何在游戏中添加不公平骰子的逻辑?现在,我的代码生成了掷 2 个 6 面骰子 i 次的概率总和。但是,它以 1/6 的概率掷出给定数字来处理骰子。我该如何调整它,使不公平的骰子只出现在 2-5 的范围内,而不会出现在 1 或 6 的范围内?在给定公平和不公平骰子的情况下,输出应该是 2-12 范围内所有数字的概率总和。

import random
from collections import defaultdict

def main():
    dice = 2
    sides = 6
    rolls = int(input("Enter the number of rolls to simulate: "))
    result = roll(dice, sides, rolls)
    maxH = 0
    for i in range(dice, dice * sides + 1):
        if result[i] / rolls > maxH: maxH = result[i] / rolls
    for i in range(dice, dice * sides + 1):
        print('{:2d}{:10d}{:8.2%} {}'.format(i, result[i], result[i] / rolls, '#' * int(result[i] / rolls / maxH * 40)))


def roll(dice, sides, rolls):
    d = defaultdict(int)
    for _ in range(rolls):
        d[sum(random.randint(1, sides) for _ in range(dice))] += 1
    return d

main()

输出

Enter the number of rolls to simulate: 10000
 2       265   2.65% ######
 3       567   5.67% #############
 4       846   8.46% ####################
 5      1166  11.66% ############################
 6      1346  13.46% ################################
 7      1635  16.35% ########################################
 8      1397  13.97% ##################################
 9      1130  11.30% ###########################
10       849   8.49% ####################
11       520   5.20% ############
12       279   2.79% ######

鉴于目前哪些结果可能的逻辑被线路控制

random.randint(1, sides)

如果你想以不同的界限滚动,那是要改变的线。例如,要获得 2-5,您可以概括函数:

def main():
    dice = 2
    sides = 6
    unfair_min = 2
    unfair_max = 5
    rolls = int(input("Enter the number of rolls to simulate: "))
    result_unfair = roll_biased(dice, sides, rolls, min_roll=unfair_min, max_roll=unfair_max)
    maxH = max(result_unfair.values()) / rolls

    for i in range(dice, dice * sides + 1):
        print('{:2d}{:10d}{:8.2%} {}'.format(i, result_unfair[i], result_unfair[i] / rolls,
                                             '#' * int(result_unfair[i] / rolls / maxH * 40)))


def roll_biased(dice, sides, rolls, min_roll=1, max_roll=None):
    if max_roll is None:
        max_roll = sides
    d = defaultdict(int)
    for _ in range(rolls):
        d[sum(random.randint(min_roll, max_roll) for _ in range(dice))] += 1
    return d

可以打印:

Enter the number of rolls to simulate: 10000
 2         0   0.00% 
 3         0   0.00% 
 4       632   6.32% ##########
 5      1231  12.31% ###################
 6      1851  18.51% #############################
 7      2480  24.80% ########################################
 8      1873  18.73% ##############################
 9      1296  12.96% ####################
10       637   6.37% ##########
11         0   0.00% 
12         0   0.00% 

您也可以使用 random.choices() 将其概括为任意选择(或任意权重):

def roll_from_choices(dice, sides, rolls, allowed_rolls=None):
    if allowed_rolls is None:
        allowed_rolls = list(range(1, sides+1))
    d = defaultdict(int)

    for _ in range(rolls):
        d[sum(random.choices(allowed_rolls, k=dice))] += 1
    return d

您可以称其为:

result_unfair = roll_from_choices(dice, sides, rolls, allowed_rolls=[2, 3, 4, 5])

我会开始一个函数,returns掷骰子(a)的结果,其中可以定制可用选项以排除不可能的选项,例如:

import random

def throw_die(options):
    return random.choice(options)

然后我会为一般情况编写代码,您可以拥有 any 个骰子,每个 个不同的能力(待通过作为掷骰子时的选项)。在您的特定情况下,这将是两个骰子,第二个骰子不包括 16(b):

dice = [
    [1, 2, 3, 4, 5, 6],
    [   2, 3, 4, 5   ]
]

然后为结果分配足够的存储空间(我在这里浪费了少量 space 以确保收集数据的代码更简单):

min_res = sum([min(die) for die in dice]) # Smallest possible result,
max_res = sum([max(die) for die in dice]) #   and largest.
count = [0] * (max_res + 1)               # Allocate space + extra.

你的数据收集相对简单(我在这里硬编码了滚动计数而不是使用输入,但你可以把它放回去):

rolls = 10000 # rolls = int(input("How many rolls? "))
for _ in range(rolls):
    # Throw each die, sum the results, then increment correct count.

    result = sum([throw_die(die) for die in dice])
    count[result] += 1

并且数据输出可以这样完成(四舍五入而不是截断,以便最高计数有 40 个哈希值——这只是我的 CDO(c) 性质):

hash_mult = 40 / max(count)
for i in range(min_res, max_res + 1):
    per_unit = count[i] / rolls
    hashes = "#" * int(count[i] * hash_mult + 0.5)
    print(f"{i:2d}{count[i]:10d}{per_unit:8.2%} {hashes}")

完整的程序变成:

import random

# Throw a single die.

def throw_die(options):
    return random.choice(options)

# Define all dice here as list of lists.
# No zero/negative number allowed, will
#   probably break code :-)

dice = [
    [1, 2, 3, 4, 5, 6],
    [   2, 3, 4, 5   ]
]

# Get smallest/largest possible result.

min_res = sum([min(die) for die in dice])
max_res = sum([max(die) for die in dice])

# Some elements wasted (always zero) to simplify later code.
# Example: throwing three normal dice cannot give 0, 1, or 2.

count = [0] * (max_res + 1)

# Do the rolls and collect results.

rolls = 10000
for _ in range(rolls):
    result = sum([throw_die(die) for die in dice])
    count[result] += 1

# Output all possible results.

hash_mult = 40 / max(count)
for i in range(min_res, max_res + 1):
    per_unit = count[i] / rolls
    hashes = "#" * int(count[i] * hash_mult + 0.5)
    print(f"{i:2d}{count[i]:10d}{per_unit:8.2%} {hashes}")

和一些示例运行以查看它的实际效果:

pax:/mnt/c/Users/Pax/Documents/wsl> python prog.py
 3       418   4.18% #########
 4       851   8.51% ####################
 5      1266  12.66% ##############################
 6      1681  16.81% ########################################
 7      1606  16.06% ######################################
 8      1669  16.69% #######################################
 9      1228  12.28% #############################
10       867   8.67% ####################
11       414   4.14% #########

pax:/mnt/c/Users/Pax/Documents/wsl> python prog.py
 3       450   4.50% ##########
 4       825   8.25% ###################
 5      1206  12.06% ############################
 6      1655  16.55% #######################################
 7      1679  16.79% ########################################
 8      1657  16.57% #######################################
 9      1304  13.04% ###############################
10       826   8.26% ###################
11       398   3.98% #########

pax:/mnt/c/Users/Pax/Documents/wsl> python prog.py
 3       394   3.94% #########
 4       838   8.38% ####################
 5      1271  12.71% ##############################
 6      1617  16.17% ######################################
 7      1656  16.56% #######################################
 8      1669  16.69% ########################################
 9      1255  12.55% ##############################
10       835   8.35% ####################
11       465   4.65% ###########

脚注:

(a) 对单骰子和多骰子使用正确的命名法,以防任何非英语使用者感到困惑。

(b) 你也可以处理像 [1, 2, 3, 4, 4, 5, 6] 这样的情况,你得到 4 的可能性是任何其他号码。任何比这更复杂的事情最好用一个元组来处理,该元组代表每个可能的结果及其相对可能性。可能有点太复杂了,无法放入脚注(考虑到这不是问题的要求),但如果您有兴趣,可以随时在 separate 问题中询问这个问题。

(c) 就像强迫症一样,但顺序正确:-)