The Random Quine

15

Escreva um programa capaz de gerar-se aleatoriamente.

Isso deve ser feito com base nos tokens usados ​​em seu código-fonte. Se o código-fonte do seu programa for composto por 50 tokens exclusivos e tiver 60 tokens, o programa deverá gerar 60 tokens nos quais cada token for escolhido aleatoriamente dentre um dos 50 tokens exclusivos.

Por exemplo, este programa teria uma chance em 50 ^ 60 de se reproduzir.

O que é um token? Isso depende do idioma. Por exemplo, identificadores ( foo_bar), palavras-chave ( while) e números ( 42) contariam como tokens na maioria dos idiomas. Espaço em branco não conta na maioria dos idiomas.

Regras adicionais:

  • A saída pode conter apenas tokens encontrados no código-fonte do programa, separados pelo delimitador apropriado
  • A saída deve ter o mesmo comprimento que o código-fonte do programa, contado por tokens
  • Apenas uma linguagem de programação pode ser usada
  • O código-fonte deve ter pelo menos três tokens exclusivos
  • Excluir comentários do código-fonte
  • O programa deve ter apenas uma chance em U ^ L de se reproduzir

Pontuação: O programa que tem a melhor chance de se reproduzir ganha.

Austin Henley
fonte
@MathieuRodic: Você está assumindo que o programa desenha tokens sem repetição.
User2357112 suporta Monica
@MathieuRodic: Deixe-me reformular. Você está assumindo que o programa embaralha aleatoriamente o multiset de seus tokens, em vez de desenhar L tokens com repetição do conjunto de U tokens usados ​​em sua origem.
User2357112 suporta Monica
@ user2357112: Entendo. Meu erro foi considerar esse problema como um empate sem substituição.
Mathieu Rodic
1
As regras 1 e 5 parecem estar em contradição comigo.
Cruncher
4
Você pode assumir que funções aleatórias integradas são TRNGs? As implementações típicas têm sementes muito pequenas para produzir todas as saídas e, portanto, podem ser incapazes de realmente se regenerar.
CodesInChaos

Respostas:

11

Python 2, 3 ^ -3 = 0,037

