Алгоритм выбора колеса рулетки

Кто-нибудь может предоставить какой-нибудь псевдокод для функции выбора рулетки? Как бы это реализовать: я действительно не понимаю, как читать эту математическую запись. Я хочу, чтобы для этого был общий алгоритм.

Отредактировал теги. Кто-то удалил "генетический" тег из первой редакции этого вопроса, что сделало менее ясным, о чем спрашивали.

Dan Dyer 26.11.2008 19:25

беззнаковое целое число = :: rand ()% 37;

Viktor Sehr 07.05.2010 13:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
22
2
84 881
12

Ответы 12

Для этого есть 2 шага: Сначала создайте массив со всеми значениями на колесе. Это может быть двухмерный массив с цветом и числом, или вы можете добавить 100 к красным числам.

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

Большинство языков имеют встроенные функции случайных чисел. В VB и VBScript функция - RND(). В Javascript это Math.random()

Получите значение из этой позиции в массиве, и у вас будет случайный номер рулетки.

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

Псевдокод генератора случайных чисел

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

Используйте цифры случайного числа, чтобы создать случайные числа от 1 до 38 (или 37 европейских) для рулетки.

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

Karl 27.11.2008 03:22

Что ж, для колеса американской рулетки вам нужно будет сгенерировать случайное целое число от 1 до 38. Есть 36 чисел, 0 и 00.

Тем не менее, одна из важных вещей, которые следует учитывать, заключается в том, что в американской рулетке можно делать множество различных ставок. Одиночная ставка может покрывать 1, 2, 3, 4, 5, 6, две разные 12 или 18. Вы можете создать список списков, в котором каждое число имеет дополнительные флажки, чтобы упростить это, или сделать все это в программе. .

Если бы я реализовал его на Python, я бы просто создал кортеж от 0, 00 и от 1 до 36 и использовал random.choice () для каждого вращения.

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

Вот код Java, реализующий выбор колеса рулетки.

Предположим, у вас есть 10 элементов на выбор, и вы выбираете, генерируя случайное число от 0 до 1. Вы делите диапазон от 0 до 1 на десять неперекрывающихся сегментов, каждый из которых пропорционален пригодности одного из десяти элементов. Например, это может выглядеть так:

0 - 0.3 is item 1
0.3 - 0.4 is item 2
0.4 - 0.5 is item 3
0.5 - 0.57 is item 4
0.57 - 0.63 is item 5
0.63 - 0.68 is item 6
0.68 - 0.8 is item 7
0.8 - 0.85 is item 8
0.85 - 0.98 is item 9
0.98 - 1 is item 10

Это ваше колесо рулетки. Ваше случайное число от 0 до 1 - это ваше вращение. Если случайное число 0,46, то выбран элемент 3. Если это 0,92, то это элемент 9.

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

Parrish Husband 19.04.2014 06:14

Никто не говорит о замене выделенного элемента, чтобы выбранный элемент больше не выделялся. Любое решение для этого?

Anik Islam Abhi 24.03.2016 20:20

@AnikIslamAbhi, насколько я понимаю, выбор колеса рулетки предполагает, что каждый элемент можно выбрать более одного раза. Если вы рандомизируете N раз (где N - количество популяции), вы бы взяли точно такую ​​же популяцию после отбора.

Sebastian Budka 11.05.2017 15:43

Сначала сгенерируйте массив назначенных вами процентов, скажем, p[1..n]. и предположим, что общая сумма является суммой всех процентов.

Затем получите случайное число от 1 до всего, скажем, r.

Теперь алгоритм на lua:

local  c  =  0
for i = 1,n do
    c = c + p[i]
    if r <= c then
        return i
    end
end

Это предполагает некоторый класс «Классификатор», который имеет только условие String, сообщение String и двойную силу. Просто следуйте логике.

-- Павел

