Program, który pozwala sobie na kodowanie łańcucha (wariant quine)

16

Napisz program, który wypisze następujący wiersz o długości 80 znaków:

Ten program z codegolf.stackexchange.com zezwala na kodowanie łańcucha.

następnie akceptuje jeden wiersz danych wejściowych, a następnie drukuje kod źródłowy z ewentualnymi zmienionymi kolejnymi punktami kodowymi (brak dodanych i usuniętych) Kiedy ten kod jest wykonywany, to samo musi się zdarzyć, z wyjątkiem tego, że linia drukowana byłaby najnowszą linią wprowadzania.

Wyrażenie regularne w stylu Perla ^[A-Za-z0-9. ]{80}$będzie pasować do dowolnego wiersza wprowadzania. Nie możesz przyjąć żadnych dodatkowych założeń.

Wynik zgłoszenia to liczba punktów kodowych w kodzie źródłowym pomniejszona o 94 . Niższe jest lepsze.

Kod nie może robić niczego, co byłoby niedopuszczalne w quine ( np. Czytanie pliku). W szczególności każde zgłoszenie z wynikiem ujemnym musi w jakiś sposób oszukiwać, ponieważ 93! jest mniejsza niż 64 80 .

Dodano 2014-04-21: Cały kod źródłowy twojego programu musi być dobrze sformatowany w kodowaniu znaków, pod którym policzono punkty kodowe. Na przykład, nie można używać 80 kolejnych bajtów w końcowym zakresie bajtów UTF-8 (80..BF) i liczyć każdego z nich jako pojedynczego ZNAKU WYMIANY UFFD (lub, co gorsza, wcale nie jest kodem).

Dodatkowo, jeśli kodowanie pozwala na wiele sposobów kodowania punktu kodowego ( np. SCSU ), twój program, jak również wszystkie programy, które generuje bezpośrednio lub pośrednio, musi używać tylko jednego z nich (lub przynajmniej wszystkie muszą być traktowane jednakowo w całym kodzie ).

Proszę wstać
źródło
Po ponownym przeczytaniu pytania nie jestem pewien, czy moja odpowiedź odpowiada dokładnie temu, co miałeś na myśli. Czy przekazanie nowego ciągu do programu jest prawidłowe, czy musi uruchomić interaktywny monit?
Dennis
@Dennis: Nie dlatego twoja odpowiedź jest nie do przyjęcia. Zamiast tego odczytuje dane wejściowe przed wydrukowaniem „Ten program z [...]”.
PleaseStand
Właśnie to miałem na myśli, po prostu nie wyraziłem tego dobrze. Interpreter GolfScript odczytuje wszystko, co jest do niego przesyłane, zanim zaczął wykonywać skrypt. Jedynym sposobem na uniknięcie tego jest uruchomienie monitu, który uniemożliwia wykonanie potoku.
Dennis
Cześć, próbuję tego w JavaScript. Wydaje się niemożliwe, aby zrobić quine bez czytania tekstu między tagami <script>? Jaki jest cel permutacji kodu źródłowego? Mówisz „prawdopodobnie zmieniony”; czy to oznacza permutację tylko w razie potrzeby?
bacchusbeale

Odpowiedzi:

5

GolfScript, 231 162 131

'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~

Jak to działa

Zaczynamy od wybrania 94 różnych znaków, które zostaną zakodowane w celu zakodowania łańcucha. Dowolne 94 postacie będą działać, ale do gry w golfa wybieramy:

\n .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
àáâãäåçèéêëìíîïðñòóôõöøùúûüýÿ

Nazwijmy tablicę tych znaków „i”.

Wiersz wprowadzania zawsze będzie zawierał 81 znaków (w tym LF). Wszystkie te znaki są obecne w pierwszych 65 znakach „&”. Jest to jedyny powód wybierania znaków z górnych 128 bajtów.

Zastępujemy każdy znak ciągu jego indeksem w „&”, więc LF staje się 0, spacja staje się 1 itd.

Otrzymane 81 liczb traktujemy jako cyfry pojedynczej liczby bazowej 65. Nazwijmy ten numer „N”.

Teraz wyliczamy wszystkie możliwe kombinacje „i” i pobieramy permutację odpowiadającą liczbie z góry. Osiąga się to w następujący sposób:

  1. Ustaw c = 1i A = [].
  2. Przygotuj N % c do A.
  3. Zestaw N = N / ci c = c + 1.
  4. Jeśli c < 95wróć do 2.
  5. Zestaw i = 0i s = "".
  6. Odzyskaj charcter &[A[i]] , dodaj go do „s” i usuń z „&”.
  7. Zestaw i = i + 1 .
  8. Gdyby i < 94 wrócisz do 6.

