6

私はC#を初めて使用します。

私がやろうとしていること

ここで運が左右するゲームシステムを作成しようとしています。

基本的にこれはそれがどのようであるかです:

私の質問:私がやろうとしていることを達成するためにどのようにすればよいですか?

4

5 に答える 5

5

150/208あなたのサンプルコードには難しいバグがあります:あなたはとを書きました190/209。これは整数の除算であり、どちらも結果はゼロになります。次のように記述しておく必要があります。150.0/208そして190.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");

アイデアは、すべてのアイテムを次々にゆるい列に並べますが、それらをグループに保持するというものです。したがって、最初は第1の種類のミリオンが3つあり、次に第2のタイプのミリオンと半分があります。合計6820000個のアイテムが並んでいます。ここで、1から6820000(または0から6819999)の数値をランダムに選択し、それをLINEの要素のNUMBERとして使用します。

アイテムは正しい統計分布と一致しているため、ランダム化1-6820000がFLATの場合、結果の「宝くじ」は希望どおりに分布します。

説明するために残された唯一のトリックは、どのアイテムが選ばれたかを推測する方法です。これが、アイテムをグループにまとめた理由です。3000000アイテムの最初の部分は最初のタイプであるため、数が3000000未満の場合は、最初のタイプにヒットします。それよりも大きいが、次の1500000よりも小さい(4500000よりも小さい)場合は、2番目のタイプがヒットします。

于 2012-08-13T23:42:41.330 に答える
1

他の人が言っているように、あなたのコードには整数除算のバグがあります。

いずれにせよ、あなたは見たいと思うでしょう:逆変換サンプリング。

基本的に、それはあなたが均一な乱数(ほとんどのPRNGがあなたに与えるもの)を取り、それを任意の分布からのランダムサンプルに変換することを可能にします。これを行うには、ターゲット分布のCDFを使用する必要があります。

参考資料と役立つページ:

[ CiteHistoryレコード]

編集済み:私は実際には、多項分布ではなく、カテゴリ分布を意味していました。これらの2つの分布は(特に私の分野では)しばしば混同されますが、違いは重要です。2つの分布は、多項分布がn = 1でパラメーター化されている場合(つまり、1回の試行)にのみ同等です。

于 2012-08-13T23:57:30.073 に答える
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クラスは、名前と値のプレースホルダーにすぎません。

長く見えますが、いくつかの利点があります。

  • 値が変更されると、合計が自動的に計算されます。
  • アイテムを追加するときは、1行だけ変更する必要があります。
于 2012-08-13T23:47:11.577 に答える
0

ゼロが除算されないようにするには、1つの除数をdoubleにする必要があります。確率を計算するには、それらを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));

ランダムインスタンスを再利用することに注意してください。ループ内で作成する場合、「ランダムな値は、同じ時間にシードされるため、常に同じになります。

于 2012-08-13T23:57:30.290 に答える
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;
}
于 2012-08-14T00:19:10.250 に答える