public static List<Classifier> rouletteSelection(int classifiers) {
    List<Classifier> classifierList = new LinkedList<Classifier>();
    double strengthSum = 0.0;
    double probabilitySum = 0.0;

    // add up the strengths of the map
    Set<String> keySet = ClassifierMap.CLASSIFIER_MAP.keySet();
    for (String key : keySet) {
        /* used for debug to make sure wheel is working.
        if (strengthSum == 0.0) {
        ClassifierMap.CLASSIFIER_MAP.get(key).setStrength(8000.0);
        }
         */
        Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
        double strength = classifier.getStrength();
        strengthSum = strengthSum + strength;
    }
    System.out.println("strengthSum: " + strengthSum);

    // compute the total probability. this will be 1.00 or close to it.
    for (String key : keySet) {
        Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
        double probability = (classifier.getStrength() / strengthSum);
        probabilitySum = probabilitySum + probability;
    }
    System.out.println("probabilitySum: " + probabilitySum);

    while (classifierList.size() < classifiers) {
        boolean winnerFound = false;
        double rouletteRandom = random.nextDouble();
        double rouletteSum = 0.0;

        for (String key : keySet) {
            Classifier classifier = ClassifierMap.CLASSIFIER_MAP.get(key);
            double probability = (classifier.getStrength() / strengthSum);
            rouletteSum = rouletteSum + probability;
            if (rouletteSum > rouletteRandom && (winnerFound == false)) {
                System.out.println("Winner found: " + probability);
                classifierList.add(classifier);
                winnerFound = true;
            }
        }
    }
    return classifierList;
}

Вот немного кода на Python:

def roulette_select(population, fitnesses, num):
    """ Roulette selection, implemented according to:
        <http://stackoverflow.com/questions/177271/roulette
        -selection-in-genetic-algorithms/177278#177278>
    """
    total_fitness = float(sum(fitnesses))
    rel_fitness = [f/total_fitness for f in fitnesses]
    # Generate probability intervals for each individual
    probs = [sum(rel_fitness[:i+1]) for i in range(len(rel_fitness))]
    # Draw new population
    new_population = []
    for n in xrange(num):
        r = rand()
        for (i, individual) in enumerate(population):
            if r <= probs[i]:
                new_population.append(individual)
                break
    return new_population

будет ли это работать, даже если некоторые из значений пригодности отрицательны?

mkuse 04.01.2013 11:04

Нет, не будет. Но вы должны задаться вопросом: поскольку приспособленность соответствует вероятности получения этой выборки, не существует такой вещи, как отрицательная вероятность получения выборки, поэтому какого поведения вы можете ожидать?

noio 05.01.2013 15:21

Я хочу сказать, что у меня есть фитнес-функция, которая дает отрицательные значения. Предположим, я решаю задачу, в которой пригодность является «ошибочной», т.е. отличие целевого значения от значения, полученного ГА. В этом случае фитнес-функция будет генерировать отрицательные значения. Как мне сформулировать это в виде колеса Routtle?

mkuse 06.01.2013 16:33

Как я уже сказал, вы должны подумать о том, что вы хотите делать с этими отрицательными значениями! Колесо рулетки не принимает значения фитнес в качестве входных данных, но (ненормализованное) вероятности. Вы должны найти способ превратить эти, возможно, отрицательные значения ошибок в вероятности. Вы делаете что-то странное, если у вас могут быть отрицательные значения ошибка, но, возможно, вы можете просто отрицать их (error = -error), тогда то, что я обычно делаю, - это fitness = 1/(1+error).

noio 08.01.2013 17:30

Выбор колеса рулетки не работает с отрицательными значениями пригодности. Попробуйте отбор турниров.

fangmobile 03.05.2015 08:29

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

Anik Islam Abhi 24.03.2016 20:18

Вы можете использовать такую ​​структуру данных:

Map<A, B> roulette_wheel_schema = new LinkedHashMap<A, B>()

где A - целое число, представляющее карман колеса рулетки, а B - индекс, который идентифицирует хромосому в популяции. Количество карманов пропорционально приспособленности каждой хромосомы:

количество карманов = (соответствие пригодности) · (коэффициент масштабирования)

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

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

Метод getRouletteWheel возвращает схему выбора на основе предыдущей структуры данных.

private Map<Integer, Integer> getRouletteWheel(
        ArrayList<Chromosome_fitnessProportionate> chromosomes,
        int precision) {

    /*
     * The number of pockets on the wheel
     * 
     * number of pockets in roulette_wheel_schema = probability ·
     * (10^precision)
     */
    Map<Integer, Integer> roulette_wheel_schema = new LinkedHashMap<Integer, Integer>();
    double fitness_proportionate = 0.0D;
    double pockets = 0.0D;
    int key_counter = -1;
    double scale_factor = Math
            .pow(new Double(10.0D), new Double(precision));
    for (int index_cromosome = 0; index_cromosome < chromosomes.size(); index_cromosome++){

        Chromosome_fitnessProportionate chromosome = chromosomes
                .get(index_cromosome);
        fitness_proportionate = chromosome.getFitness_proportionate();
        fitness_proportionate *= scale_factor;
        pockets = Math.rint(fitness_proportionate);
        System.out.println("... " + index_cromosome + " : " + pockets);

        for (int j = 0; j < pockets; j++) {
            roulette_wheel_schema.put(Integer.valueOf(++key_counter),
                    Integer.valueOf(index_cromosome));
        }
    }

    return roulette_wheel_schema;
}