Załóżmy, że mamy bloki kodu „E” i „D”, które kodują i dekodują ciąg, jak wyjaśniono powyżej.

Teraz potrzebujemy opakowania dla tych bloków kodu, które spełniają wymagania pytania:

'encoded string'{\.$[{}/]:&; D puts '"#{`head -1`}"'~ E "'".@+\+\'.~'}.~

Robi to:

  • {…}.~definiuje blok, kopiuje go i wykonuje drugą kopię. Pierwsza kopia pozostanie na stosie.

  • \.$ zamienia zakodowany ciąg z blokiem i tworzy kopię zakodowanego ciągu z posortowanymi znakami.

  • [{}/]:&; konwertuje ciąg z góry na tablicę, zapisuje go w „&” i odrzuca.

  • D puts dekoduje zakodowany ciąg i wypisuje wynik.

  • '"#{`head -1`}"'~odczytuje jeden wiersz danych wejściowych poprzez wykonanie head -1w powłoce.

  • E "'".@+\+ koduje ciąg oraz poprzedza i dołącza pojedynczy cytat.

  • \'.~'zamienia zakodowany ciąg i blok i dołącza ciąg '.~'.

  • Po wykonaniu bloku GolfScript drukuje zawartość stosu (zakodowany ciąg, blok, '.~') i kończy działanie.

„E” można zdefiniować w następujący sposób:

{&?}%        # Replace each character by its index in “&”.
);           # Remove the last integer from the array, since it corresponds to the LF.
65base       # Convert the array to an integer “N” by considering it a base 65 number.
[            #
  94,        # For each integer “c” in 0 … 93:
  {          #
    )        # Increment “c”.
    1$1$%    # Push “N % c”.
    @@/      # Rotate “N % c” below “N” and “c” and divide the first by the latter.
  }/;        # Discard “N”.
]            # Collect the results of “N % c” in an array “A”.
-1%          # Reverse “A”.
&\           # Push “&” and swap it with “A”.
[            #
  {          # For each “j” in “A”:
    1$=.[]+  # Push “&[j] [&[j]]”.
    @^       # Rotate “&” on top of “[&[j]]” and take their symmetric difference.
  }/         #
]            # Collect the charcters into an array.

„D” można zdefiniować w następujący sposób:

0&           # Push 0 (initial value of the accumulator “A”) and “&”.
@            # Rotate the encoded string on top of “&”.
{            # For each character “c” of the encoded string:
    @2$,*    # Rotate “A” on top of the stack and multiply it by the length of “&”.
    2$2$?+   # Get the index of “c” in “&” and add it to “A”.
    @@^      # Rotate “A” below “&” and “c” and take their symmetric difference.
}/;          # Discard “&”.
65base       # Convert “A” into the array of its digits in base 65.
{&=}%        # Replace each digit by the corresponding character in “&”.
''+          # Convert the resulting array into a string.

Ostateczne gra w golfa:

  • Wymień \.$[{}/]:&;0&@się 0@.$[{}/]:&\zapisać dwa znaki.

  • Zdefiniuj funkcję, {;65base}:baby zapisać jeden znak.

  • Usuń wszystkie białe znaki oprócz końcowego LF i LF w ciągu.

Przykład

