求和并添加概率标度

时间:2019-06-19 18:33:25

标签: c# console-application

我正在做一个作业,需要创建一个功能全面的Yahtzee程序。现在我已经完成了初始任务,并且拥有一个功能齐全的Yahtzee应用程序,因此我可以掷骰子,并且可以保存值等。 但是我现在面临的问题是,我需要在混音中添加2个特殊的模具,其中一个模具需要较高的概率输出较小的数字,而另一个模具需要较大的概率输出较高的数字,我还需要为用户提供一种在控制台窗口中调整这些管芯的概率的方法。

所以基本上我正在网上浏览,好像,如果我用一个数组对它进行硬编码,基本上我放置的低位数比高位数更多,它确实可以工作,但这很混乱,而且也没有。不仅解决了该问题,而且使允许用户调整概率的任务非常愚蠢。

自从我使用该网站以来,很久很抱歉,如果这有点草率。

class Dice
{
    public static readonly Random rng = new Random();

        public int NumberOfDice { get; private set; }

        public Dice()
        {
            NumberOfDice = rng.Next(1, 7);
        }

        public void Reroll()
        {
            NumberOfDice = rng.Next(1, 7);
        }
    }

    public bool FirstRound { get; private set; } = true;

    public readonly Dice[] Dices =
    {
        new Dice(),
        new Dice(),
        new Dice(),
        new Dice(),
        new Dice(),

    public void KeepDices(int[] toReroll)
    {
        for (int i = 0; i < Dices.Length; i++)
        {
            bool numFound = false;

            foreach (int roll in toReroll)
            {
                if (Dices[i].NumberOfDice == roll)
                {
                    numFound = true;
                }
            }

            if (numFound)
            {
                continue;
            }
            else
            {
                Dices[i].Reroll();
            }
        }

        ShowDices();
    }

    public void ShowDices()
    {
        Console.WriteLine();

        foreach (Dice dice in Dices)
        {
            Console.Write("[{0}] ", dice.NumberOfDice);
            FirstRound = false;
        }

        Console.WriteLine();
        Console.WriteLine();
    }

    public void RerollAll()
    {
        foreach (Dice dice in Dices)
        {
            dice.Reroll();
        }

        ShowDices();
    }
}

正如我所说的,该程序运行良好,可以运行,但是只需要以某种方式添加一种方法即可将两个骰子与概率联系起来。

4 个答案:

答案 0 :(得分:3)

我最近写了一个由40个部分组成的博客系列,内容涉及如何更优雅地将随机性构建到C#程序中。您的问题已在第9部分中介绍:

https://ericlippert.com/2019/02/28/fixing-random-part-9/

简而言之:创建一个非均匀加权分布对象来表示分布。您可以使用 alias方法有效地实现它。然后,您从该分布中采样来滚动骰子。

然后您可以通过合计各种骰子分布的结果来创建游戏分布,并从中进行采样。

我建议您阅读整个系列;您将从中学到很多东西。从这里开始:

https://ericlippert.com/2019/01/31/fixing-random-part-1/

您可以在此处找到实现别名方法的源代码:

https://github.com/ericlippert/probability/tree/episode09

答案 1 :(得分:1)

您可以为骰子的每个面创建一个概率阵列。

var loadedDice = new double[] { 0.1, 0.12, 0.18, 0.2, 0.21, 0.19 };

现在,您将生成一个介于0.0和1.0之间的随机数,并计算这些概率的总和,直到总和大于或等于该随机数为止。

// Play the dice
double p = rng.NextDouble() * loadedDice.Sum();

double sum = 0.0;
for (int i = 0; i < 6; i++) {
    sum += loadedDice[i];
    if (sum >= p) {
        Console.Write($"The number is {i + 1}");
        break;
    }
}

我们添加一个,因为索引从0开始。


示例:

此图中的x代表运行总和。它们之间的距离对应于阵列中的概率。如果说我们得到的随机数为0.27239827(图像中的p),则对于索引= 2,运行总和变得大于p。我们滚动了3。

     x     x p      x         x          x        x
+----+----+----+----+----+----+----+----+----+----+
0   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9  1.0

答案 2 :(得分:0)

一种方法是在您的ChanceOfRollingSmallNumber类中添加一个名为Dice的属性:

public int ChanceOfRollingSmallNumber { get; set; } = 50;

掷骰子时,生成一个0到99之间的随机数。如果该数字小于ChanceOfRollingSmallNumber,则生成一个较小的随机数,否则生成一个较大的随机数:

if (rng.Next(100) < ChanceOfRollingSmallNumber) {
    NumberOfDice = rng.Next(1, 4);
} else {
    NumberOfDice = rng.Next(4, 7);
}

对于掷骰子可能性很小的骰子,只需将ChanceOfRollingSmallNumber设置为大骰子即可。对于掷骰数很高的骰子,只需将其设置为较小的骰子即可。对于公平的骰子,只需将其设置为50。

如果您想进行更精细的调整,可以将ChanceOfRollingSmallNumber的范围设置为0到1000,或者更大。

答案 3 :(得分:0)

我认为您正在寻找的是加权随机数生成器。

因此,我认为您应该能够根据需要采用此解决方案。

首先,定义您的体重的体重类别。这就是您在骰子侧面使用的东西。

public class WeightUnit
{
    public string Name = string.Empty;
    public int Weight = 0;

    public WeightUnit(string n, int w)
    {
        this.Name = n;
        this.Weight = w;
    }
}

然后此方法将返回加权随机数:

public static WeightUnit GetRandom(List<WeightUnit> weights)
{
    var totalWeight = weights.Sum(x => x.Weight);
    int randomNumber = _rnd.Next(0, totalWeight);

    WeightUnit selected = null;
    foreach (WeightUnit unit in weights)
    {
        if (randomNumber < unit.Weight)
        {
            selected = unit;
            break;
        }

        randomNumber = randomNumber - unit.Weight;
    }

    return selected;
}

这是要验证的主程序:

private static Random _rnd = new Random();

static void Main()
{
    List<WeightUnit> weights = new List<WeightUnit>
    {
        new WeightUnit("1", 20),
        new WeightUnit("2", 20),
        new WeightUnit("3", 20),
        new WeightUnit("4", 10),
        new WeightUnit("5", 10),
        new WeightUnit("6", 10)
    };

    Dictionary<string, int> result = new Dictionary<string, int>();

    WeightUnit selected = null;

    for (int i = 0; i < 1000; i++)
    {
        selected = GetRandom(weights);
        if (selected != null)
        {
            if (result.ContainsKey(selected.Name))
            {
                result[selected.Name] = result[selected.Name] + 1;
            }
            else
            {
                result.Add(selected.Name, 1);
            }
        }
    }


    Console.WriteLine("1\t\t" + result["1"]);
    Console.WriteLine("2\t\t" + result["2"]);
    Console.WriteLine("3\t\t" + result["3"]);
    Console.WriteLine("4\t\t" + result["4"]);
    Console.WriteLine("5\t\t" + result["5"]);
    Console.WriteLine("6\t\t" + result["6"]);
    Console.ReadLine();
}

正如您所看到的,我为数字1,2和3分配了两倍的权重,并且经过1,000次迭代,它们的选择次数是4、5和5的两倍。在列表中,您可以分配所需的权重。

enter image description here