Коммерческая рандомизация для игры в покер - PullRequest
4 голосов
/ 17 марта 2011

Мне нужен совет о том, как решать алгоритмическую проблему (т.е. не программировать как таковую). Ниже приведены мои потребности и то, как я пытался их удовлетворить. Любые комментарии по улучшению будут приветствоваться.

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

Я хотел бы создать программу, которая может производить более рандомизированные колоды карт, чем обычная программа, вызывающая random (). Это должны быть качественные колоды, созданные из высококачественных случайных чисел. Я слышал, что коммерческие покерные серверы используют 64-битные векторы для каждой карты, таким образом, обеспечивая случайность для всех миллионов покерных игр, в которые играют ежедневно.

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

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

Псевдо-код ниже:

    Start by noting the system time.
    Hash the current time (with MD5) around ten times (I chose the ten arbitrarily).
    Take the resulting hash, and use it as the seed to the language-dependent random() function.
    Call random() 52 times and store the results.
    Take the values produced by random() and hash them.
    Any hash function that produces at least 64-bits of output will do for this.
    Truncate (if the hash is too big) so the hashes will fit inside a 64-bit double.
    Find a way to map the 52 doubles (which should be random now, according to my calculations) into 52 different cards, so we can play some poker.

Моя проблема с последним шагом. Я не могу придумать, как правильно сопоставить каждое 64-битное значение с соответствующей картой, не беспокоясь о том, что два числа совпадают (маловероятно) или не теряют случайности (вероятно).

Моя первая идея состояла в том, чтобы разбить 0x0000000000000000 - 0xFFFFFFFFFFFFFFFF на четыре четных секции (для представления мастей). Но нет никакой гарантии, что мы найдем ровно тринадцать карт в разделе, что было бы плохо.

Теперь, когда вы знаете, где я застрял, как бы вы преодолели этот вызов?

- отредактировано -

Чтение байтов из / dev / random будет хорошо работать на самом деле. Но это все еще оставляет меня потерянным на том, как сделать преобразование? (при условии, что я прочитал достаточно байтов для 52 карт).

Мое настоящее желание - взять что-то простое и предсказуемое, например системное время, и превратить его в рандомизированную колоду карт. Заполнение random () системным временем - ПЛОХОЙ способ сделать это. Отсюда хэширование времени и хэширование значений, которые получаются случайными ().

Черт, если бы я захотел, я мог бы хэшировать байты из / dev / random, только для смеха и хихиканья. Хеширование улучшает случайность вещей, не так ли? Разве не поэтому современные менеджеры паролей хранят пароли, которые были хешированы тысячи раз?

- Редактировать 2 -

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

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

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

Второе, на что я хочу обратить внимание: Я делаю это задом наперед.

Я имею в виду, что вы все предлагаете мне взять отсортированную, предсказуемую, неслучайную колоду карт и использовать на ней перетасовку Фишера-Йейтса.Я уверен, что Фишер-Йейтс - хороший алгоритм, но допустим, что вы не могли его использовать по какой-либо причине.

Не могли бы вы взять случайный поток байтов, скажем, в окрестности 416 байтов (52 картыс 8 байтами на карту), а BAM производит уже случайную колоду карт?Байты были случайными, поэтому это не должно быть слишком сложно.

Большинство людей начинали с колоды из 52 карт (случайных или нет) и обменивали их несколько раз (выбирая случайный индекс для обмена).Если вы можете сделать это, то вы можете взять 52 случайных числа, пробежать их один раз и создать рандомизированную колоду.

Как я могу описать, Алгоритм принимает поток случайных байтов и просматривает каждый 8-байтовый фрагмент.Он отображает каждый кусок на карту.

Пример.0x123 карты для пикового туза Ex.0x456 карты для короля бриллиантов Ex.0x789 сопоставляется с 3 клубами .... и т. Д.

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

Шаг 1: Получить достаточное количество случайных байтов из хорошего источника. Шаг 2: Разделить этот поток байтов на 52 блока, по одному для каждой карты в колоде. Шаг 2a: Выполните 52 фрагмента, преобразовав их в значения карт согласно нашей карте.

