C#机会游戏

时间:2012-08-13 23:29:11

标签: c# probability

我是C#的新手。

我想做什么

我想在这里创建一个机会游戏系统。

基本上就是这样:

我的问题:如何完成我想要做的事情?

5 个答案:

答案 0 :(得分:5)

您的示例代码有一个难题:您已撰写150/208190/209。这是一个整数除法,都会导致。您应该编写:150.0/208190.0/209来指示编译器将它们分为double而不是整数。

编辑:
假设系统的RNG是平坦的,您的表格如下:

[item]    [amount]
0        3 000 000
25       1 500 000
50       2 000 000
75       300 000
100      10 000
150      10 000    (no typo)
  sum  = 6820000

然后你的随机数发生器看起来像:

int randomItemNumber = Random.Next(6820000); // 0..6819999
if(randomItemNumber < 3000000)
    Console.WriteLine("Aah, you've won the Item type #0\n");
else if(randomItemNumber < 3000000+1500000)
    Console.WriteLine("Aah, you've won the Item type #1\n");
else if(randomItemNumber < 3000000+1500000+2000000)
    Console.WriteLine("Aah, you've won the Item type #2\n");
else if(randomItemNumber < 3000000+1500000+2000000+300000)
    Console.WriteLine("Aah, you've won the Item type #3\n");
else if(randomItemNumber < 3000000+1500000+2000000+300000+10000)
    Console.WriteLine("Aah, you've won the Item type #4\n");
else if(randomItemNumber < 3000000+1500000+2000000+300000+10000+10000)
    Console.WriteLine("Aah, you've won the Item type #5\n");
else
    Console.WriteLine("Oops, somehow you won nothing, the code is broken!\n");

这个想法是你把所有物品一个接一个地放在一条宽松的线上,但是你把它们放在他们的小组中。所以,一开始有第一种类型的三百万,然后是第二种类型的数百万,依此类推。该行共有6820000项。现在,您随机选择1到6820000(或从0到6819999)的数字,并将其用作LINE中元素的NUMBER。

由于项目存在于具有正确统计分布的行中,如果随机化1-6820000是FLAT,那么得到的“抽奖”将具有与您想要的完全分布。

唯一需要解释的技巧是如何猜测挑选的物品。这就是我们将这些项目分组的原因。 3000000项的第一部分是第一部分,所以如果数字小于3000000那么我们就打第一类。如果超过这个数,但低于下一个1500000(低于450000),则第二个类型被击中..依此类推。

答案 1 :(得分:1)

正如其他人所说,你的代码有一个整数除法错误。

在任何情况下,您都需要查看:逆变换采样。

基本上,它允许您采用统一的随机数(大多数PRNG提供给您)并将其转换为来自任何分布的随机样本。为此,您需要使用目标分发的CDF。

参考文献&amp;有用的页面:

[CiteHistory Record]

编辑: 我实际上是指分类分布,而不是多项分布。这两种分布通常是混淆的(特别是在我的领域),但差异很重要。只有当多项分布参数化为n = 1(即一次试验)时,这两个分布才是等价的。

答案 2 :(得分:0)

我在我的应用中做了类似的事情,并将其转换为您的问题如下: 在伪代码中:

  • 总结所有值(以获得总数)
  • 获取0和总和之间的随机值
  • 遍历所有项目,汇总所有值,直到该项目
  • 当到达随机数时,该项目是属于该值的项目。

类Items看起来如下(删除了一些不重要的行,并添加了//

的备注
public class Items : List<Item>
{
    public Items() 
    {
        Add(new Item( 0, 3000000)); 
        Add(new Item(25, 1500000)); 
        Add(new Item(50, 2000000));
        // etc
    }

    /// <summary>
    /// Returns a random item based on value.
    /// </summary>
    /// <returns></returns>
    public Item GetRandomItem()
    {
        var sum = this.Sum(item => item.Value);
        var randomValue = new Random().Next(sum);

        // Iterate through itemsuntil found.
        var found = false;
        var itemIndex = 0;
        var visitedValue = 0;
        while (!found)
        {
            var item = this[itemIndex];
            if ((visitedValue + item.Value ) > randomValue)
            {
                found = true;
            }
            else
            {
                itemIndex++;
                visitedValue += item.value;                
            }
        }

        return this[itemIndex];        
    }

Item类只不过是Name和Value的占位符。

看起来很长,但它有一些好处:

  • 当值更改时,将自动计算总和。
  • 添加项目时,只需要更改一行。

答案 3 :(得分:0)

一个除数必须是双重才能防止零除。要计算您需要将它们累积到100%(或1)的概率:

//     Element     - Probability      - Cumulative Probability
//     Item100     10000 / 6820000       0.001466275659824
//     Item75      300000 / 6820000      0.0439882697947214 + 0.001466275659824
//     Item50      2000000 / 6820000     0.2932551319648094 + 0.0454545454545454
//     Item25      1500000 / 6820000     0.219941348973607  + 0.3387096774193548
const double Item100 = 0.001466275659824;
const double Item75 = 0.0454545454545454;
const double Item50 = 0.3387096774193548;
const double Item25 = 0.5586510263929618;

int getRandomItem(Random rnd)
{
    double value = rnd.NextDouble();
    if (value <= Item100)
    {
        // use one of both possible items (100 or 150)
        int which = rnd.Next(0, 2);
        return which == 0 ? 100 : 150;
    }
    else if (value <= Item75)
        return 75;
    else if (value <= Item50)
        return 50;
    else if (value <= Item25)
        return 25;
    else
        return 0;
}

你将如何使用它:

var rnd = new Random();
var items = new List<int>();
for (int i = 0; i < 100; i++)
    items.Add(getRandomItem(rnd));
Console.Write(string.Join(Environment.NewLine, items));

请注意,我重用了随机实例。如果我在循环中创建它,“随机值将会变得相同,因为它将在同一时间播种。

答案 4 :(得分:0)

这样的事应该适合你。也许不是世界上最好的例子,但它应该足够了:

class Item
{
    public string Name { get ; private set ; }
    public int    Amount { get ; private set ; }

    public Item( string name , int amount )
    {
        if ( string.IsNullOrWhiteSpace(name) ) throw new ArgumentException("name") ;
        if ( amount < 0 ) throw new ArgumentException("amount") ;

        this.Name = name ;
        this.Amount = amount ;

        return ;
    }
}
static void Main( string[] args )
{
    Random rng   = new Random() ;
    Item[] items = { new Item( "item--0"  , 3000000 ) ,
                     new Item( "item-25"  , 1500000 ) ,
                     new Item( "item-50"  , 2000000 ) ,
                     new Item( "item-75"  ,  300000 ) ,
                     new Item( "item-100" ,   10000 ) ,
                     new Item( "item-150" ,   10000 ) ,
                    } ;
    int    total = items.Sum( x => x.Amount ) ;

    for ( int i = 0 ; i < 100 ; ++i )
    {
        int  r = rng.Next(0, total ) ; // get a random integer x such that 0 <= x < total
        int  n = 0 ;
        Item selected = null ;
        int  lo = 0 ;
        int  hi = 0 ;
        for ( int j = 0 ; j < items.Length ; ++j )
        {
            lo = n ;
            hi = n + items[j].Amount ;
            n  = hi ;

            if ( r < n )
            {
                selected = items[j] ;
                break ;
            }

        }
        Console.WriteLine( "iteration {0}. r is {1} <= {2} < {3}. Selected item is {4}" ,
            i ,
            lo ,
            r ,
            hi ,
            selected.Name
            ) ;


    }

    return;
}