Entropowa Quine!

12

Twoim zadaniem jest napisanie programu lub funkcji, która:

  • Przy pierwszym uruchomieniu wyświetla kod źródłowy.
  • Przy kolejnych wykonaniach powinien wypisać to, co wypisał wcześniej, ale z jedną losową zmianą znaku (zdefiniowaną poniżej). Nie musi to być jednolicie losowa zmiana, ale każda możliwa zmiana powinna mieć niezerową szansę wystąpienia.

    Po pierwszym wykonaniu, Twój program nie musi być już na Quine'a; dane wyjściowe ulegną zmianie (a program może się również modyfikować).

Na przykład, jeśli twój quine był ABCD, wielokrotnie go uruchamiając może wydrukować:

ABCD
A!CD
j!CD
j!CjD

Dane techniczne

  • Zmiana postaci to:

    • Wstawienie losowego znaku,
    • Usunięcie losowego znaku lub
    • Zastąpienie postaci nową losową postacią. Zauważ, że nowy znak może być taki sam jak ten, który zastępuje, w którym to przypadku nie zostaną wprowadzone żadne zmiany.

    Oczywiście usunięcie lub zastąpienie znaku z pustego ciągu nie jest poprawną zmianą.

  • Pomimo tego, że jest oznaczony jako , zasady dotyczące odczytywania kodu źródłowego nie mają zastosowania.

Możesz użyć dowolnego zestawu znaków, o ile zawiera on znaki użyte w kodzie źródłowym.

Esolanging Fruit
źródło
1
Do jakich znaków odnosi się każda postać ?
Dennis
2
Jak często to musi działać? Oczywiście nie może to być arbitralnie często ani w inny sposób każdy możliwy program, tak długi lub dłuższy niż oryginalny, musi być rozwiązaniem problemu.
Martin Ender,
1
Czy można dodać postać w dowolnym miejscu, czy tylko na końcu?
Conor O'Brien
1
@ ConorO'Brien Anywhere.
Esolanging Fruit
1
Ile iteracji musi działać?
dylnan

Odpowiedzi:

7

Python 3 , 288 270 224 212 195 196 194 180 178 168 bajtów

f=__file__
m=open(f).read()
x=m	
print(end=x)
h=hash
k=h(f)
n=k%2
a=h(m)%-~len(x)
x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:]
open(f,'w').write(m.replace("\t",";x=%r\t"%x))

Wypróbuj online!

Po wydrukowaniu kodu źródłowego pliku przy pierwszej iteracji dodajemy dodatkowy wiersz, aby ustawić x na nowy kod źródłowy, a nie m.

Wyjaśnienie:

f=__file__    #Open and read the source code
m=open(f).read()

x=m       #Set x to the source code for the first iteration
x="..."
...
x="..."   #Set x to the latest iteration
          #On the last iteration there's a tab character to mark progress
print(end=x)    #Print the previous iteration's text

#Modify the text
h=hash
k=h(f)            #Generate a random number to use
n=k%2             #Whether the character will be inserted or changed/deleted
a=h(m)%-~len(x) #The index of the change
                         #Add 1 to the range to append new characters, and to avoid mod by 0 in the case of an empty string
x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:]    #Make the change

open(f,'w').write(m.replace("\t",";x=%r\t"%x))   #Modify the source code, adding the new iteration of the source code

Zakładając, że hashzwraca jednolicie losową liczbę, istnieje około 1/6 szansy na wstawienie nowej postaci, 1/6 szansy na zmianę istniejącej postaci i 2/6 szansy na usunięcie postaci. O jaką pozostałą szansę 2/6 pytasz? Cóż, w ogóle nie robi nic w 2/6 czasu!

(Oto program sprawdzający poprawność na podstawie odpowiedzi mbomb007 . Wypróbuj online! )

Jo King
źródło
Myślę, f=__file__że pomógłby również w pierwszym kroku.
Ørjan Johansen
4

Python 3 , 205 195 bajtów

s='print(end=x);h=hash;k=h(x);n=k%2;a=h(s)%-~len(x);x=x[:a]+(not(k%3)*x)*chr(k%127)+x[a+n:];open(__file__,"w").write("s=%r;x=%r;exec(s)"%(s,x))';x='s=%r;x=%r;x=x%%(s,x);exec(s)';x=x%(s,x);exec(s)

