Кости от смены случайного генератора


10

Введение

Вам дан случайный целочисленный генератор со следующей реализацией

  • Первый вызов всегда возвращает 1.
  • Второй вызов возвращает случайное целое число от 1 до 2.
  • Третий вызов возвращает случайное целое число от 1 до 3.
  • N-й вызов возвращает случайное целое число от 1 до n включительно.

Основываясь на вышеупомянутой функции, напишите генератор случайных костей, который является совершенно случайным, возвращая значение от 1 до 6 (включительно) с равной вероятностью.

правила

  • Ваша программа / функция должна приводить к случайному целому числу от 1 до 6 включительно в некоторой пригодной для использования форме, т. Е. К стандартному выводу или в качестве возвращаемого значения функции.
  • Вышеуказанный генератор восходящих случайных чисел может быть определен как «свободная» функция в вашей программе (т. Е. Не учитывается при подсчете количества символов) или как отдельный скрипт / программа, которая выполняется по мере необходимости, при условии сохранения состояния ( n) между звонками.
  • Предположим, что в одном случае использования вашей программы будет запрошено не более 1000 бросков игральных костей, и первоначальный генератор случайных чисел может быть сброшен 1в конце 1000 бросков игральных костей, чтобы избежать переполнения n.
  • Ваша программа не может использовать какой-либо другой источник случайных чисел, кроме генератора случайных чисел по возрастанию, определенного выше. Конечно, вы можете запросить несколько случайных чисел у генератора случайных чисел для каждого отдельного результата броска костей.
  • Это код-гольф, поэтому победитель - самый короткий ответ или большинство голосов в случае ничьей. Если вы можете сгенерировать 1000 бросков костей, используя менее 1000 сгенерированных случайных чисел, дайте себе 10-очковый бонус эффективности .

пример

./asc-rand
1 # random integer between 1 and 1
./asc-rand
1 # random integer between 1 and 2
./asc-rand
3 # random integer between 1 and 3
./asc-rand
4 # random integer between 1 and 4

# dice-gen generates random dice based on output of asc-rand program.
./dice-gen
3
./dice-gen
6
./dice-gen
5
./dice-gen
1

Программа iterate(6):b=asc-rand(); print bнезаконна или не работает? Я мог бы неправильно понять третье правило.
beary605

@ beary605: Генератор случайных чисел может быть сброшен только после 1000 бросков костей, а не между каждым броском костей. Единственная причина, о которой я упоминаю, - это возможность переполнения значения, возвращаемого генератором случайных чисел, не является проблемой в этой задаче. Изменить: Я уточнил цель правила, надеюсь, это поможет.
mellamokb

Когда вы говорите «случайное число», вы подразумеваете «случайное целое число» или «случайное (усеченное) действительное число»? Возможно, есть какое-то соглашение, о котором я не знаю.
DavidC

@DavidCarraher: Очень хороший момент. Я имел в виду случайное целое число, и я вижу, что это не ясно. Я обновлю вопрос. Редактировать: Обновлено.
mellamokb

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

Ответы:


2

J - 13 символов

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

r=:1+?  NB. free random function
r>:i.".1!:1]1

Объяснил взрывом:

r=:1+?           NB. r(x) = 1 + a random number between 0 and n-1
           ]1    NB. input file handle
       1!:1      NB. read in a string
     ".          NB. convert to integer
 >:i.            NB. make a list of numbers, from 1 to that integer
r                NB. apply the random function

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

r=:1+?  NB. free random function
c=:0
f=:3 :'r c=:1+c'

K аналогов: свободная случайная функция r:{*1_draw x}, стандартная версия (10 символов) r'1+!. 0:` , функциональная версия (14 символов), c:0;f:{r@c+:1}вызываемая f[].
алгоритмическая

6

Питон, 31 символ

Аналогично scleaver, определите генератор следующим образом:

from random import randint
n=0
def r():
    global n;n+=1
    return randint(1,n)

Затем функция для возврата бросков костей:

D=lambda:eval('r(),'*6)[-1]%6+1

Звоните в D()любое время, когда вам нужен случайный бросок костей.


Ах, умное использование eval, мне это нравится.
scleaver

3

Скала 23

def s={r;r;r;r;r;r%6+1}

Метод r может быть (примерно) реализован так:

var cnt = 0 
val rnd = new util.Random 

def r = {
  cnt %= 1000
  cnt += 1
  rnd.nextInt (cnt)
}

грубый тест:

scala> (1 to 6).map (i => ((1 to 600) map (_=>s)).filter (_ == i).size)
res26: scala.collection.immutable.IndexedSeq[Int] = Vector(110, 105, 91, 96, 106, 102)

Каждый шестой вызов должен давать равное распределение по 6 значениям, поэтому я выбрасываю 5.


2

GolfScript (15 символов)

Это предполагает, что количество требуемых бросков указано в stdin, и перечисляет столько результатов в stdout.

# The free increasing random function
0:N;{N):N rand)}:r;

~{r{;r}5*6%)n}*

Онлайн демо