Я хотел того же и поэтому создал этот автономный класс Roulette. Вы даете ему серию весов (в форме двойного массива), и он просто возвращает индекс из этого массива в соответствии с взвешенным случайным выбором.

Я создал класс, потому что вы можете значительно ускориться, выполнив накопительные дополнения только один раз через конструктор. Это код C#, но наслаждайтесь скоростью и простотой C!

class Roulette
{
    double[] c;
    double total;
    Random random;

    public Roulette(double[] n) {
        random = new Random();
        total = 0;
        c = new double[n.Length+1];
        c[0] = 0;
        // Create cumulative values for later:
        for (int i = 0; i < n.Length; i++) {
            c[i+1] = c[i] + n[i];
            total += n[i];
        }
    }

    public int spin() {
        double r = random.NextDouble() * total;     // Create a random number between 0 and 1 and times by the total we calculated earlier.
        //int j; for (j = 0; j < c.Length; j++) if (c[j] > r) break; return j-1; // Don't use this - it's slower than the binary search below.

        //// Binary search for efficiency. Objective is to find index of the number just above r:
        int a = 0;
        int b = c.Length - 1;
        while (b - a > 1) {
            int mid = (a + b) / 2;
            if (c[mid] > r) b = mid;
            else a = mid;
        }
        return a;
    }
}

Начальный вес зависит от вас. Может быть, это может быть пригодность каждого члена или значение, обратно пропорциональное положению члена в «50 лучших». Например: 1-е место = 1,0 взвешивания, 2-е место = 0,5, 3-е место = 0,333, 4-е место = 0,25 взвешивания и т. д.

Вот действительно быстрый способ сделать это с помощью выбора потока в Java. Он выбирает индексы массива, используя значения в качестве весов. Никаких кумулятивных весов не требуется из-за математические свойства.

static int selectRandomWeighted(double[] wts, Random rnd) {
    int selected = 0;
    double total = wts[0];

    for( int i = 1; i < wts.length; i++ ) {
        total += wts[i];            
        if ( rnd.nextDouble() <= (wts[i] / total)) selected = i;
    }

    return selected;        
}

Это можно было бы дополнительно улучшить, используя Суммирование Кахана или чтение двойников как итерацию, если массив был слишком большим для одновременной инициализации.

Это выглядит интересным решением. Я также дал ответ в тот же час, что и вы, несмотря на то, что вопрос был лет (возможно, вы видели мой пост). В любом случае, мне нравится ваш, потому что он такой короткий, но я думаю, что мой может быть более эффективным из-за эффективности O (log2 n) вместо вашего O (n).

Dan W 23.03.2013 22:29

Я думаю, что вы наткнулись на вопрос, заставив меня опубликовать свой ответ. Во всяком случае, ваша начальная совокупная сумма по-прежнему занимает O(n). Я думаю, что это определенно нижняя граница, несмотря ни на что :)

Andrew Mao 24.03.2013 00:42

Только впервые в конструкторе. В реальном мире вы будете делать много «вращений рулетки» (то есть искать много разных родительских пар). Здесь вступает в игру O (log2 n), поскольку после этого вызывается только метод spin ().

Dan W 24.03.2013 02:24

Это верно, если вы хотите многократно рисовать из одного и того же дистрибутива. Но я думаю, что на практике и по моему опыту такого не происходит; например, в генетических алгоритмах веса приспособленности всегда меняются. Кроме того, если вы собираетесь взять огромную выборку из такого распределения, вам вообще не нужно действительно рандомизировать, поскольку дробь сходится к нормализованным весам.

Andrew Mao 24.03.2013 03:04

Возможно, предоставлено для GA, как вы говорите. Для случая, когда мне это было нужно (имитация миллионов или миллиардов ставок для проверки риска / прибыли), мой код ответа O (log2 n) является улучшением. Я уверен, что будут и другие случаи.

