Programm, das es sich erlaubt, einen String zu kodieren (quine-variant)

16

Schreiben Sie ein Programm, das die folgende 80-stellige Zeile ausgibt:

Dieses Programm von codegolf.stackexchange.com erlaubt es sich, einen String zu kodieren.

Akzeptiert dann eine Eingabezeile und druckt den Quellcode mit möglicherweise neu angeordneten Codepunkten (keiner hinzugefügt und keiner gelöscht). Wenn dieser Code ausgeführt wird, muss dasselbe geschehen, mit der Ausnahme, dass die gedruckte Zeile die letzte Eingabezeile ist.

Der reguläre Ausdruck ^[A-Za-z0-9. ]{80}$im Perl-Stil passt zu jeder Eingabezeile. Sie können keine zusätzlichen Annahmen treffen.

Die Bewertung einer Einreichung ergibt sich aus der Anzahl der Codepunkte im Quellcode abzüglich 94 . Weniger ist besser.

Der Code darf nichts tun, was in einem Quine nicht akzeptabel wäre ( z . B. Lesen von Dateien). Insbesondere muss jede Einsendung mit einer negativen Punktzahl irgendwie schummeln, wie 93! ist kleiner als 64 80 .

Hinzugefügt am 21.04.2014: Der gesamte Quellcode Ihres Programms muss in der Zeichencodierung, unter der Sie Codepunkte zählen, wohlgeformt sein. Beispielsweise können Sie nicht 80 aufeinanderfolgende Bytes im UTF-8-Trailing-Byte-Bereich (80..BF) verwenden und jedes als einzelnes U + FFFD-ERSATZZEICHEN (oder schlimmer noch als gar kein Codepunkt) zählen.

Wenn die Codierung mehrere Möglichkeiten zum Codieren eines Codepunkts ( z. B. SCSU ) zulässt , darf Ihr Programm sowie alle von ihm direkt oder indirekt generierten Programme nur eines von ihnen verwenden (oder zumindest alle müssen im gesamten Code gleich behandelt werden) ).

PleaseStand
quelle
Nach dem erneuten Lesen Ihrer Frage bin ich mir nicht sicher, ob meine Antwort genau das tut, was Sie sich vorgestellt haben. Ist die Weiterleitung des neuen Strings an das Programm in Ordnung oder muss eine interaktive Eingabeaufforderung gestartet werden?
Dennis
@ Tennis: Das ist nicht der Grund, warum deine Antwort nicht akzeptabel ist. Vielmehr liest es die Eingabe vor dem Ausdruck von "Dieses Programm von [...]".
PleaseStand
Das habe ich gemeint, ich habe es einfach nicht gut ausgedrückt. Der GolfScript-Interpreter liest alles, was dazu geleitet wird, bevor er mit der Ausführung des Skripts beginnt. Die einzige Möglichkeit, dies zu vermeiden, besteht darin, eine Eingabeaufforderung zu starten, die die Verrohrung unmöglich macht.
Dennis
Hallo, ich versuche dies in JavaScript. Es scheint unmöglich zu sein, ein Quine zu erstellen, ohne den Text zwischen den <script> -Tags zu lesen. Was ist der Zweck der Permutation des Quellcodes? Sie sagen "möglicherweise nachbestellt"; heißt das permutieren nur wenn nötig?
Bacchusbeale

Antworten:

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$=.@^}/]"'".@+\+\'.~'}.~

Wie es funktioniert

Wir beginnen mit der Auswahl von 94 verschiedenen Zeichen, die für die Codierung eines Strings permutiert werden. Alle 94 Zeichen würden funktionieren, aber wir wählen die folgenden aus Golfgründen:

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

Nennen wir das Array dieser Zeichen "&".

Die Eingabezeile enthält immer 81 Zeichen (einschließlich des LF). Alle diese Zeichen sind in den ersten 65 Zeichen von "&" enthalten. Dies ist der einzige Grund für die Auswahl von Zeichen in den oberen 128 Bytes.

Wir ersetzen jedes Zeichen des Strings durch seinen Index in "&", so dass LF zu 0 wird, Leerzeichen zu 1 usw.

Wir betrachten die 81 erhaltenen Zahlen als die Ziffern einer einzelnen Zahl zur Basis 65. Nennen wir diese Nummer "N".

Nun werden alle möglichen Permutationen von "&" aufgezählt und die der Zahl entsprechende Permutation von oben abgerufen. Dies wird auf folgende Weise erreicht:

  1. Stellen Sie c = 1und ein A = [].
  2. Prepend N % cto A.
  3. Stellen Sie N = N / cund ein c = c + 1.
  4. Wenn ja c < 95, gehe zurück zu 2.
  5. Stellen Sie i = 0und ein s = "".
  6. Rufen &[A[i]]Sie das Zeichen ab , hängen Sie es an "s" an und entfernen Sie es von "&".
  7. Einstellen i = i + 1.
  8. Wenn i < 94zurück zu 6.

Angenommen, wir haben Codeblöcke "E" und "D", die eine Zeichenfolge wie oben erläutert codieren und decodieren.

Jetzt brauchen wir einen Wrapper für die Codeblöcke, die den Anforderungen der Frage entsprechen:

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

