Випадкова квітка


15

Напишіть програму, яка здатна випадково генерувати себе.

Це потрібно зробити на основі лексем, які використовуються у вихідному коді. Якщо вихідний код вашої програми складається з 50 унікальних жетонів і становить 60 лексем, то програма повинна виводити 60 жетонів, де кожен маркер випадковим чином вибирається з одного з 50 унікальних жетонів.

Наприклад, ця програма матиме шанс на 50 ^ 60 відтворити себе.

Що таке маркер? Це залежить від мови. Наприклад, ідентифікатори ( foo_bar), ключові слова ( while) та числа ( 42) вважатимуться лексемами на більшості мов. Пробіли не враховуються на більшості мов.

Додаткові правила:

  • Вихідні дані можуть містити лише маркери, знайдені у вихідному коді програм, розділені відповідним роздільником
  • Вихід повинен бути такої ж довжини, що і вихідний код програми, відлічений лексемами
  • Може використовуватися лише одна мова програмування
  • Вихідний код повинен мати не менше 3-х унікальних маркерів
  • Виключіть коментарі з вихідного коду
  • Програма повинна мати лише той, який має шанс U ^ L відтворити себе

Оцінка балів: Перемагає програма, яка має найкращі шанси відтворити себе.


@MathieuRodic: Ви припускаєте, що програма малює маркери без повторення.
user2357112 підтримує Моніку

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

@ user2357112: Бачу. Моєю помилкою було розглянути цю проблему як нічию без заміни.
Матьє Родіч

1
Правила №1 та №5, здається, суперечать мені.
Cruncher

4
Чи можете ви припустити, що вбудовані випадкові функції є TRNG? У типових реалізаціях є занадто мало насіння для отримання всіх результатів і, таким чином, можливо, неможливо реально відновити себе.
CodesInChaos

Відповіді:


11

Пітон 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 х 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 використовує рядки в стилі Паскаль), результат є 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.6е-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. Оцінка була б покращена, якби програму вже можна було б пограти в гольф, але це моя перша "справжня" програма Whitespace, тому я просто залишу її з мізерною кількістю гольфу.

Звичайний код Whitespace або переконайтеся, що він працює : (щоб спробувати, натисніть «редагувати», скопіюйте матеріал всередині тегів <pre>; має бути 132 символи з EOL у стилі Unix)

    

























Код, в якому зазначається, яка команда - це те, що не технічно, оскільки це не відтворює коментарі:

стек push_number + 0 кінець
стек push_number + 1 0 0 1 кінець
стек купи магазину push_number + 1 кінець
стек push_number + 1 0 0 0 0 0 кінець
стек купи зберігання push_number + 1 0 кінець
стек push_number + 1 0 1 0 кінець
стек магазина купи push_number + 1 0 0 0 0 0 1 1 кінець
потік
make_label loop_begin  
стек push_number + 1 1 кінець
IO  
читати стек символів push_number + 1 1 кінець
купа витягнення стека push_number + 1 1 кінець
арифметична купа модулів отримують IO  
друк стека char push_number + 1 кінець
арифметичний віднімання стека дублікату
 потік
jump_if_zero end_prog
потік
jump_to 
loop_begin  
потік
make_label end_prog
потік
кінцева програма

Якщо насіння просто еквівалентне (символи приймаються mod 3 для перетворення в лексеми) до цього, це вдасться:

CCCCACCCBCCBABBCCCCBACCCBCCCCCABBCCCCBCACCCBCBCABBCCCCBCCCCCBBAACCBACCCBBABCCCCBBABBBCCCCBBCCBBBBBACCCCCBABCCBCACABBAACABAACCAAAAAAAAAAAAAAAAAAAAA

Це досить проста програма, приблизно еквівалентна цій програмі 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,44779 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.