Имеет ли это смысл?

Ответы [ 8 ]

14 голосов
/ 18 марта 2011

Вы чрезмерно усложняете проблему.Для решения вашей проблемы необходимы два компонента:

  1. Алгоритм перемешивания
  2. Достаточно качественный генератор случайных чисел для использования алгоритма перемешивания.

Первое легко, просто используйте алгоритм Фишера-Йейтса shuffle .

Для второго, если вы хотите достаточных степеней свободы , чтобы иметь возможность генерировать каждыйвозможная перестановка (из 52! возможностей), тогда вам нужно как минимум 226 бит энтропии.Использование системных часов не даст вам больше 32 или 64 битов энтропии (на практике гораздо меньше, поскольку большинство битов предсказуемо), независимо от того, сколько избыточных хешей вы выполняете.Найдите RNG, который использует 256-битное начальное число, и запустите его 256 случайными битами (проблема с самозагрузкой, но для этого вы можете использовать / dev / random или аппаратное устройство RNG).

6 голосов
/ 18 марта 2011

Вы не упоминаете, в какой ОС вы работаете, но большинство современных ОС имеют заранее сделанные источники высококачественной энтропии. В Linux это /dev/random и /dev/urandom, из которых вы можете прочитать столько произвольных байтов, сколько захотите.

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

5 голосов
/ 17 марта 2011

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

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

Редактировать:

Вы упомянули, что вы также хотите знать, как сопоставитьэто обратно к алгоритму случайного перемешивания.Эта часть на самом деле довольно проста.Один простой способ - это shuffle Фишера-Йейтса. По сути, все, что вам нужно от вашего RNG, - это случайное число, равномерно распределенное между 0 и 51 включительно.То, что вы можете сделать в вычислительном отношении с учетом любого ГСЧ и обычно встроено в хорошую библиотеку.См. Раздел «Потенциальные источники предвзятости» статьи в Википедии.

2 голосов
/ 18 марта 2011

Отличный вопрос!

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

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

Хорошей новостью является то, что очень легко получить криптографически безопасный PRNG. Если вы берете какой-либо безопасный блочный шифр (скажем, AES или 3DES) и , используя случайный ключ , начинаете шифровать числа 0, 1, 2, ... и т. Д., Тогда полученная последовательность является криптографически безопасной. То есть вы можете использовать /dev/random, чтобы получить несколько случайных байтов для использования в качестве ключа, а затем получить случайные числа, последовательно зашифровав целые числа, используя надежный шифр с заданным ключом. Это безопасно до тех пор, пока вы не вернете примерно & radic; n чисел, где n - размер пространства ключа. Для шифра, такого как AES-256, это 2 128 значений, прежде чем вам потребуется сбросить случайный ключ. Если вы «только» хотите играть в миллиарды игр (2 40 ), это будет более чем хорошо.

Надеюсь, это поможет! И удачи в проекте!

1 голос
/ 18 марта 2011

Вы обязательно должны прочитать ответ на этот вопрос: Понимание "случайности"

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

Вы можете рассмотреть возможность использования физически полученных случайных чисел, а не псевдослучайных чисел: http://en.wikipedia.org/wiki/Hardware_random_number_generator

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

0 голосов
/ 02 июня 2011

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

0 голосов
/ 18 марта 2011

Чтение байтов из / dev / random будет хорошо работать на самом деле. Но это все еще оставляет меня потерянным, как сделать преобразование? (при условии, что я прочитал достаточно байтов для 52 карт).

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

Просто убедитесь, что правильно реализовали алгоритм перетасовки :)

0 голосов
/ 18 марта 2011

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

В основном вы предполагаете, что фактические карты имеют естественный порядок, а затем вы сортируете случайные числа и отображаете карту в колоду.

Редактировать

Судя по всему, в Википедии перечислен этот метод как альтернатива алгоритму Фишера-Йейтса (о котором я раньше не слышал - спасибо Дэн Дайер!). Одна вещь в статье википедии, о которой я не думал, это то, что вам нужно быть уверенным, что вы не повторяете случайные числа, если используете алгоритм, который я описал.

...