Как сгенерировать на одно случайное число больше, чем на другие случайные числа в массиве?

#c# #unity3d

#c# #unity3d

Вопрос:

У меня есть список чисел, например: {1,2,3,4,5,6} .

Я хочу сгенерировать эти числа случайным образом, что я и сделал следующим образом:

 void Update(){
    float ran = Random.Range(1,6);
    print(ran);
}
  

Как мне сгенерировать или напечатать на 3 больше, чем другие числа?

Комментарии:

1. Я не понимаю, что вы пытаетесь сделать. Пожалуйста, объясните подробнее, каким будет ожидаемый результат.

2. Пример: random.range выведет 3,1,5,2,4,6,1,3,2,5,2,5,6 Теперь я хочу напечатать (3) больше, чем другие числа, такие как 2,3,3,4,3,3,3,3,3,4,3,3,5,3,3

3. () после имени метода не требуется в Unity3D, как Update() ?

4. Ах, вы только что добавили их!

5. Как часто вы хотите 3 печатать относительно других чисел?

Ответ №1:

Если вы хотите искаженное распределение, вы можете, скажем, сопоставить сгенерированные значения с желаемым распределением

 // all 1..6 are equal with exception of 3 which appears more frequently 
// 1..2, 4..6 - 10% each (1 occurence  per 10 items)
// 3          - 50%      (5 occurences per 10 items)
private static int[] map = new int[1, 2, 3, 4, 5, 6, 3, 3, 3, 3];

...

void Update{
  float ran = map[Random.Range(map.Length)];
  print(ran);
}
  

Комментарии:

1. @Dmitry Bychenko Но в вашем ответе используется коллекция like {1, 2, 3, 4, 5, 6, 3, 3, 3, 3} , а в вопросе приведен пример like {1,2,3,4,5,6} . При этом выводится число «3» просто потому, что их больше. Я написал 2 решения, которые принимают список с {1,2,3,4,5,6} формой.

2. @Jorge Santos: Есть много способов исказить начальное распределение, мой самый простой и, я надеюсь, его легко поддерживать; конечно, есть некоторые недостатки кода, например, трудно обеспечить 3 точное 51.253496% время появления. Но, как я вижу из вопроса — «сгенерировать на одно случайное число больше, чем на другое» — это не так.

3. @Dmitry Bychenko Спасибо за ваше объяснение, но я все еще не понимаю, насколько это соответствует требованиям. Если вы хотите взять красный шар из пакета с синими и красными шарами, ваше решение просто вставит больше красных шаров (и, конечно, это сработает). Если ОП с этим согласен, то мне больше нечего сказать, может быть, я что-то упускаю.

4. @Jorge Santos: требование «Как мне сгенерировать или напечатать на 3 больше, чем другие числа» я прочитал как «как исказить распределение». Ответ — могу я процитировать вас — «вставить больше красных шариков» ( 3 ‘s). В общем случае (если 3 должно появиться с произвольной заданной вероятностью) мое решение работает плохо ( map может потребоваться огромный массив), но поскольку вероятности не указаны просто «больше, чем другие», я подумал, что простейшее отображение является достаточно хорошим решением.

Ответ №2:

Установите значение threeMultiplier равным 1 для нормального распределения, 2 для двух раз большего количества 3, 3 для трех раз большего количества 3 и так далее.

 void Update() {
    int threeMultiplier = 2; // Twice as much 3's
    int maxNumber = 6;
    int num = Random.Range(1, threeMultiplier * maxNumber);
    if (num > maxNumber) num = 3;
    print(num); 
}
  

Ответ №3:

Одним из решений для «взлома игральных костей» может быть следующее: float ran = Random .Диапазон (1,10);

«преобразовать ran в int»

 switch (ran) 
 case 1: 
   return 1
 case 2: 
   return 2
 case 3:
   return 3
 case 4:
   return 4
 case 5: 
   return 5
 case 6:
   return 6
 default:
   return 3
  

таким образом, у вас будет 50% шансов для 3 и 10% друг для друга, чтобы уменьшить количество 3-х, измените 10 на меньшее значение ^^

Ответ №4:

