Нахождение суммы и добавление шкалы вероятностей - PullRequest
2 голосов
/ 19 июня 2019

Я работаю над заданием, в котором мне нужно создать полнофункциональную программу Yahtzee. Теперь я выполнил начальную задачу, и у меня есть полностью работающее приложение Yahtzee, так что я могу бросать кости, хранить значения и т. Д. Но проблема, с которой я сталкиваюсь сейчас, заключается в том, что мне нужно добавить 2 специальных матрицы в микс, одна из матриц должна иметь более высокую вероятность вывода меньших чисел, в то время как другая должна иметь более высокую вероятность вывода больших чисел, Также мне нужно предоставить пользователю возможность настроить вероятность этих штампов в окне консоли.

Так что в основном я искал в интернете, и мне казалось, что если я жестко закодировал его с помощью массива, где я в основном помещаю более низкие числа, чем большие, это работает, но это очень грязно, а также не • устраняет проблему, а также делает задачу предоставления пользователю возможности корректировать вероятность очень глупо.

Давно я не пользовался сайтом, извиняюсь, если он немного небрежный.

class Dice
{
    public static readonly Random rng = new Random();

        public int NumberOfDice { get; private set; }

        public Dice()
        {
            NumberOfDice = rng.Next(1, 7);
        }

        public void Reroll()
        {
            NumberOfDice = rng.Next(1, 7);
        }
    }

    public bool FirstRound { get; private set; } = true;

    public readonly Dice[] Dices =
    {
        new Dice(),
        new Dice(),
        new Dice(),
        new Dice(),
        new Dice(),

    public void KeepDices(int[] toReroll)
    {
        for (int i = 0; i < Dices.Length; i++)
        {
            bool numFound = false;

            foreach (int roll in toReroll)
            {
                if (Dices[i].NumberOfDice == roll)
                {
                    numFound = true;
                }
            }

            if (numFound)
            {
                continue;
            }
            else
            {
                Dices[i].Reroll();
            }
        }

        ShowDices();
    }

    public void ShowDices()
    {
        Console.WriteLine();

        foreach (Dice dice in Dices)
        {
            Console.Write("[{0}] ", dice.NumberOfDice);
            FirstRound = false;
        }

        Console.WriteLine();
        Console.WriteLine();
    }

    public void RerollAll()
    {
        foreach (Dice dice in Dices)
        {
            dice.Reroll();
        }

        ShowDices();
    }
}

Как я уже сказал, программа работает нормально, она работает, но просто нужно каким-то образом добавить способ привязать две кубики к вероятности.

Ответы [ 4 ]

3 голосов
/ 19 июня 2019

Недавно я написал серию из 40 статей о том, как более элегантно встроить случайность в программы на C #.Ваша проблема описана в части 9:

https://ericlippert.com/2019/02/28/fixing-random-part-9/

Вкратце: создайте неоднородный взвешенный объект распределения для представления распределения.Вы можете эффективно реализовать его с помощью метода псевдонима .Затем вы сэмплируете из этого дистрибутива, чтобы бросить свой кубик.

Затем вы можете создать игровой дистрибутив, суммируя результаты различных распределений кубиков и сэмплируя из него.

Я предлагаю вам прочитать всю серию;Вы многому научитесь из этого.Он начинается здесь:

https://ericlippert.com/2019/01/31/fixing-random-part-1/

Исходный код для реализации метода псевдонима можно найти здесь:

https://github.com/ericlippert/probability/tree/episode09

1 голос
/ 19 июня 2019

Вы можете создать массив вероятностей для каждой грани кости.

var loadedDice = new double[] { 0.1, 0.12, 0.18, 0.2, 0.21, 0.19 };

Теперь вы генерируете случайное число в диапазоне от 0,0 до 1,0 и вычисляете промежуточную сумму этих вероятностей, пока сумма не станет большеили равно случайному числу.

// Play the dice
double p = rng.NextDouble() * loadedDice.Sum();

double sum = 0.0;
for (int i = 0; i < 6; i++) {
    sum += loadedDice[i];
    if (sum >= p) {
        Console.Write($"The number is {i + 1}");
        break;
    }
}

