Losowa Quine


15

Napisz program, który potrafi się losowo wygenerować.

Musi to zrobić w oparciu o tokeny użyte w jego kodzie źródłowym. Jeśli kod źródłowy twojego programu składa się z 50 unikalnych tokenów i ma 60 tokenów, wówczas program powinien wypisać 60 tokenów, przy czym każdy token jest losowo wybierany z jednego z 50 unikalnych tokenów.

Na przykład ten program miałby szansę na odtworzenie się w 50–60.

Co to jest token? To zależy od języka. Na przykład identyfikatory ( foo_bar), słowa kluczowe ( while) i liczby ( 42) byłyby liczone jako tokeny w większości języków. Białe znaki nie będą się liczyć w większości języków.

Dodatkowe zasady:

  • Dane wyjściowe mogą zawierać tylko tokeny znalezione w kodzie źródłowym programu, oddzielone odpowiednim separatorem
  • Dane wyjściowe muszą być tej samej długości co kod źródłowy programu, liczony według tokenów
  • Można użyć tylko jednego języka programowania
  • Kod źródłowy musi mieć co najmniej 3 unikalne tokeny
  • Wyklucz komentarze z kodu źródłowego
  • Program powinien mieć tylko jedną szansę na reprodukcję

Punktacja: Program, który ma najlepszą szansę na reprodukcję, wygrywa.


@MathieuRodic: Zakładasz, że program rysuje tokeny bez powtórzeń.
user2357112 obsługuje Monikę

@MathieuRodic: Pozwól, że powtórzę. Zakładasz, że program losowo szyfruje multiset swoich tokenów, zamiast losować tokenów L z powtórzeniami z zestawu tokenów U używanych w jego źródle.
user2357112 obsługuje Monikę

@ user2357112: Rozumiem. Moim błędem było uznanie tego problemu za remis bez wymiany.
Mathieu Rodic

1
Reguły nr 1 i nr 5 wydają się być dla mnie sprzeczne.
Cruncher

4
Czy możesz założyć, że wbudowane funkcje losowe to TRNG? Typowe implementacje mają zbyt małe nasiona, aby wygenerować wszystkie wyniki, a zatem mogą nie być w stanie się zregenerować.
CodesInChaos

Odpowiedzi:


11

Python 2, 3 ^ -3 = 0,037

execnadużycie jest bardzo przydatne w celu zmniejszenia liczby tokenów. Teraz zaktualizowane, aby nie czytać pliku źródłowego!

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

Dodatkowa ''pomiędzy execi gigant potrójnie cytowany ciąg jest po prostu pad token liczyć do wymaganego minimum 3. Zostanie on włączony do drugiego łańcucha ze względu na niejawny strun dosłownym konkatenacji.

Oryginalna wersja pliku źródłowego:

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

Ściśle mówiąc, gramatyka Python umieszcza token ENDMARKER na końcu pliku źródłowego, a my nie możemy stworzyć pliku źródłowego z losowo rozrzuconymi ENDMARKER-ami. Udajemy, że to nie istnieje.


@Cruncher To jest prawdopodobieństwo. 3 ^ -3 == 1/3 ^ 3
Austin Henley

