且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

游戏设计/理论,哄抢跌落机会/繁殖速率

更新时间:2023-11-10 15:38:10

我第一次代表每个战利品类型作为一个简单的数字的概率。
纯数学概率常规表示为0到1范围内的浮点数,但为了提高效率,你可以在任何(足够大)的范围内使用整数(每个值是0-1值乘以最大的(这我打电话的 MaxProbability 的位置))。

I'd first represent the probability of each loot type as a simple number. A probability in pure mathematics is conventionally expressed as a floating point number in the range 0 to 1, but for efficiency, you can use integers in any (large enough) range (each value is the 0-1 value multiplied by the maximum (which I'm calling MaxProbability here)).

e.g. Bloodstone (1 in 100) is 1/100 = 0.01, or MaxProbability * (1/100).
     Copper (1 in 15) is 1/15 = 0.06667, or MaxProbability * (1/15).



我假设默认(空节点)是指没有其他人的可能性。
在这种情况下,最简单的方法是不定义它 - 你得到它,如果被选择没有他人的

I'm assuming that 'Default (Empty Node)' means the probability of none of the others. In this case, the simplest way is not to define it - you get it if none of the others are chosen.

如果默认被列入。所有这些概率的和是1(即100%)(或 MaxProbability 的,如果使用整数)。

If 'Default' was included, the sum of all these probabilities would be 1 (i.e. 100%) (or MaxProbability, if using integers).

1/10概率在你的榜样默认的实际上是一个矛盾,因为总所有这些概率不是1(这是0.38247619 - 就像我上面的例子来计算概率的总和)。

The 1/10 probability of 'Default' in your example is actually a contradiction because the total of all those probabilities is not 1 (it's 0.38247619 - the sum of the probability as calculated in my examples above).

然后,你会选择一个随机数范围为0到1(或MaxProbability如果使用的整数),并将选定的战利品类型是的第一个的列表中其中一个,这样的概率总和它和以前的不同(累积概率)是的的随机数。

Then you would choose a random number in the range 0 to 1 (or MaxProbability if using integers), and the chosen loot type is the first one in the list such that the sum of the probabilities of it and all previous ones ("cumulative probability") is greater than the random number.

例如

MaxProbability = 1000   (I'm using this to make it easy to read).
     (For accurate probabilities, you could use 0x7FFFFFFF).

Type                 Probability  Cumulative
----                 -----------  ----------
Bloodstone             10            10              (0..9 yield Bloodstone)
Copper                 67            77    (10+67)   (10..76 yield Copper)
Emeraldite             29           105    (77+29)
Gold                   20           125    etc.
Heronite               17           142
Platinum               17           159
Shadownite             13           172
Silver                 29           200
Soranite                1           201
Umbrarite               1           202
Cobalt                 13           216
Iron                   67           282

Default (Empty Node) 7175          1000   (anything else)

例如如果该范围内的随机数0至999(含)为184(或范围172至199任何东西),你会选择银(与累积概率大于这个是第一个)。

e.g. If your random number in the range 0 to 999 (inclusive) was 184 (or anything in the range 172 to 199), you would choose "Silver" (the first one with cumulative probability greater than this).

您可以容纳在通过一个数组和循环的累积概率,直到你找到比随机数越高,或者到达终点。

You could hold the cumulative probabilities in an array and loop through it until you find one higher than the random number, or reach the end.

列表的顺序并不重要。
你选择一个随机数,每个实例只有一次。

The order of the list does not matter. You chose a random number only once per instance.

包括默认(空节点)列表中的意思是最后的累积概率永远是 MaxProbability 的,而且搜索它永远不会晃过结束循环。 (可替代地,默认可以被省略,并且如果循环到达列表末尾选择它。)

Including 'Default (Empty Node)' in the list means that the last cumulative probability will always be MaxProbability and the loop that searches it would never go past the end. (Alternatively, 'Default' can be omitted, and you choose it if the loop reaches the end of the list.)

需要注意的是选择为每一个中的随机数转,如: 1/10机会血石的,那么,如果没有血石一个1/15机会铜,偏斜概率朝向较早的项目:
铜的实际概率将是(1/15)*(1 - (1/10)) - 10%小于1/15

Note that choosing a random number for each one in turn, e.g. a 1/10 chance of 'Bloodstone', then a 1/15 chance of Copper if not Bloodstone, skews the probabilities towards the earlier items: The actual probability of Copper would be (1/15) * (1 - (1/10)) - 10% less than 1/15.

下面的代码将做到这一点(实际选择是5声明 - 该方法的选择的)

Here's code to do it (the actual choosing is 5 statements - in the method Choose ).

using System;

namespace ConsoleApplication1
{
    class LootChooser
    {
        /// <summary>
        /// Choose a random loot type.
        /// </summary>
        public LootType Choose()
        {
            LootType lootType = 0;         // start at first one
            int randomValue = _rnd.Next(MaxProbability);
            while (_lootProbabilites[(int)lootType] <= randomValue)
            {
                lootType++;         // next loot type
            }
            return lootType;
        }

        /// <summary>
        /// The loot types.
        /// </summary>
        public enum LootType
        {
            Bloodstone, Copper, Emeraldite, Gold, Heronite, Platinum,
            Shadownite, Silver, Soranite, Umbrarite, Cobalt, Iron, Default
        };

        /// <summary>
        /// Cumulative probabilities - each entry corresponds to the member of LootType in the corresponding position.
        /// </summary>
        protected int[] _lootProbabilites = new int[]
        {
            10, 77, 105, 125, 142, 159, 172, 200, 201, 202, 216, 282,  // (from the table in the answer - I used a spreadsheet to generate these)
            MaxProbability
        };

        /// <summary>
        /// The range of the probability values (dividing a value in _lootProbabilites by this would give a probability in the range 0..1).
        /// </summary>
        protected const int MaxProbability = 1000;

        protected Random _rnd = new Random((int)(DateTime.Now.Ticks & 0x7FFFFFFF));    


        /// <summary>
        /// Simple 'main' to demonstrate.
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            var chooser = new LootChooser();
            for(int n=0; n < 100; n++)
                Console.Out.WriteLine(chooser.Choose());
        }           
    }
}