Wypróbuj online!

Chciałem wypróbować wersję, która nie odczytuje kodu źródłowego. Okazało się, że nie jest tak źle, jak myślałem, i ma tylko 30 bajtów za wersją, która ma . Wyjaśnienie tego, jak to działa, jest w większości takie samo jak druga odpowiedź, ale inicjuje x inaczej, ponieważ nie może po prostu odczytać kodu źródłowego.

Jo King
źródło
4

Python 2 , 779 801 bajtów

Chociaż wyzwanie zostało zredagowane, aby pokazać, że czytanie Twojego źródła jest dozwolone, już bez niego tworzyłem swoje rozwiązanie. Aby pokazać, że to możliwe, skończyłem. Brak odczytu pliku źródłowego:

s='s=%r;print s%%s\nfrom random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint\nf.write("\\n".join((s%%s).split("\\n")[1:5:2]).replace("4",`map(ord,s%%s)`))\nif L>5:exec\'b=[];h=%%d\\nwhile~-h:b+=[h%%%%1000];h/=1000\\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\\nprint"".join(map(chr,L))\'%%1\n\nn=R(0,2);p=R(0,len(L if L>5else s%%s));r=R(0,255);f.write("%%03d"*3%%(n,p,r))';print s%s
from random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint
f.write("\n".join((s%s).split("\n")[1:5:2]).replace("4",`map(ord,s%s)`))
if L>5:exec'b=[];h=%d\nwhile~-h:b+=[h%%1000];h/=1000\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\nprint"".join(map(chr,L))'%1

n=R(0,2);p=R(0,len(L if L>5else s%s));r=R(0,255);f.write("%03d"*3%(n,p,r))

Wypróbuj online! (Pamiętaj, że nie spowoduje to modyfikacji źródła. Aby działało, musisz uruchomić je lokalnie)

Aby pokazać, że transformacje działają, oto program testowy (obecnie skonfigurowany tak, aby zawsze wybierał 100dla r, i drukuje wynik dla każdej kombinacji ni pdla początkowej listy).



Wyjaśnienie:

s='s=%r;print s%%s...';print s%s...

Pierwsza linia to twoja klasyczna quine, ale o wiele dłużej, aby uwzględnić to, co nastąpi później.

from random import*;L=4;f=open(__file__,"wa"[L>5]);R=randint

Importuj losowe liczby całkowite. Lstanie się listą porządków kodu źródłowego, ale początkowo jest liczbą całkowitą, która nie jest używana nigdzie indziej w źródle, aby umożliwić zamianę ciągu. Otwórz plik, aby napisać nowe źródło. W późniejszych uruchomieniach zostanie ono otwarte, aby dołączyć.

f.write("\n".join((s%s).split("\n")[1:5:2]).replace("4",`map(ord,s%s)`))

Usuń pierwszą i trzecią linię kodu. Zamień 4powyższe na listę rzędnych.

if L>5:exec'b=[];h=%d\nwhile~-h:b+=[h%%1000];h/=1000\nwhile b:r,p,n=b[-3:];b=b[:-3];L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1]\nprint"".join(map(chr,L))'%1

n=R(0,2);p=R(0,len(L if L>5else s%s));r=R(0,255);f.write("%03d"*3%(n,p,r))

W kawałkach:

  • if L>5:- Pomija tę linię przy pierwszym wykonaniu. Później Lpojawi się lista, która się uruchomi. Wyjaśnię to execostatnie, ponieważ nie jest uruchamiane za pierwszym razem.

  • n- Liczba losowa 0-2. Określa, która modyfikacja nastąpi (0 = wstaw, 1 = zamień, 2 = usuń).

  • p - Losowa pozycja na liście, na której nastąpi modyfikacja.

  • r - Liczba losowa do wstawienia lub zastąpienia na liście

  • f.write("%03d"*3%(n,p,r))- Dołącz 3 losowe na końcu pliku źródłowego. Przy każdym uruchomieniu będzie to dodawane do liczby całkowitej, która koduje wszystkie zmiany w początkowym źródle, które miały miejsce.

  • exec'b=[];h=%d...'%1...- Uzyskaj losowe liczby (znalezione po %1późniejszych uruchomieniach), zastosuj zmiany do listy i wydrukuj.

  • while~-h:b+=[h%%1000];h/=1000- Zbuduj listę losowych generowanych do tej pory, uwzględniając wiodące 1, co zapobiega problemom z zerami wiodącymi.

  • while b:r,p,n=b[-3:];b=b[:-3] - Przypisz losowe dla tej iteracji.

  • L=[L[:p]+L[p+1:],L[:p]+[r]+L[p+n:]][n<2if L else 1] - (0 = wstaw, 1 = zamień, 2 = usuń)

  • print"".join(map(chr,L)) - Wydrukuj zmodyfikowane źródło.