Хотя я мог получить бонус в 10 баллов за использование менее 1000 бросков для генерации 1000 чисел, это стоило бы мне гораздо больше, чем 10 символов. Тривиальный подход извлечения подходящей энтропии, когда N кратно степени 2 или 3, значительно сокращается, потому что число доступных результатов в моде 3 составляет всего 333 + 111 + 37 + 12 + 4 + 1 = 498. Поэтому необходимо принять образец и отклонить подход. Используя этот подход, вы можете получить ожидаемые 2242 броска от 1000 звонков до r, но есть дополнительные накладные расходы на бухгалтерию и baseэто очень длинное имя функции.


5
baseэто очень длинное имя функции" Вы, очевидно, не используете Mathematica . Мы получаем такие чудеса , как NegativeBinomialDistribution, ExponentialGeneratingFunction, MathieuCharacteristicExponent, InverseFourierSequenceTransformи SemialgebraicComponentInstances. :-)
Mr.Wizard

1

Python 65 63

i=7
while i>5:[R()for x in range(9)];i=int(`R()`[-1])
print i+1

Функция R()является восходящим рандомизатором.

Применение:

$ ./rollDice.py
3
$ ./rollDice.py
5

Почему бы не избавиться от вашего forцикла и просто позвонить Rодин раз перед вашим whileциклом?
Кит Рэндалл

@KeithRandall Число, которое я возвращаю в качестве броска костей, является последней цифрой числа, которое возвращает восходящий генератор. Мне нужно сделать 10 вызовов восходящему генератору, чтобы обеспечить равные вероятности для всех возможных цифр.
Мэтт

Почему 10 звонков? В принципе, если генератор случайный, не должен ли каждый вызов предоставлять одинаковую вероятность для любой из (десяти) цифр? Конечно, на практике вы можете ожидать только приблизиться к равному числу для каждого из чисел.
DavidC

@DavidCarraher Генератор возвращает случайные числа от 1 до n, где n - это количество раз, когда вы вызывали его. Я смотрю на последнюю цифру этого возвращенного числа. Если n не является целым числом, кратным 10, вероятность не будет равномерной. Например: если n = 13, вероятности будут разбиты следующим образом: 1/9 для бросков 1,5,6 и 2/9 для бросков 2,3,4
Мэтт

@Matt: я предполагал, что R()возвращал число с плавающей точкой, и вы брали наименее значимую цифру. Теперь, когда выяснено, что R()возвращает целое число, это имеет смысл.
Кит Рэндалл

1

Python, 56

r определяется как:

from random import randint
n=0
def r(z):
    global n;n+=1
    return randint(1,n)

генератор костей d:

import math;d=lambda:math.ceil(6.*r(r(r(r(r(r(0))))))/n)

использование, например, для 100 рулонов:

for i in range(100):print d()

Вы можете, вероятно, удалить, import mathесли вы замените math.ceil(...)наint(...)+1
Matt

Я хотел бы, но это произвело бы 7 как возможный вывод.
Scleaver

О, да. Я пропустил это.
Мэтт

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

1

Mathematica 51

Генератор случайных чисел, rсбрасывается путем установки глобальной переменной равной n1.

n = 1; r[c_] := RandomInteger[{1, c}]

Код

Не в бегах за самый короткий код ...

h := (n++; If[n < 4 \[Or] (y = r@n) > 6 Quotient[n, 6], h, y~Mod~6 + 1])

Применение

t = Table[h, {60000}];
n
SortBy[Tally[t], First]

Для 60000 бросков игральных костей требуется 60031 звонок h. Tallyпоказывает разбивку по номерам 1-6.

60031

{{1, 9923}, {2, 9966}, {3, 10016}, {4, 10028}, {5, 10009}, {6, 10058}}


1

Perl, 22 или 45

Реализация генератора восходящих случайных чисел:

my $n=0;
sub r { $n++; return 1+int(rand$n); }

Генерация:

#copy of the Scala solution; short code; uses 6N rolls
sub s{r;r;r;r;r;1+r%6}
#more efficient implementation, uses approximately 6+N+lnN rolls
sub roll { do{$a=r-1}while($a>$n-$n%6);return 1+(1+$a)%6 }

Тестирование:

число чисел
1 10001867 0,348569
2 10004853 2,35161
3 9994395 3,141602
4 10000177 0,003133
5 9999227 0,05753
6 9999481 0,026936
Т 60000000 5.935154
60000000 бросков игральных костей заняли 60000042 звонков и 570.432735 секунд



0

GolfScript , 8 байт

f;3f*f(-

Попробуйте онлайн!

Он запускает генератор один раз, а затем избавляется от результата. Затем он бросает f2 и умножает его на 3 (3 или 6), затем вычитает f3-1 (0, 1, 2), что приводит к (3-2, 3-1, 3-0) или (6-2, 6-1, 6-0) W5.

Golfscript и случайная функция существовали до того, как этот вопрос был опубликован, так же как и юридическое представление.

Это отправка только один раз. Если вам нужно запустить его несколько раз за один звонок,

GolfScript , 12 байт

f;3f*f-)0:i;

Попробуйте онлайн!

Это сбрасывает ваш я звоню на 0, поэтому он сбрасывается соответственно. Этот TIO показывает 50 случайных результатов.


0

C (gcc) , 31 байт

f(i){for(i=5;i--;)c;i=~-c%6+1;}

При каждых 6 вызовах вероятность каждого сгенерированного числа от 1 до 6 включительно равна.

cэто #defined как вызов функции, которая генерирует идеальные случайные числа.

Попробуйте онлайн!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.