2
+1 za genialny hack zasad. Ta sama idea wdrożona w J: ".]';(?3 3 3){]`".;~({:,],{:,],6#{:)'';(?3 3 3){]`".;~({:,],{:,],6#{:)'''''''.
algorytmshark

5

JavaScript, 102 tokeny, 33 unikalne, 7,73 × 10-154

Uwaga, to jest prawdziwa quine. Nie czyta pliku ani nie używa evallubFunction.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 (program generujący w 1 wersji próbnej) = 3,0317 * 10 ^ -123

34 unikalne żetony, 80 łącznych żetonów. Zauważ, że na końcu każdej linii jest spacja.

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 

Przykładowe dane wyjściowe:

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

Dzięki drugiemu rozwiązaniu Python użytkownika user2357112 za przypomnienie, żebym odrzucił ostatni token i __file__którego nie znałem wcześniej.


3

J - 1 na 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 ma wiele przydatnych narzędzi do wykonywania tego rodzaju zadań.

  • Po pierwsze, dowolny ciąg liczb oddzielony spacjami jest jednym tokenem . Oznacza jednowymiarową tablicę tych liczb. Tak działa leksykon J. Nawiasem mówiąc, to siedemnaście 11sekund, jeśli ktoś jest ciekawy.

  • (,,,{:,{:)'QUINE'''jest powszechną sztuczką quine w J, stworzoną tak, aby używać jak najmniejszej liczby żetonów: {:oznacza Ogon , więc dodaje ciąg do siebie, a następnie dodaje dwie kopie ostatniego znaku na końcu tego. Ponieważ ostatnim znakiem jest pojedynczy cudzysłów (J używa ciągów w stylu Pascala), wynikiem jest QUINE'QUINE'''.

  • ;:jest tokenizerem i rozkłada ciąg wejściowy tak, jakby to był kod J, zwracając listę pól. Długość tego wyniku wynosi 17.

  • ~.pobiera wszystkie unikalne elementy tej tablicy. Długość tego wyniku wynosi 11.

  • ?nazywa się Roll . Dla każdej liczby całkowitej w argumencie wybiera losową liczbę dodatnią większą lub równą zero, mniejszą niż ta liczba. Więc tutaj J wygeneruje 17 liczb od 0 do 10 włącznie.

  • { używa losowych wskaźników do wybierania przedmiotów z naszej listy unikalnych tokenów w skrzynkach.

  • ; otwiera wszystkie te pola i uruchamia wynik razem.

Oto kilka przykładów. Wcięte linie są monitami o wprowadzenie danych, a linie w jednej linii z lewą stroną stanowią dane wyjściowe interpretera.

   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
~.~.(?;;:11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''(){11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){(;:;
   ;(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)'''
{';(?11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11){~.;:(,,,{:,{:)''',?{:;:{:';(?11 11 11 11 11 11 11 11 11 11 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

Postscriptum

To było zabawne

/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

Istnieje 17 unikalnych żetonów i 54 żetonów łącznie za około 1 z szansy 3,6e-67.


2

Biała spacja , 3 ^ -205 3 ^ -189 3 ^ -181 3 ^ -132 ~ = 10 ^ -63

Jest to program WhiteSpace, który, gdy jest zapełniony losowymi postaciami, ma szansę na reprodukcję 1 na 3 ^ 132 (3 różne tokeny, powtórzone 132 razy). Po uruchomieniu musi być zaszczepiony co najmniej 132 losowymi znakami (Whitespace nie ma wbudowanej funkcji losowej ani funkcji daty), np some_whitespace_interpreter my_quine.ws <some_random_source >quine_output.ws. Wynik zostałby poprawiony, gdyby ten program mógł być już golfem, ale jest to mój pierwszy „prawdziwy” program Whitespace, więc zostawię go z moją niewielką ilością gry w golfa.

Zwykły kod białych znaków lub zobacz, jak się uruchamia : (aby go wypróbować, kliknij „edytuj”, skopiuj zawartość do tagów <pre>; powinien mieć 132 znaki w EOL w stylu uniksowym)

    

























Kod opatrzony adnotacjami o tym, co jest poleceniem (nie jest to technicznie quine, ponieważ nie odtworzy komentarzy):

stos push_number + 0 end
stos push_number + 1 0 0 1 koniec
stos magazynu stos numer_pchnięcia + 1 koniec
stos push_number + 1 0 0 0 0 0 koniec
stos magazynu stos numer_p Push + 1 0 koniec
stos push_number + 1 0 1 0 koniec
stos magazynu stos numer_ push + 1 0 0 0 0 0 1 1 koniec
pływ
make_label loop_begin  
stos push_number + 1 1 koniec
IO  
odczyt stosu znaków numer_pchnięcia + 1 1 koniec
sterta pobieranie stosu numer_pchnięcia + 1 1 koniec
sterta arytmetyczna modulo odzyskuje IO  
print stos stosu znaków numer_pchnięcia + 1 koniec
arytmetyczny duplikat stosu odejmowania
 pływ
jump_if_zero end_prog
pływ
Skocz do 
loop_begin  
pływ
make_label end_prog
pływ
program_końcowy

Jeśli ziarno jest po prostu równoważne (postacie są zabrane modem 3 do konwersji na tokeny), to się powiedzie:

CCCCACCCBCCBABBCCCCBACCCBCCCCCABBCCCCACACCCBCBCABBCCCCBCCCCCBBAACCBACCCBBABABCCCCCCBBABBBCCCBBABCBBBBBBACCCCCBABCCBCACABBAACABAACCAAAA

Jest to dość prosty program, w przybliżeniu odpowiadający temu programowi Ruby:

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

1

Perl, 27 żetonów, P = 1,4779 x 10 -34

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

Ostatnia edycja: użyj @ARGV=$0zamiast, open*ARGV,$0aby zapisać token.

  • 15 unikalnych tokenów
  • Pojawia się 2 razy 4 żetony ( =, /, @, $)
  • 1 token pojawia się 4 razy ( W)

Myślę więc, że to czyni prawdopodobieństwo (pow (2,2 * 4) * pow (4,4)) / pow (27,27), około 1,48E-34.

Jeśli kod źródłowy jest w pliku o nazwie ARGV, a następnie można użyć tego rozwiązania z tokena 26 P = ~ 2,193 x 10 -31 :

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

Właściwie, P = (4 * 2! + 4!) / 27!czyli około 1,7632684538487448 x 10 ^ -26
Mathieu Rodic

0

Perl 6 ,1 w 3)3) = 0,037037 ...

(Wiem, że to nie jest golf golfowy, ale ...)

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

Wypróbuj online!

Podobnie jak odpowiedź w Pythonie, gdzie pierwszy token jest literałem ciągu, który jest obliczany. Tokeny są

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

Wyjaśnienie:

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.