Лучший случайный шаффлер в Rust?

Я только что сделал программу, которая создает колоду из 26 карт, разбивает ее на 5 рук по 5 карт (отбрасывая 1) и проверяет покерные комбинации, которые есть в этих руках, если они есть.

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

И что странно, как только я добавил счетчик, чтобы показать, сколько колод он прошел, он показывал только 150 - 4000! И я думаю, что это вина случайного перемешивателя. Я сделал аналогичную программу на Python, и она проверяла примерно правильное количество колод.

Я использовал это, что должно перетасовать колоду на месте:

fn shuffle_deck(deck: &mut Vec<Card>) -> () {
    deck.shuffle(&mut rand::thread_rng())
}

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

Обновлено: также, для тех, кто интересуется, это структура карты:

pub struct Card {
    value: i32,
    suit: String
}

"создает колоду из 26 карт" Как? Можете ли вы показать код? Кроме того, как вы получили число 1: 600k, похоже, это число для колод из 52 карт и недействительно для колод из 26 карт. Это также вероятность того, что одна конкретная рука окажется флеш-роялем, а не любая из рук. Лучше всего предоставить минимальный воспроизводимый пример.

cafce25 17.02.2023 16:02

Это далеко не 1: 600k с колодой из 26 карт, 26 C 5 - это 65780, а в колоде 4 флеша-рояля, поэтому шансы на то, что любая данная рука окажется флеш-роялем, составляет 1: 16445. И поскольку вы видите 5 раздач за сессию, я бы предположил, что это 1:3289.

Masklinn 17.02.2023 16:07

Я голосую за то, чтобы закрыть этот вопрос, потому что заявленная «проблема» на самом деле является правильным поведением.

pjs 17.02.2023 17:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваше предположение неверно.

26 карт могут составлять 26 over 5 возможных комбинаций, то есть 65780 комбинаций.

Поскольку у вас в колоде 4 флеш-рояля, вероятность того, что вам выпадет флеш-рояль, составляет 4/65780 = 0.006080875646093037 % или один из всех 16445.

Если вы посмотрите на четыре одновременно, это число примерно делится на 4 (не совсем потому, что эти четыре розыгрыша не являются независимыми), поэтому вы должны получать что-то примерно одно каждые ~3300.

Итак, если вы измерите это экспериментально, вы получите:

use rand::seq::SliceRandom;

fn is_royal_flush(deck: &[u8]) -> bool {
    if deck.len() != 5 {
        false
    } else {
        let mut buckets = [0u8; 4];
        for el in deck {
            if let Some(bucket) = buckets.get_mut((*el / 5) as usize) {
                *bucket += 1;
            }
        }

        buckets.iter().any(|bucket| *bucket == 5)
    }
}

fn has_royal_flush(deck: &[u8; 26]) -> bool {
    is_royal_flush(&deck[0..5])
        || is_royal_flush(&deck[5..10])
        || is_royal_flush(&deck[10..15])
        || is_royal_flush(&deck[15..20])
        || is_royal_flush(&deck[20..25])
}

fn main() {
    let mut rng = rand::thread_rng();

    let mut deck = [0; 26];
    deck.iter_mut()
        .enumerate()
        .for_each(|(pos, val)| *val = pos as u8);

    println!("Deck, initially: {:?}", deck);
    deck.shuffle(&mut rng);
    println!("Deck, shuffled:  {:?}", deck);
    println!();

    let mut total: usize = 0;
    let mut royal_flushes: usize = 0;

    loop {
        deck.shuffle(&mut rng);

        total += 1;

        if has_royal_flush(&deck) {
            royal_flushes += 1;
        }

        if total % 10000000 == 0 {
            println!(
                "Now {} out of {}. (Probability: 1/{})",
                royal_flushes,
                total,
                total / royal_flushes
            );
        }
    }
}
Deck, initially: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
Deck, shuffled:  [25, 16, 3, 12, 18, 1, 14, 8, 17, 0, 5, 15, 6, 11, 4, 21, 2, 13, 24, 20, 22, 7, 10, 9, 19, 23]

Now 2976 out of 10000000. (Probability: 1/3360)
Now 6004 out of 20000000. (Probability: 1/3331)
Now 8973 out of 30000000. (Probability: 1/3343)
Now 11984 out of 40000000. (Probability: 1/3337)

Что примерно соответствует ожидаемому. Таким образом, ваше предположение о том, что вы должны получать только один флеш-рояль каждый 600k, неверно, и, скорее всего, что-то не так с вашим кодом на Python.


Тем не менее, если вы вычислите вероятность собрать один флеш-рояль в колоде из 52 карт, то вы должны получить (52 over 5) / 4 = один каждые 649740 розыгрышей. Вероятно, вы имели в виду, и если вы запрограммируете его, он соответствует его ожиданиям:

use rand::seq::SliceRandom;

fn is_royal_flush(deck: &[u8]) -> bool {
    if deck.len() != 5 {
        false
    } else {
        let mut buckets = [0u8; 4];
        for el in deck {
            if let Some(bucket) = buckets.get_mut((*el / 5) as usize) {
                *bucket += 1;
            }
        }

        buckets.iter().any(|bucket| *bucket == 5)
    }
}

fn has_royal_flush(deck: &[u8; 52]) -> bool {
    is_royal_flush(&deck[0..5])
}

fn main() {
    let mut rng = rand::thread_rng();

    let mut deck = [0; 52];
    deck.iter_mut()
        .enumerate()
        .for_each(|(pos, val)| *val = pos as u8);

    println!("Deck, initially: {:?}", deck);
    deck.shuffle(&mut rng);
    println!("Deck, shuffled:  {:?}", deck);
    println!();

    let mut total: usize = 0;
    let mut royal_flushes: usize = 0;

    loop {
        deck.shuffle(&mut rng);

        total += 1;

        if has_royal_flush(&deck) {
            royal_flushes += 1;
        }

        if total % 10000000 == 0 {
            println!(
                "Now {} out of {}. (Probability: 1/{})",
                royal_flushes,
                total,
                total / royal_flushes
            );
        }
    }
}
Deck, initially: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
Deck, shuffled:  [2, 15, 44, 39, 26, 47, 28, 11, 1, 19, 31, 6, 43, 42, 29, 48, 35, 30, 3, 49, 50, 37, 9, 10, 18, 45, 33, 22, 36, 5, 38, 46, 51, 32, 7, 17, 23, 27, 41, 14, 21, 13, 25, 4, 8, 16, 20, 24, 12, 34, 0, 40]

Now 6 out of 10000000. (Probability: 1/1666666)
Now 22 out of 20000000. (Probability: 1/909090)
Now 36 out of 30000000. (Probability: 1/833333)
Now 54 out of 40000000. (Probability: 1/740740)
Now 70 out of 50000000. (Probability: 1/714285)
Now 78 out of 60000000. (Probability: 1/769230)
Now 92 out of 70000000. (Probability: 1/760869)
Now 102 out of 80000000. (Probability: 1/784313)
Now 125 out of 90000000. (Probability: 1/720000)
Now 139 out of 100000000. (Probability: 1/719424)
Now 164 out of 110000000. (Probability: 1/670731)
Now 190 out of 120000000. (Probability: 1/631578)
Now 202 out of 130000000. (Probability: 1/643564)
Now 217 out of 140000000. (Probability: 1/645161)
Now 232 out of 150000000. (Probability: 1/646551)
Now 248 out of 160000000. (Probability: 1/645161)

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