不同类型的骰子投掷后点数和的概率

3
我目前正在开发一个Java应用程序,需要计算各种骰子的每个点数出现的概率。我支持的骰子类型有d4(四面体骰子)、d6(六面体骰子)、d8(八面体骰子)、d10、d12和d20。用户可以输入他们想要在计算中使用的每种骰子的数量。例如,用户可能输入6个d6和4个d4。
根据这些信息(每种骰子的数量),我将计算每个可能点数被投出的概率。然后,我将使用这些信息创建一个图表,显示所选骰子组合的概率分布。
该应用程序是用Java编写的。
目前我已经编写了一个函数,用于仅使用一种骰子计算特定点数的概率。
/*
    Recursively calculates the probability of rolling a particular number
    when rolling multiple dice of one type
    @param dice Number of dice
    @param seekedValue Value whose probability is being calculated
    @param sides Number of sides on the type of die
     */
    private double diceProb(int dice, int seekedValue, int sides){
        if (dice == 0){
            if (seekedValue == 0){
                return 1.0;
            } else {
                return 0.0;
            }
        } else {
            double sum = 0;
            for (int i = seekedValue - sides; i < seekedValue; i++){
                sum += diceProb(dice -1, i, sides) / sides;
            }
            return sum;
        }

    }

我使用这段代码来查找所有可能的概率。
/*
Variable Explanations:
diceEntries: This array list contains the number of each dice supplied by the user.
It is ordered by number of sides, with d4 at the beginning and d20 at the end
diceValues: This array contains the sides of the dice types
probArray: this array list will contain the probabilities of each sum possible
min: the minimum sum  possible
max: the maximum sum possible
*/
ArrayList<Integer> diceEntries
ArrayList<Float> probArray = new ArrayList<>();
int[] diceValues = {4,6,8,10,12,20};
float prob = 0;
for (int i = min; i <= max; i++){
    for (int j = 0; j <= 5; j++) {
        prob = (float) diceProb(diceEntries.get(j), i, diceValues[j]);
        if (prob != 0) {
            probArray.add(prob);
        }
    }
}

我的当前代码只能处理一种大小的骰子,即只有d6或d4而不能混合使用。

如果社区能提供一些指导,那将不胜感激。我也可以接受其他方法。例如,我已经了解到生成函数可能是更好的方法,但我的组合统计学有点薄弱,如果有人能编写出这样的代码,那就太好了。

非常感谢大家。


不确定这是否有帮助,但这里的示例:[链接](http://www.wikihow.com/Calculate-Multiple-Dice-Probabilities)提供了一个算法,可用于骰子数量(n),面数(r)和目标总和(k)。 - James C. Taylor IV
3个回答

3

用一个整数列表(骰子面)实现的暴力方法的另一种实现,处理多种骰子类型。优点是如果您需要大量的概率,可以运行一次,然后查询各种概率。缺点是作为暴力方法,只想获取单个概率非常低效。

public int[] probs;

public void genRolls(int sum, List<Integer> sides)
{
    if (sides.size() == 0)
    {
        probs[sum]++;
        return;
    }
    int top = sides.get(0);
    for (int x = 1; x <= top; x++)
        genRolls(sum+x, sides.subList(1, sides.size()));
}

public void diceprob(int target, List<Integer> sides)
{
    int maxval = 0;
    double possibilities = 1;
    for (Integer i : sides)
    {
        maxval+= i;
        possibilities *= i;
    }
    probs = new int[maxval+1];
    genRolls(0, sides);
    System.out.println("Probability is " + (probs[target]/possibilities));
}

你的方法如何支持同一类型的多个骰子?例如,我如何在一个包含6面骰子和4面骰子的集合中使用它? - Andrew
该列表由骰子面组成。3d6 + 2d4将是[6,6,6,4,4],顺序任意。 - Thomas

0
你可以简单地模拟所有组合。下面的代码是针对 nD6 进行的,但这个例子应该可以扩展到多个骰子类型。
public class Main {

    static final int FACES = 6;
    int[] buckets;
    int[] currentCombination;
    int totalCombinations;

    public Main(int numberOfDices) {
        this.buckets = new int[FACES * numberOfDices];
        this.currentCombination = new int[numberOfDices];
        this.totalCombinations = 0;
    }

    public void calculate() {
        calculate(this.currentCombination.length);
        for (int i = 0; i < this.buckets.length; ++i) {
            System.out.println((i + 1) + ":\t" + this.buckets[i] + " / "
                    + this.totalCombinations);
        }
    }

    public void calculate(int dicesLeft) {
        if (0 == dicesLeft) {
            int sum = 0;
            for (int die : this.currentCombination) {
                sum += die;
            }
            ++this.buckets[sum - 1];
            ++this.totalCombinations;
        } else {
            --dicesLeft;
            for (int die = 1; die <= FACES; ++die) {
                currentCombination[dicesLeft] = die;
                calculate(dicesLeft);
            }
        }
    }

    public static void main(String... args) {
        int n = Integer.parseInt(args[0]);
        Main m = new Main(N);
        m.calculate();
    }
}

0

独立变量之和的概率是每个变量概率的卷积。对于离散变量,卷积是一个简单的求和,您可以在Java中轻松实现。我的建议是按照以下方式组织计算:

get numbers of dice and numbers of sides
for each die
    construct array with length=number of sides and each element=1/(number of sides)

let convolution result=first array
for second through rest of arrays
    let convolution result = convolution(result, next array)

output result

多个函数的卷积可以一次计算两个,顺序无关紧要。

对于两个数组 ab 的卷积只需:

for i=0 through length(a) + length(b) - 2 inclusive,
    conv[i] = sum(a[j]*b[i - j], j, max(0, i - length(b) + 1), min(length(a) -1, i))

您可以使用 Octave 等工具方便地检查结果。在 Octave 中,conv 是卷积函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接