Мы добавляем один, потому что индексы начинаются с 0.


Пример:

x s вэто изображение представляет собой бегущую сумму.Расстояния между ними соответствуют вероятностям в массиве.Если, скажем, мы получим случайное число 0,27239827 (p на изображении), то промежуточная сумма станет больше, чем p для индекса = 2. Мы бросили число 3.

     x     x p      x         x          x        x
+----+----+----+----+----+----+----+----+----+----+
0   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9  1.0
0 голосов
/ 19 июня 2019

Я думаю, что вы ищете генератор взвешенных случайных чисел.

Так что я думаю, что вы должны быть в состоянии принять это решение для ваших нужд.

Во-первых, весовой классопределить свой вес.Это было бы то, что вы использовали бы для своих сторон кости.

public class WeightUnit
{
    public string Name = string.Empty;
    public int Weight = 0;

    public WeightUnit(string n, int w)
    {
        this.Name = n;
        this.Weight = w;
    }
}

Тогда этот метод вернет взвешенное случайное число:

public static WeightUnit GetRandom(List<WeightUnit> weights)
{
    var totalWeight = weights.Sum(x => x.Weight);
    int randomNumber = _rnd.Next(0, totalWeight);

    WeightUnit selected = null;
    foreach (WeightUnit unit in weights)
    {
        if (randomNumber < unit.Weight)
        {
            selected = unit;
            break;
        }

        randomNumber = randomNumber - unit.Weight;
    }

    return selected;
}

А вот основная программа для проверки:

private static Random _rnd = new Random();

static void Main()
{
    List<WeightUnit> weights = new List<WeightUnit>
    {
        new WeightUnit("1", 20),
        new WeightUnit("2", 20),
        new WeightUnit("3", 20),
        new WeightUnit("4", 10),
        new WeightUnit("5", 10),
        new WeightUnit("6", 10)
    };

    Dictionary<string, int> result = new Dictionary<string, int>();

    WeightUnit selected = null;

    for (int i = 0; i < 1000; i++)
    {
        selected = GetRandom(weights);
        if (selected != null)
        {
            if (result.ContainsKey(selected.Name))
            {
                result[selected.Name] = result[selected.Name] + 1;
            }
            else
            {
                result.Add(selected.Name, 1);
            }
        }
    }


    Console.WriteLine("1\t\t" + result["1"]);
    Console.WriteLine("2\t\t" + result["2"]);
    Console.WriteLine("3\t\t" + result["3"]);
    Console.WriteLine("4\t\t" + result["4"]);
    Console.WriteLine("5\t\t" + result["5"]);
    Console.WriteLine("6\t\t" + result["6"]);
    Console.ReadLine();
}

Как видите, я назначил удвоенное значение веса для чисел 1,2 и 3, и более 1000 итераций выбирается в два раза больше по сравнению с 4, 5 и5. Поэтому, когда вы составляете свой список, вы можете назначить нужный вам вес.

enter image description here

0 голосов
/ 19 июня 2019

Один из способов сделать это - добавить свойство с именем ChanceOfRollingSmallNumber в ваш класс Dice:

public int ChanceOfRollingSmallNumber { get; set; } = 50;

При броске костей сгенерируйте случайное число от 0 до 99. Если числоменьше, чем ChanceOfRollingSmallNumber, затем сгенерируйте небольшое случайное число, в противном случае сгенерируйте большое случайное число:

if (rng.Next(100) < ChanceOfRollingSmallNumber) {
    NumberOfDice = rng.Next(1, 4);
} else {
    NumberOfDice = rng.Next(4, 7);
}

Для игры в кости с высокой вероятностью броска небольшого числа просто установите ChanceOfRollingSmallNumberк чему-то большомуДля кости, у которой, вероятно, большое число бросков, просто установите его на что-то маленькое.Для честных кубиков просто установите его на 50.

Если вы хотите еще более точную настройку, вы можете сделать ChanceOfRollingSmallNumber диапазон от 0 до 1000 или что-то еще больше.

...