$ # Create GolfScript file using base64 to avoid encoding issues.
$ base64 > permute.gs -d <<< JzHg4jT/YVZvNUf5cFpCdGlYT/xyc/NO7k1tV+VLSGMwOUpk8frqeXrtRUPkWe9oRFUg4+FJRvU26TjyUuxqVHYyM/hudfBMd3hmU2v0YutBZWxx/S7n6FBRCvb7ZzcnezBALiRbe30vXTomXHtAMiQsKjIkMiQ/K0BAXn0vezs2NWJhc2V9OmJ+eyY9fSUnJytwdXRzJyIje2BoZWFkIC0xYH0iJ357Jj99JSliWzk0LHspMSQxJCVAQC99LztdLTElJlxbezEkPS5AXn0vXSInIi5AK1wrXCcufid9Ln4K
$
$ # Set locale to en_US (or any other where one character is one byte).
$ LANG=en_US
$
$ # Go back and forth between two different strings.
$ # Second and sixth line are user input, not output from the script.
$
$ golfscript permute.gs | tee >(tail -n+2 > tmp.gs) && golfscript tmp.gs && rm tmp.gs
This program from codegolf.stackexchange.com permutes itself to encode a string.
Permuting source code code points to encode a string is a certain quine variant.
'18äJoS3sgV9qdçëxm0ÿKMNe5íPî.Htn2ciâIuøbRZéð4AwB7áìUüöôWõèûfñåLàóDrhQlO6
pTaýzòkùYCyFêïãG júEvX'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
Permuting source code code points to encode a string is a certain quine variant.
This program from codegolf.stackexchange.com permutes itself to encode a string.
'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
$
$ # Sort all characters from the original source code and hash them.
$ fold -1 permute.gs | sort | md5sum
b5d978c81df5354fcda8662cf89a9784  -
$
$ # Sort all characters from the second output (modified source code) and hash them.
$ golfscript permute.gs | tail -n+2 | fold -1 | sort | md5sum
Permuting source code code points to encode a string is a certain quine variant.
b5d978c81df5354fcda8662cf89a9784  -
$
$ # The hashes match, so the characters of the modified source code are a permutation
$ # of the character of the original one.
Dennis
źródło
224 minus 94 wynosi 130.
mbomb007
Czy mógłbyś opracować?
Dennis
1

Perl, 1428 1099

Ma 1193 znaków ASCII (w tym 960 permutowanych cyfr binarnych). 1193 - 94 = 1099

$s='010011100001100010101100111111101001101011101000100000101011011010100110111111011111101011101000100110111111011100101000011101011110100000101000100101011111111110101100101101011010011100100100011110110001011100100001011010100111100000011110111110011100101000100110111111101001011110101011100110101110101101011110101100111111100010101101101100011110100101011111111111101101101000111111011110100111011100101000011101011110111111011010111111101100101101101011100010100111100000111110';$_=q{$i=join'',A..Z,a..z,0..9,'. ';print map({substr$i,oct'0b'.$_,1}$s=~/.{6}/g),$/;chop($s=<>);$s=join'',map{sprintf"%06b",index$i,$_}$s=~/./g;$t=join'',map{$_ x(480-(()=$s=~/$_/g))}0,1;print"\$s='$s';\$_=q{$_};eval#$t"};eval#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Mój pierwszy projekt

Zanim zasugerowałem Dennisowi przejście na binarne, mój program zezwolił na stosowanie cyfr ósemkowych.

Mój pierwszy projekt koduje każdy ciąg w 160 cyfrach ósemkowych, z 2 cyframi na znak. To kodowanie ma 100 8 = 64 różnych znaków. System ósemkowy ma 8 różnych cyfr. Program musi mieć 160 kopii każdej cyfry, więc dopuszcza 8 × 160 = 1280 cyfr.

Trzymam 160 cyfr, $sa pozostałe 1120 cyfr $t. Zaczynam od programu, który nie jest quine, ale drukuje tylko przypisania do $si $tdo następnego uruchomienia. To jest to:

$s = '2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';
$t = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777';

# $i = character map of 64 characters, such that:
#  substr($i, $_, 1) is the character at index $_
#  index($i, $_) is the index of character $_
$i = join '', 'A'..'Z', 'a'..'z', '0'..'9', '. ';

# Decode $s from octal, print.
#  1. ($s =~ /../g) splits $s into a list of pairs of octal digits.
#  2. map() takes each $_ from this list.
#  3. oct() converts $_ from an octal string to a number.
#  4. substr() on $i converts number to character.
#  5. print() outputs the characters from map() and a final "\n".
print map({ substr $i, oct, 1 } $s =~ /../g), "\n";

# Read new $s, encode to octal.
#  1. ($s = <>) reads a line.
#  2. chop($s) removes the last character of $s, the "\n".
#  3. ($s =~ /./g) splits $s into characters.
#  4. map() encodes each character $_ as a pair of octal digits.
#  5. join() concatenates the pairs from map().
chop($s = <>);
$s = join '', map { sprintf "%02o", index $i, $_ } $s =~ /./g;

# Make new $t.
#  1. map() takes each $_ from 0 to 7.
#  2. $_ x (160 - (() = $s =~ /$_/g)) makes a string where $_ repeats
#     160 times, minus the number of times that $_ appears in $s.
#  3. join() concatentates the strings from map().
$t = join '', map { $_ x (160 - (() = $s =~ /$_/g)) } 0..7;