Dan W 05.02.2016 22:08

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

Спасибо за ценную информацию.

Phantômaxx 22.11.2014 22:15

Я разработал код Java, похожий на код Дэна Дайера (упоминавшийся ранее). Однако мое колесо рулетки выбирает один элемент на основе вектора вероятности (входных данных) и возвращает индекс выбранного элемента. Сказав это, следующий код более подходит, если размер выборки является унитарным и если вы не предполагаете, как рассчитываются вероятности, и допускается нулевое значение вероятности. Код является самодостаточным и включает тест с 20 вращениями колеса (на запуск).

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Roulette-wheel Test version.
 * Features a probability vector input with possibly null probability values.
 * Appropriate for adaptive operator selection such as Probability Matching 
 * or Adaptive Pursuit, (Dynamic) Multi-armed Bandit.
 * @version October 2015.
 * @author Hakim Mitiche
 */
public class RouletteWheel {

/**
 * Selects an element probabilistically.  
 * @param wheelProbabilities elements probability vector.
 * @param rng random generator object
 * @return selected element index
 * @throws java.lang.Exception 
 */
public int select(List<Double> wheelProbabilities, Random rng) 
        throws Exception{

    double[] cumulativeProba = new double[wheelProbabilities.size()];
    cumulativeProba[0] = wheelProbabilities.get(0);
    for (int i = 1; i < wheelProbabilities.size(); i++)
    {
        double proba = wheelProbabilities.get(i);
        cumulativeProba[i] = cumulativeProba[i - 1] + proba;
    }
    int last = wheelProbabilities.size()-1;
     if (cumulativeProba[last] != 1.0)
     {
            throw new Exception("The probabilities does not sum up to one ("
                    + "sum = "+cumulativeProba[last]);
     }
    double r = rng.nextDouble();
    int selected = Arrays.binarySearch(cumulativeProba, r);
     if (selected < 0)
        {
            /* Convert negative insertion point to array index.
            to find the correct cumulative proba range index.
            */
            selected = Math.abs(selected + 1);
        }
     /* skip indexes of elements with Zero probability, 
        go backward to matching index*/  
    int i = selected; 
    while (wheelProbabilities.get(i) == 0.0){
        System.out.print(i+" selected, correction");
        i--;
        if (i<0) i=last;
    }
    selected = i;
    return selected;
}



   public static void main(String[] args){

   RouletteWheel rw = new RouletteWheel();
   int rept = 20;
   List<Double> P = new ArrayList<>(4);
   P.add(0.2);
   P.add(0.1);
   P.add(0.6);
   P.add(0.1);
   Random rng = new Random();
   for (int i = 0 ; i < rept; i++){
       try {
           int s = rw.select(P, rng);
           System.out.println("Element selected "+s+ ", P(s) = "+P.get(s));
       } catch (Exception ex) {
           Logger.getLogger(RouletteWheel.class.getName()).log(Level.SEVERE, null, ex);
       }
   }
   P.clear();
   P.add(0.2);
   P.add(0.0);
   P.add(0.5);
   P.add(0.0);
   P.add(0.1);
   P.add(0.2);
   //rng = new Random();
   for (int i = 0 ; i < rept; i++){
       try {
           int s = rw.select(P, rng);
           System.out.println("Element selected "+s+ ", P(s) = "+P.get(s));
       } catch (Exception ex) {
           Logger.getLogger(RouletteWheel.class.getName()).log(Level.SEVERE, null, ex);
       }
   }
}

 /**
 * {@inheritDoc}
 * @return 
 */
 @Override
 public String toString()
 {
    return "Roulette Wheel Selection";
 }
}

Ниже пример выполнения для вектора вероятности P = [0.2,0.1,0.6,0.1], WheelElements = [0,1,2,3]:

Выбран элемент 3, P (s) = 0,1

Выбран элемент 2, P (s) = 0,6

Выбран элемент 3, P (s) = 0,1

Выбран элемент 2, P (s) = 0,6

Выбран элемент 1, P (s) = 0,1

Выбран элемент 2, P (s) = 0,6

Выбран элемент 3, P (s) = 0,1

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Выбран элемент 3, P (s) = 0,1

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Выбран элемент 0, P (s) = 0,2

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Выбран элемент 2, P (s) = 0,6

Код также проверяет колесо рулетки с нулевой вероятностью.

Другие вопросы по теме