Случайная Куайн


15

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

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

Например, у этой программы был бы один шанс из 50 ^ 60 воспроизвести себя.

Что такое токен? Это зависит от языка. Например, идентификаторы ( foo_bar), ключевые слова ( while) и цифры ( 42) будут считаться токенами в большинстве языков. Пробелы не учитываются в большинстве языков.

Дополнительные правила:

  • Вывод может содержать только токены, найденные в исходном коде программы, разделенные соответствующим разделителем
  • Вывод должен быть той же длины, что и исходный код программы, с учетом токенов
  • Можно использовать только один язык программирования
  • Исходный код должен иметь как минимум 3 уникальных токена
  • Исключить комментарии из исходного кода
  • Программа должна иметь только один шанс, чтобы воспроизвести себя

Подсчет очков: побеждает программа, которая имеет наилучшие шансы воспроизвести себя.


@MathieuRodic: Вы предполагаете, что программа рисует токены без повторений.
user2357112 поддерживает Monica

@MathieuRodic: Позвольте мне перефразировать. Вы предполагаете, что программа случайным образом скремблирует мультимножество своих токенов, а не вытягивает L токенов с повторением из набора U токенов, использованных в его источнике.
user2357112 поддерживает Monica

@ user2357112: Понятно. Моя ошибка заключалась в том, чтобы рассматривать эту проблему как ничью без замены.
Матье Родик

1
Правило № 1 и № 5, кажется, противоречит мне.
Cruncher

4
Можете ли вы предположить, что встроенные случайные функции являются TRNG? Типичные реализации имеют слишком маленькие семена для получения всех выходов и, следовательно, могут быть неспособны к самовосстановлению.
CodesInChaos

Ответы:


11

Python 2, 3 ^ -3 = 0,037

execЗлоупотребление очень удобно для уменьшения количества токенов. Теперь обновлено, чтобы не читать исходный файл!

exec '' """
s = '''{a}
s = {b}
s = s.format(a='"'*3, b="'"*3+s+"'"*3)
import random
tokens = ['exec', "''", s]
print random.choice(tokens), random.choice(tokens), random.choice(tokens),
{a}'''
s = s.format(a='"'*3, b="'"*3+s+"'"*3)
import random
tokens = ['exec', "''", s]
print random.choice(tokens), random.choice(tokens), random.choice(tokens),
"""

Дополнительная строка ''между execи гигантской строкой в ​​тройных кавычках просто добавляет число маркеров к необходимому минимуму 3. Он объединяется во вторую строку из-за неявной конкатенации буквенных строк.

Оригинальная версия с открытием исходного файла:

exec '''
# String literals are one token!
import random
import tokenize

with open(__file__) as f:
    tokens = [x[1] for x in tokenize.generate_tokens(f.readline)][:-1]

''' '''
# Splitting the string into two strings pads the token count to the minimum of 3.

print random.choice(tokens), random.choice(tokens), random.choice(tokens),
'''

Строго говоря, грамматика Python помещает токен ENDMARKER в конец исходного файла, и мы не можем создать исходный файл с произвольно разбросанными ENDMARKER. Мы притворяемся, что его не существует.


@ Cruncher Это вероятность. 3 ^ -3 == 1/3 ^ 3
Остин Хенли