# Print the new assignments for $s and $t.  This is not yet a quine,
# because it does not print the rest of the program.
print "\$s = '$s';\n\$t = '$t';\n";

(() = $s =~ /$_/g))jest przypisaniem do pustej listy zmiennych. Biorę tę sztuczkę z samouczka kontekstowego w PerlMonks . Wymusza kontekst listy na operatorze dopasowania =~. W kontekście skalarnym dopasowanie byłoby prawdziwe lub fałszywe i potrzebowałbym pętli, $i++ while ($s =~ /$_/g)aby policzyć dopasowania. W kontekście listy$s =~ /$_/g znajduje się lista dopasowań. Umieszczam tę listę w skalarnym kontekście odejmowania, więc Perl liczy elementy listy.

Aby zrobić quine, biorę formularz $_=q{print"\$_=q{$_};eval"};evalz quinów Perla z Rosetta Code . Ten przypisuje ciąg q{...}do $_wywołań eval, a następnie je wywołuje , dzięki czemu mogę umieścić mój kod w ciągu, a także go uruchomić. Mój program staje się Quine kiedy owinąć mój trzeci do ostatniej linii $_=q{i };eval, i zmienić mój ostatni printdo print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval".

Na koniec gram w golfa swój program, zmieniając pierwsze zadanie na $t komentarz i usuwając dodatkowe postacie.

Ma 1522 znaków ASCII (w tym 1280 permutowanych cyfr ósemkowych).
1522 - 94 = 1428

$s='2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
$_=q{$i=join'','A'..'Z','a'..'z','0'..'9','. ';print map({substr$i,oct,1}$s=~/../g),"\n";chop($s=<>);$s=join'',map{sprintf"%02o",index$i,$_}$s=~/./g;$t=join'',map{$_ x(160-(()=$s=~/$_/g))}0..7;print"\$s='$s';#$t\n\$_=q{$_};eval"};eval

Przełącz na binarny

W komentarzach Dennis zauważył, że 960 permutowanych cyfr binarnych będzie mniej niż 1280 cyfr ósemkowych. Więc wykreśliłem liczbę permutowanych cyfr dla każdej bazy od 2 do 16.

Maxima 5.29.1 http://maxima.sourceforge.net
using Lisp ECL 13.5.1
...
(%i36) n : floor(x);
(%o36)                             floor(x)
...
(%i41) plot2d(n * ceiling(log(64) / log(n)) * 80, [x, 2, 16],
              [xlabel, "base"], [ylabel, "number of permuted digits"]);
(%o41) 

wykres z podstawą na osi x, liczba cyfr permutowanych na osi y

Chociaż podstawa 8 jest lokalnym minimum, bazy 2, 3 i 4 wiążą się dla najlepszej bazy, przy 960 cyfrach permutowanych. W przypadku golfa kodowego najlepsza jest baza 2, ponieważ Perl ma konwersje dla bazy 2.

Zastąpienie 1280 cyfr ósemkowych 960 cyframi dwójkowymi oszczędza 320 znaków.

Zmiana kodu z ósemkowego na binarny kosztuje 8 znaków:

  • Zmień octdo oct'0b'.$_kosztów 7.
  • Zmień /../gdo /.{6}/gkosztów 2.
  • Zmiana "%02o" na „% 06b” kosztuje 0.
  • Zmiana 160na 480koszty 0.
  • Zmień 0..7na 0,1zapisy 1.

Nauczyłem się kilku wskazówek golfowych Perla . Zapisują 14 znaków:

  • Zmień 'A'..'Z','a'..'z','0'..'9'na A..Z,a..z,0..9, używając słów i nagich cyfr, zapisuje 12 znaków.
  • Zmień, "\n"aby $/zapisać 2 znaki.

Zapisuję 3 znaki, przenosząc #$tkomentarz na koniec pliku. To usuwa nowy wiersz, który kończy komentarz, i literał \nw quine.

Te zmiany oszczędzają łącznie 329 znaków i zmniejszają mój wynik z 1428 do 1099.

kernigh
źródło
1
Użycie cyfr binarnych zamiast cyfr ósemkowych wymagałoby „tylko” 960 dopuszczalnych znaków.
Dennis
@Dennis Dzięki za wskazówkę! Zmieniłem na binarny (zapisując 312 znaków). Będąc tutaj, grałem w golfa jeszcze 17 postaci.
kernigh