mbomb007
źródło
Czy to czasami usuwa nieistniejący znak z końca łańcucha? Ponieważ pmoże być długością łańcucha. Jakie jest zachowanie pustego łańcucha?
Jo King
@JoKing Dodałem program testowy. Każda możliwa zmiana postaci może się zdarzyć. Pokazuje po prostu, że każdą pozycję można wybrać dla wstawienia, zastąpienia lub usunięcia oraz że obsługuje pustą listę. tio.run/##LYoxDsMgDEVnOAUjCAZgRO0NuIHloUOaRIocy6JDT08dpdt/…
mbomb007
Nie sądzę, że żadna zmiana jest ważna, chociaż poprosiłem OP. Pytanie brzmiOf course, deleting or replacing a character from an empty string is not a valid change
Jo King
Zapytałem Esolanging Fruit, a oni mówią, że żadna zmiana nie jest ważna, ale nie dla pustego ciągu.
Jo King
1
@JoKing powinien zostać naprawiony.
mbomb007
1

Java 10, 370 bajtów

String s;v->{if(s==null){s="String s;v->{if(s==null){s=%c%s%1$c;s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%%3<2?c:%1$c%1$c)+s.substring(r+(c%%3>0?1:0));}}";s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%3<2?c:"")+s.substring(r+(c%3>0?1:0));}}

Wypróbuj online.

Wyjaśnienie:

String s;               // Class-level String variable to store the modifying source code
v->{                    // Method without parameter nor return-type
  if(s==null){          //  If this is the first execution of this function:
    s="String s;v->{if(s==null){s=%c%s%1$c;s=s.format(s,34,s);}else{int r=s.length();r*=Math.random();char c=127;c*=Math.random();s=s.substring(0,r)+(c%%3<2?c:%1$c%1$c)+s.substring(r+(c%%3>0?1:0));}}";
                        //   Set `s` to the unformatted source-code
    s=s.format(s,34,s);}//   And then to the formatted source-code
else{                   //  For any following executions of this function:
  int r=s.length();r*=Math.random();
                        //   Random index in range [0, length_of_modified_source_code)
  char c=127;c*=Math.random();
                        //   Random ASCII character in unicode range [0, 127)
  s=                    //   Replace the current String `s` with:
    s.substring(0,r)    //    The first [0, `r`) characters of the modified source code `s`
    +(c%3<2?            //    If the random option is 0 or 1:
           c:"")        //     Append the random character
        +s.substring(r  //    Append the rest of the modified source code `s`, but:
          +(c%3>0?      //     If the random option is 1 or 2:
             1:0));}}   //      Skip the first character of this second part

Ogólne wyjaśnienie:

-part:

  • Ciąg szawiera niesformatowany kod źródłowy.
  • %ssłuży do wprowadzania tego ciągu do siebie za pomocą s.format(...).
  • %c, %1$ci 34służą do formatowania podwójnych cudzysłowów.
  • ( %%służy do formatowania modułu %).
  • s.format(s,34,s) łączy to wszystko razem.

Oto podstawowy program quine Java.

Część wyzwania:

  • String s; to kod źródłowy, który zmodyfikujemy na poziomie klasy.
  • int r=s.length();r*=Math.random(); służy do wybierania losowego indeksu kodu źródłowego w zakresie [0, length_of_modified_source_code) .
  • char c=127;c*=Math.random();służy do wybierania losowego znaku ASCII (w tym niedrukowalnych) w zakresie Unicode [0, 126].
  • c%3służy do wyboru losowej opcji 0, 1 lub 2. Opcja 0 doda losowy znak przed indeksem r; opcja 1 zastąpi znak o indeksie rlosowym znakiem; a opcja 2 usunie znak z indeksu r.
Kevin Cruijssen
źródło