2
+1 за блестящий взлом правил. Та же идея реализована в J: ".]';(?3 3 3){]`".;~({:,],{:,],6#{:)'';(?3 3 3){]`".;~({:,],{:,],6#{:)'''''''.
алгоритмическая

5

Javascript, 102 токена, 33 уникальных, 7,73 × 10 -154

Обратите внимание, это настоящая квинна. Он не читает файл или не использует evalилиFunction.toString

meta = "meta = ; out = '' ; tokens = meta . split ( '\\u0020' ) ; tokens . push ( '\"' + meta + '\"' ) ; length = tokens . length ; tmp = length ; unique = { } ; while ( tmp -- ) unique [ tokens [ tmp ] ] = unique ; unique = Object . keys ( unique ) ; tmp = unique . length ; while ( length -- ) out += tokens [ ~~ ( Math . random ( ) * tmp ) ] + '\\u0020' ; console . log ( out )"; 
out = '';
tokens = meta.split('\u0020');
tokens.push('"' + meta + '"');
//console.log(tokens);
length = tokens.length;
tmp = length;
unique = { };
while(tmp--) unique[tokens[tmp]] = unique;
unique = Object.keys(unique);
//console.log(unique);
tmp = unique.length;
while(length--)
    out += unique[~~(Math.random() * tmp)] + '\u0020';
console.log(out)

4

Python: P (создание программы в 1 пробной версии) = 3,0317 * 10 ^ -123

34 уникальных токена, 80 всего токенов. Обратите внимание, что в конце каждой строки есть пробел.

import tokenize , random 
tokens = [ x [ 1 ] for x in tokenize . generate_tokens ( open ( __file__ , 'r' ) . readline ) ] [ : -1 ] 
s = '' 
for x in tokens : s += random . choice ( list ( set ( tokens ) ) ) ; s += [ ' ' , '' ] [ s [ -1 ] == '\n' ] 
print s 

Пример вывода:

' ' random len set 'r' , for ( list , import ] ] tokens : random [ for '\n' import readline readline 'r' tokens [ len 'r' import '' choice '' '' for in ( readline ( = open readline , list 1 list s += for s 1 , '' : 1 += list len - __file__ ; open __file__ print . - ] 'r' for import [ print . , 

; . [ [ print print __file__ generate_tokens ] ; open ] , readline 

Спасибо другому решению Python от user2357112 за напоминание, что я должен отказаться от последнего токена и использовать его, о __file__котором я раньше не знал.


3

J - 1 в 11 17 = 1,978 x 10 -18

;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''

У J есть несколько удобных маленьких инструментов для выполнения таких работ.

  • Прежде всего, любая строка чисел, разделенная пробелами, является одним токеном . Это означает одномерный массив этих чисел. Вот как работает лексер J. Кстати, это семнадцать 11секунд, если кому-то интересно.

  • (,,,{:,{:)'QUINE'''это обычный трюк с квиннами в J, созданный для использования как можно меньшего числа токенов: {:означает Tail , поэтому он добавляет строку к себе, а затем добавляет две копии последнего символа в конце этого. Поскольку последний символ представляет собой одинарную кавычку (J использует строки в стиле Pascal), результат будет QUINE'QUINE'''.

  • ;:является токенизатором и разбивает входную строку, как если бы это был код J, возвращая список блоков. Длина этого результата составляет 17.

  • ~.берет все уникальные элементы этого массива. Длина этого результата составляет 11.

  • ?называется Roll . Для каждого целого числа в своем аргументе он выбирает случайное положительное число, большее или равное нулю, меньше этого числа. Так что здесь J сгенерирует 17 чисел от 0 до 10 включительно.

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

  • ; открывает все эти поля и запускает результат вместе.

Вот несколько примеров. Строки с отступом - это входные приглашения, а строки, находящиеся на одном уровне с левой стороной, - это вывод интерпретатора.

   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
~.~.(?;;:11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''(){11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){(;:;
   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
{';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)''',?{:;:{:';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11{:{;(;:{:,~.

2

постскриптум

Это было весело

/cvx /cvx cvx /exec /exec cvx /dup /rand /mod /get /== /array /astore /realtime
/srand /repeat 6 17 54 17 /array cvx exec /astore cvx exec 54 /dup cvx /rand
cvx 17 /mod cvx /get cvx /== cvx 6 /array cvx exec /astore cvx exec cvx /realtime
cvx exec /srand cvx exec /repeat cvx exec

Существует 17 уникальных жетонов и 54 жетона всего на 1 шанс 3,6e-67.


2

Пробелы, 3 ^ -205 3 ^ -189 3 ^ -181 3 ^ -132 ~ = 10 ^ -63

Это программа Whitespace, которая при засеве случайными символами имеет шанс 1 на 3 ^ 132 воспроизвести себя (3 различных токена, повторяемые 132 раза). При запуске он должен содержать не менее 132 случайных символов (в пробеле нет встроенной функции выбора случайных чисел или даты), напримерsome_whitespace_interpreter my_quine.ws <some_random_source >quine_output.ws . Счет мог бы улучшиться, если бы программу можно было играть в гольф больше, но это моя первая «настоящая» программа для пробелов, поэтому я просто оставлю ее с моим скудным количеством игры в гольф.

Простой код пробела или его запуск : (чтобы попробовать, нажмите «изменить», скопируйте содержимое внутри тегов <pre>; должно быть 132 символа с EOL в стиле Unix)

    

























Код с аннотацией к какой команде есть что (технически не квин, так как он не воспроизводит комментарии):

стек push_number + 0 end
стек push_number + 1 0 0 1 конец
стек кучи, push_number + 1 конец
стек push_number + 1 0 0 0 0 0 конец
стек хранилища кучи push_number + 1 0 end
стек push_number + 1 0 1 0 конец
стек хранилища кучи push_number + 1 0 0 0 0 0 1 1 end
течь
make_label loop_begin  
стек push_number + 1 1 конец
IO  
читать стек символов push_number + 1 1 end
стек извлечения кучи push_number + 1 1 end
арифметика по модулю кучи получить IO  
печать набора символов push_number + 1 end
стек арифметического вычитания дубликат
 течь
jump_if_zero end_prog
течь
перейти к 
loop_begin  
течь
make_label end_prog
течь
end_program

Если семя просто оказывается эквивалентным (символы берутся из мода 3 для преобразования в токены), то это будет успешно:

CCCCACCCBCCBABBCCCCBACCCBCCCCCABBCCCCBCACCCBCBCABBCCCCBCCCCCBBAACCBACCCBBABABCCCCBBABBBCCCBBABCBBBBBBACCCCCBABCCBCACABBAACABAACCAAAA

Это довольно простая программа, примерно эквивалентная этой Ruby-программе:

i = 131
while true
    print '\t \n'[STDIN.getc.ord % 3]
    i = i - 1
    break if i < 0
end

1

Perl, 27 токенов, P = 1,4779 x 10 -34

@ARGV=$0;print$W[rand@W]for@W=split/(\W)/,readline

Последнее редактирование: используйте @ARGV=$0вместо open*ARGV,$0сохранения токена.

  • 15 уникальных токенов
  • Появляются 4 жетонов в 2 раза ( =, /, @, $)
  • 1 токен появляется 4 раза ( W)

Поэтому я думаю, что это делает вероятность (pow (2,2 * 4) * pow (4,4)) / pow (27,27), около 1,48E-34.

Если исходный код находится в файле с именем ARGV, то вы можете использовать это решение с 26 токенами с P = ~ 2,193 x 10 -31 :

@ARGV=ARGV;print$ARGV[rand@ARGV]for@ARGV=split/(\W)/,readline

На самом деле, P = (4 * 2! + 4!) / 27!что составляет около 1,7632684538487448 x 10 ^ -26
Матье Родик

0

Perl 6 ,1 в 33 знак равно 0.037037 ...

(Я знаю, что это не код-гольф, но ...)

q[say |roll <<~~"q[$_]".EVAL>>: 3]~~.EVAL

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

Почти так же, как ответ Python, где первый токен является строковым литералом, который оценивается. Токены

q[say |roll <<~~"q[$_]".EVAL>>: 3]   String literal
~~                                   Smartmatch operator
.EVAL                                Function call

Объяснение:

q[say |roll <<~~"q[$_]".EVAL>>: 3]         # Push as string literal
                                  ~~       # Smartmatch by setting $_ to the string literal
                                    .EVAL  # Eval the string
            <<~~"q[$_]".EVAL>>             # From the list of tokens
       roll                   : 3          # Pick 3 times with replacement
  say |                                    # Join and print
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.