Вот какое-то решение, использующее теорию вероятностей, но оно перегружено. В нем также могут быть незначительные синтаксические ошибки, потому что сейчас я далек от Visual Studio (

 var data = new float[] {1, 2, 3, 4, 5, 6};
var indexToWeight = (index) => {
  if (index == 3) return 2;
  return 1; 
};
var total = data.Select((value, index) => indexToWeight(index)).Sum(); 
var weightedData = data.Select((value, index) => Tuple.Create(value, indexToWeight(index)/(float)sum)).ToList();
var boundedData = new List<Tuple<float, float>>(weightedData.Count);
float bound = 0.0f;
for (int i = 0; i < weightedData.Count; i  ) {
  boundedData.Add(Tuple.Create(weightedData[i].Item1, bound));
  bound  = weightedData[i].Item2;
}

var weightedToValue = (List<Tuple<float, float>> wv, float p) => {
  var pair = wv.FirstOrDefault(item => item.Item2 > p);
  if (pair != null) return pair.Item1;
  return vw.Last().Item1; 
}; 
Random random;
var randomizedData = Enumerable.Range(1, data.Count).Select(index => weightedtoValue(weightedData, random.NextDouble())).ToArray();   
  

Комментарии:

1. Хорошо, большое спасибо 🙂

Ответ №5:

Проверьте этот пример, который я сделал.Чистая скрипка. В этом коде у вас есть 2 возможности. Я уверен, что это решит вашу проблему, и это довольно простое решение. Конечно, в Unity вы можете использовать Random .Диапазон… измените имена некоторых переменных yada yada.

1 — Вы можете печатать столько раз, сколько элементов в вашем списке, поэтому список с ‘n’ элементами всегда будет выводить ‘n’ чисел в качестве выходных данных.

2- Вы можете напечатать любое количество, которое хотите, если вы измените переменную timesToPrint

Код будет печатать на goldenNumber основе chanceToPrintGoldenNumber , иначе он печатает случайный элемент в списке (который случайно может быть золотым числом).

Пример ссылки ЗДЕСЬ!

Код:

 public static void Main()
{
    Random rnd = new Random();
    var li = new List<int> {1,2,5,3,6,8};
    var timesToPrint = 10;

    var goldenNumber = 3;

     // this is actually 55% chance, because we generate a number form 0 to 100 and if it is  > than 45 we print it... so 55% chance
    var chanceToPrintGoldenNumber = 45;


    // Print as many times as there are numbers on the list

    Console.WriteLine("Printing as many times as there are elements on the list");

    foreach(var number in li)
    {       
        var goldenNumberChance = rnd.Next(0,100);

        if (goldenNumberChance > chanceToPrintGoldenNumber) // 55% chance to print goldenNumber
        {
            Console.WriteLine(goldenNumber);            
        }
        else
        {           
            var i = rnd.Next(0,li.Count);
            Console.WriteLine(li[i]);           
        }
    }

    Console.WriteLine("****************** END ***************************");

    // Print as many times as the value of your "timesToPrint".

    Console.WriteLine("Printing as many times as the value on timesToPrint ");

    for(var i=0; i< timesToPrint; i  )
    {
        var goldenNumberChance = rnd.Next(0,100);

        if (goldenNumberChance > chanceToPrintGoldenNumber) // 55% chance to print goldenNumber
        {
            Console.WriteLine(goldenNumber);            
        }
        else
        {           
            var n = rnd.Next(0,li.Count);
            Console.WriteLine(li[n]);           
        }

    }

}
  

Ответ №6:

Я бы сделал что-то подобное для взвешенного распределения:

 public class RandomGenerator
{
    Dictionary<Tuple<double, double>, Tuple<int, int>> probability;
    Random random;

    public RandomGenerator(Dictionary<double, Tuple<int, int>> weights)
    {
        random = new Random();

        Dictionary<double, Tuple<int, int>> percent = weights.Select(x => new { Key = x.Key / weights.Keys.Sum(), Value = x.Value }).ToDictionary(t => t.Key, t => t.Value);
        probability = new Dictionary<Tuple<double, double>, Tuple<int, int>>();
        double last = 0;
        foreach (var item in percent.OrderBy(x => x.Key).Select(x => new { Key = x.Key, Value = x.Value }))
        {
            probability.Add(new Tuple<double, double>(last, last   item.Key), item.Value);
            last  = item.Key;
        }
    }

    public double GetRandomNumber()
    {
        double w = random.NextDouble();

        var range = probability.Where(x => w >= x.Key.Item1 amp;amp; w <= x.Key.Item2).First().Value;

        return random.Next(range.Item1, range.Item2);
    }
}
  

И вы могли бы использовать это так:

 Dictionary<double, Tuple<int, int>> weights = new Dictionary<double, Tuple<int, int>>();
weights.Add(80, new Tuple<int, int>(1, 100));
weights.Add(20, new Tuple<int, int>(3,3));

var randgen = new RandomGenerator(weights);
var number = randgen.GetRandomNumber();