C#加权随机数

问题描述 投票:2回答:4

我需要一个游戏的编程帮助。

你打开胸部和给定的概率你找到一个项目。

项目/机会

A / 10% B / 30% ℃/ 60%

Random random = new Random();
int x = random.Next(1, 101);

if (x < 11) // Numbers 1..10 ( A -> 10% )
{ 
     do_something1(); d
} 
else if (x < 41) // Numbers 11..40 ( B -> 30 % )
{ 
     do_something2();
}
else if (x < 101) // Numbers 41..100 ( C -> 60 % ) 
{ 
     do_something3();
}

难道这个例子真的有意义,从概率上?你有另一种解决方案?

先感谢您!

c# unity3d random
4个回答
4
投票

我同意@Timothy,我会去一个更易于维护的解决方案,在那里你不能依靠magic numbers分裂您的概率。此外,这是个人喜好,但我也愿意把它比而不是百分比,否则“100”变成了另一个神奇的数字,你限制自己1%的概率最小。这样你就可以把它分解1:10:200或不过请您:

public static readonly int RATIO_CHANCE_A = 10;
public static readonly int RATIO_CHANCE_B = 30;
//                         ...
public static readonly int RATIO_CHANCE_N = 60;

public static readonly int RATIO_TOTAL = RATIO_CHANCE_A
                                       + RATIO_CHANCE_B
                                         // ...
                                       + RATIO_CHANCE_N;

Random random = new Random();
int x = random.Next(0, RATIO_TOTAL);

if ((x -= RATIO_CHANCE_A) < 0) // Test for A
{ 
     do_something1();
} 
else if ((x -= RATIO_CHANCE_B) < 0) // Test for B
{ 
     do_something2();
}
// ... etc
else // No need for final if statement
{ 
     do_somethingN();
}

编辑:更广义的解决方案


2
投票

我意识到这是一个稍微晚了,但这里又未consts的例子,费力的if / else和/或switch语句;

public class WeightedChanceParam
{
    public Action Func { get; }
    public double Ratio { get; }

    public WeightedChanceParam(Action func, double ratio)
    {
        Func = func;
        Ratio = ratio;
    }
}

public class WeightedChanceExecutor
{
    public WeightedChanceParam[] Parameters { get; }
    private Random r;

    public double RatioSum
    {
        get { return Parameters.Sum(p => p.Ratio); }
    }

    public WeightedChanceExecutor(params WeightedChanceParam[] parameters)
    {
        Parameters = parameters;
        r = new Random();
    }

    public void Execute()
    {
        double numericValue = r.NextDouble() * RatioSum;

        foreach (var parameter in Parameters)
        {
            numericValue -= parameter.Ratio;

            if (!(numericValue <= 0))
                continue;

            parameter.Func();
            return;
        }

    }
}

使用示例:

WeightedChanceExecutor weightedChanceExecutor = new WeightedChanceExecutor(
    new WeightedChanceParam(() =>
    {
        Console.Out.WriteLine("A");
    }, 25), //25% chance (since 25 + 25 + 50 = 100)
    new WeightedChanceParam(() =>
    {
        Console.Out.WriteLine("B");
    }, 50), //50% chance
    new WeightedChanceParam(() =>
    {
        Console.Out.WriteLine("C");
    }, 25) //25% chance
);

//25% chance of writing "A", 25% chance of writing "C", 50% chance of writing "B"        
weightedChanceExecutor.Execute(); 

1
投票

因此得出结论解决方案在这里是没有很多的if-else语句,但一个开关的情况下,而不是为任何数量的可能性的解决方案:

int[] chances = { 1, 23, 14, 49, 61 };
int totalRatio = 0;

foreach(int c in chances)
    totalRatio += c;

Random random = new Random();
int x = random.Next(0, totalRatio);

int iteration = 0; // so you know what to do next
foreach(int c in chances)
{
    iteration++;
    if((x -= c) < 0)
        break;
}

switch(iteration)
{
case 1:
case 2:
//...
default:
}

0
投票

当我结合你的答案,那么这应该在这里工作为好,对不对?

double number;
Random x = new Random();
number = x.NextDouble();

double RATIO_CHANCE_A = 0.10;
double RATIO_CHANCE_B = 0.30;
double RATIO_CHANCE_C = 0.60;
double RATIO_TOTAL = RATIO_CHANCE_A + RATIO_CHANCE_B + RATIO_CHANCE_C;


if ( number < RATIO_CHANCE_A ) // A -> 10%
{
do_something1();
}
else if ( number < RATIO_CHANCE_B + RATIO_CHANCE_A ) // B -> 30%
{
do_something2();
}
else if ( number < RATIO_TOTAL ) // C -> 60%
{
do_something3();
}
© www.soinside.com 2019 - 2024. All rights reserved.