Dies bewirkt Folgendes:

  • {…}.~Definiert einen Block, dupliziert ihn und führt die zweite Kopie aus. Die erste Kopie bleibt auf dem Stapel.

  • \.$ Vertauscht die codierte Zeichenfolge mit dem Block und erstellt eine Kopie der codierten Zeichenfolge mit sortierten Zeichen.

  • [{}/]:&; wandelt den String von oben in ein Array um, speichert ihn in "&" und verwirft ihn.

  • D puts decodiert den codierten String und gibt das Ergebnis aus.

  • '"#{`head -1`}"'~Liest eine Eingabezeile durch Ausführen head -1in der Shell.

  • E "'".@+\+ codiert die Zeichenfolge und fügt ein einfaches Anführungszeichen hinzu.

  • \'.~'tauscht die codierte Zeichenfolge und den Block aus und hängt die Zeichenfolge an '.~'.

  • Nachdem der Block ausgeführt wurde, druckt GolfScript den Inhalt des Stapels (codierte Zeichenfolge, Block '.~') und beendet ihn.

"E" kann wie folgt definiert werden:

{&?}%        # 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" kann wie folgt definiert werden:

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.

Abschließendes Golfen:

  • Ersetzen Sie \.$[{}/]:&;0&@durch 0@.$[{}/]:&\, um zwei Zeichen zu speichern.

  • Definieren Sie die Funktion {;65base}:bzum Speichern eines Zeichens.

  • Entfernen Sie alle Leerzeichen mit Ausnahme des nachfolgenden LF und des LF in der Zeichenfolge.

Beispiel

$ # 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
quelle
224 minus 94 ist 130.
mbomb007
Könnten Sie näher darauf eingehen?
Dennis
1

Perl 1428, 1099

Dieser enthält 1193 ASCII-Zeichen (einschließlich 960 permutierter Binärziffern). 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

Mein erster Entwurf

Bevor ich Dennis einen Vorschlag machte, auf Binär umzuschalten, permutierte mein Programm Oktalziffern.

Mein erstes Design codiert jede Zeichenfolge in 160 Oktalzeichen mit 2 Zeichen pro Zeichen. Diese Kodierung hat 100 8 = 64 verschiedene Zeichen. Das Oktalsystem besteht aus 8 verschiedenen Ziffern. Das Programm muss 160 Kopien jeder Ziffer enthalten, damit 8 × 160 = 1280 Ziffern möglich sind.

Ich behalte 160 Stellen in $sund die anderen 1120 Stellen in $t. Ich beginne mit einem Programm, das kein Quine ist, sondern nur die Zuweisungen für $sund $tfür den nächsten Lauf ausgibt . Das ist es:

$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))ist eine Zuweisung zu einer leeren Liste von Variablen. Ich nehme diesen Trick aus dem Kontext-Tutorial bei PerlMonks . Erzwingt den Listenkontext für den Match-Operator =~. Im skalaren Kontext wäre die Übereinstimmung wahr oder falsch, und ich bräuchte eine Schleife, $i++ while ($s =~ /$_/g)um die Übereinstimmungen zu zählen. Im Listenkontext $s =~ /$_/gist eine Liste von Übereinstimmungen. Ich habe diese Liste in den skalaren Kontext einer Subtraktion gestellt, sodass Perl die Listenelemente zählt.

Um eine Quine zu machen, nehme ich die Form $_=q{print"\$_=q{$_};eval"};evalder Perl-Quines bei Rosetta Code . Dieser ordnet einen String q{...}zu $_und ruft dann auf eval, sodass ich meinen Code in einem String haben und ihn auch ausführen kann. Mein Programm wird zu einem Quine, wenn ich meine drittletzten Zeilen in $_=q{und einbinde };evalund meine letzten printin ändern print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval".

Schließlich spiele ich mein Programm ab, indem ich die erste Zuweisung $tin einen Kommentar ändere und zusätzliche Zeichen entferne.

Dies hat 1522 ASCII-Zeichen (einschließlich 1280 permutierten Oktalzeichen).
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

Der Umstieg auf Binär

In den Kommentaren bemerkte Dennis, dass 960 permutierte Binärziffern weniger als 1280 Oktalziffern sind. Also habe ich die Anzahl der permutierten Stellen für jede Basis von 2 bis 16 grafisch dargestellt.

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) 

Grafik mit Basis auf der x-Achse, Anzahl der permutierten Stellen auf der y-Achse

Obwohl die Basis 8 ein lokales Minimum darstellt, ergeben die Basen 2 und 3 und 4 mit 960 permutierten Stellen die beste Basis. Für Code-Golf ist Basis 2 am besten geeignet, da Perl Konvertierungen für Basis 2 hat.

Durch Ersetzen von 1280 Oktalzeichen durch 960 Binärzeichen werden 320 Zeichen gespeichert.

Das Umschalten des Codes von Oktal auf Binär kostet 8 Zeichen:

  • Änderung octder oct'0b'.$_Kosten 7.
  • Änderung /../gder /.{6}/gKosten 2.
  • Wechsel "%02o"zu "% 06b" `kostet 0.
  • Wechsel 160zu 480Kosten 0.
  • 0..7Zum 0,1Speichern wechseln 1.

Ich habe einige Perl-Golftipps gelernt . Sie speichern 14 Zeichen:

  • Wechsel 'A'..'Z','a'..'z','0'..'9'an A..Z,a..z,0..9, mit Barewords und nackten Zahlen, spart 12 Zeichen.
  • Ändern, "\n"um $/2 Zeichen zu speichern.

Ich spare 3 Zeichen, indem ich den #$tKommentar an das Ende der Datei verschiebe. Das entfernt die neue Zeile, die den Kommentar beendet, und ein Literal \nin dem Quine.

Diese Änderungen speichern insgesamt 329 Zeichen und reduzieren meine Punktzahl von 1428 auf 1099.

Kernigh
quelle
1
Die Verwendung von binären anstelle von oktalen Ziffern würde "nur" 960 zulässige Zeichen erfordern.
Dennis
@Dennis Danke für den Tipp! Ich habe auf Binär umgestellt (312 Zeichen werden gespeichert). Während ich hier war, spielte ich 17 weitere Charaktere ab.
Kernigh