execabuso é bastante útil para reduzir a contagem de tokens. Agora atualizado para não ler o arquivo de origem!

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),
"""

O extra ''entre exece a cadeia gigante de aspas triplas é apenas para preencher a contagem de tokens até o mínimo necessário de 3. Ela é mesclada na segunda cadeia devido à concatenação literal implícita da cadeia.

Versão original, abrindo o arquivo de origem:

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),
'''

Estritamente falando, a gramática Python coloca um token ENDMARKER no final do arquivo de origem, e não podemos produzir um arquivo de origem com os ENDMARKERs espalhados aleatoriamente. Fingimos que não existe.

user2357112 suporta Monica
fonte
@ Cruncher Essa é a probabilidade. 3 ^ -3 == 1/3 ^ 3
Austin Henley
2
+1 para hack brilhante das regras. A mesma ideia implementada em J: ".]';(?3 3 3){]`".;~({:,],{:,],6#{:)'';(?3 3 3){]`".;~({:,],{:,],6#{:)'''''''.
algorithmshark
5

Javascript, 102 tokens, 33 exclusivo, 7,73 × 10 -154

Note, este é um verdadeiro quine. Ele não lê o arquivo ou usa evalouFunction.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)
aebabis
fonte
4

Python: P (gerando programa em uma avaliação) = 3.0317 * 10 ^ -123

34 fichas exclusivas, 80 fichas no total. Observe que há um espaço no final de cada linha.

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 

Saída de amostra:

' ' 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 

Agradeço à outra solução Python do user2357112 por me lembrar de descartar o último token e usar o __file__que eu ignorava anteriormente.

Kaya
fonte
3

J - 1 em 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 tem várias ferramentas úteis para realizar esse tipo de trabalho.

  • Antes de tudo, qualquer sequência de números separada por espaço é um token . Significa uma matriz unidimensional desses números. É assim que o lexer de J funciona. A propósito, são dezessete 11s, se alguém estiver curioso.

  • (,,,{:,{:)'QUINE'''é um truque de quine comum em J, feito para usar o menor número possível de tokens: {:significa Tail , então ele anexa a string a si próprio e adiciona duas cópias do último caractere ao final. Como o último caractere é uma aspas simples (J usa seqüências de caracteres no estilo Pascal), o resultado é QUINE'QUINE'''.

  • ;:é um tokenizador e divide uma sequência de entrada como se fosse o código J, retornando uma lista de caixas. O comprimento deste resultado é 17.

  • ~.pega todos os elementos exclusivos dessa matriz. O comprimento deste resultado é 11.

  • ?é chamado de rolo . Para cada número inteiro em seu argumento, ele seleciona um número positivo aleatório maior ou igual a zero, menor que esse número. Então, aqui J gerará 17 números de 0 a 10, inclusive.

  • { usa os índices aleatórios para selecionar itens da nossa lista de tokens-in-boxes exclusivos.

  • ; abre todas essas caixas e executa o resultado juntos.

Alguns exemplos a seguir. As linhas recuadas são os prompts de entrada e as linhas alinhadas com o lado esquerdo são a saída do intérprete.

   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
~.~.(?;;:11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''(){11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){(;:;
   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
{';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)''',?{:;:{:';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11{:{;(;:{:,~.
algoritmshark
fonte
2

Postscript

essa foi engraçada

/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

Existem 17 fichas exclusivas e 54 fichas no total, por aproximadamente 1 em 3,6e-67 de chance.

Geoff Reedy
fonte
2

Espaço em branco, 3 ^ -205 3 ^ -189 3 ^ -181 3 ^ -132 ~ = 10 ^ -63

Este é um programa de espaço em branco que, quando propagado com caracteres aleatórios, tem uma chance de 1 em 3 ^ 132 de se reproduzir (3 tokens distintos, repetidos 132 vezes). Ele deve ser propagado com pelo menos 132 caracteres aleatórios quando executado (o espaço em branco não possui nenhuma função aleatória ou de data incorporada), por exemplo some_whitespace_interpreter my_quine.ws <some_random_source >quine_output.ws. A pontuação seria melhorada se o programa pudesse ser jogado mais, mas esse é o meu primeiro programa "em branco" de espaço em branco, então deixarei com minha quantidade escassa de golfe.

Código de espaço em branco simples ou veja-o executar : (para experimentá-lo, clique em "editar", copie o material dentro das tags <pre>; deve ter 132 caracteres com EOL no estilo Unix)

    

























Código anotado com qual comando é o que (tecnicamente não é um quine, pois não reproduz os comentários):

pilha push_number + 0 end
empilhe push_number + 1 0 0 1 end
pilha de armazenamento de pilha push_number + 1 end
pilha push_number + 1 0 0 0 0 0 end
pilha de armazenamento de pilha push_number + 1 0 end
empilhar push_number + 1 0 1 0 end
pilha de armazenamento de pilha push_number + 1 0 0 0 0 0 1 1 end
fluxo
make_label loop_begin  
empilhar push_number + 1 1 final
IO  
pilha de caracteres de leitura push_number + 1 1 end
pilha recupera pilha push_number + 1 1 end
heap módulo aritmético recuperar IO  
print char stack push_number + 1 end
pilha aritmética subtrair duplicado
 fluxo
jump_if_zero end_prog
fluxo
pule para 
loop_begin  
fluxo
make_label end_prog
fluxo
end_program

Se a semente for equivalente (os caracteres serão modificados 3 para serem convertidos em tokens), isso será bem-sucedido:

ATCCACCCBCCBABBCCCCBACCCBCCCCCABBCCCCBCACCCBCBCABBCCCCBCCCCCBBAACCBACCCBBABABCCCCBBABBBCCCBBABCBBBBBACACCCCCBABCCBCACABBAACABAACCAAAA

É um programa bastante simples, aproximadamente equivalente a este programa Ruby:

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

Perl, 27 tokens, P = 1,4779 x 10 -34

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

Última edição: use em @ARGV=$0vez de open*ARGV,$0para salvar um token.

  • 15 tokens exclusivos
  • 4 tokens aparecer 2 vezes ( =, /, @, $)
  • 1 token aparece 4 vezes ( W)

Então eu acho que isso torna a probabilidade (pow (2,2 * 4) * pow (4,4)) / pow (27,27), em cerca de 1,48E-34.

Se o código-fonte estiver em um arquivo chamado ARGV, você poderá usar esta solução de 26 token com P = ~ 2.193 x 10 -31 :

@ARGV=ARGV;print$ARGV[rand@ARGV]for@ARGV=split/(\W)/,readline
multidão
fonte
Na verdade, P = (4 * 2! + 4!) / 27!que é de cerca de 1,7632684538487448 x 10 ^ -26
Mathieu Rodic
0

Perl 6 ,1 dentro 33 = 0,037037 ...

(Eu sei que isso não é código-golfe, mas ...)

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

Experimente online!

Muito parecido com a resposta do Python, onde o primeiro token é uma literal de cadeia de caracteres que é avaliada. Os tokens são

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

Explicação:

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
Brincadeira
fonte